当前位置: 首页 > news >正文

服装网站网络建设和硬件资源宁波建设集团几个分公司

服装网站网络建设和硬件资源,宁波建设集团几个分公司,宣威网站建设,wordpress外贸主题教程本文由读者 apdoer 投稿#xff0c;apdoer 是一个极具钻研精神的 Java 猿#xff0c;技术牛X头发茂盛! 博客地址#xff1a;https://blog.csdn.net/m0_43452671缘起#xff1a;一个面试题最近在上下班地铁刷博客,无意刷到一个面试题,号称很多程序员的烈士公墓#xff1a;j… 本文由读者 apdoer 投稿apdoer 是一个极具钻研精神的 Java 猿技术牛X头发茂盛! 博客地址https://blog.csdn.net/m0_43452671缘起一个面试题最近在上下班地铁刷博客,无意刷到一个面试题,号称很多程序员的烈士公墓java 能否自己写一个类叫 java.lang.System博主也提供了相关的答案一般情况下是不可以的,但是可以通过特殊的处理来达到目的,这个特殊的处理就是自己写个类加载器来加载自己写的这个 java.lang.System 类。然后随手又刷了几个,基本雷同,看到的博客都是在讲 java 类加载的双亲委托机制, 一个类在需要加载时,会向上委托,直到最上层的 bootstrapClassLoader ,然后最上层的 bootstrapClassLoader 如果能在自己对应的目录加载就加载,不能就向下查找。而 bootstrapClassLoader 会加载系统默认的 System 类,所以我们自定义的就不会被加载。但是我们自定义一个类加载器加载特定路径的,避开 jvm 默认的三个类加载器的加载路径,就可以使我们的自定义 System 类被加载。可是真的是这样吗为了弄清楚这个问题,我又看了下类加载。什么是类加载类加载指的是将类 Class 文件读入内存并为之创建一个 java.lang.Class 对象, class 文件被载入到了内存之后才能被其它 class 所引用jvm 启动的时候并不会一次性加载所有的 class 文件而是根据需要去动态加载java 类加载器是 jre 的一部分,负责动态加载 java 类到 java 虚拟机的内存类的唯一性由类加载器和类共同决定还了解到系统的三种类加载器AppClassLoader : 也称为 SystemAppClass 加载当前应用的 classpath 的所有类。ExtClassLoader : 扩展的类加载器加载目录 %JRE_HOME%\lib\ext 目录下的 jar 包和 class 文件。还可以加载 -D java.ext.dirs 选项指定的目录。BoostrapClassLoader : 最顶层的加载类主要加载核心类库 %JRE_HOME%\lib 下的 rt.jar、resources.jar、charsets.jar 和 class 等。另外需要注意的是可以通过启动 jvm 时指定 -Xbootclasspath 和路径来改变 Bootstrap ClassLoader 的加载目录。比如 java -Xbootclasspath/a:path 被指定的文件追加到默认的 bootstrap 路径中。瞄一眼源码,在Launcher类中public class Launcher {private static URLStreamHandlerFactory factory new Launcher.Factory();private static Launcher launcher new Launcher();private static String bootClassPath System.getProperty(sun.boot.class.path);private ClassLoader loader;private static URLStreamHandler fileHandler;public static Launcher getLauncher() {return launcher;}public Launcher() {// 创建ExtClassLoaderLauncher.ExtClassLoader var1;var1 Launcher.ExtClassLoader.getExtClassLoader();//创建AppClassLoaderthis.loader Launcher.AppClassLoader.getAppClassLoader(var1);//设置AppClassLoader为线程上下文类加载器Thread.currentThread().setContextClassLoader(this.loader);}public ClassLoader getClassLoader() {return this.loader;}public static URLClassPath getBootstrapClassPath() {return Launcher.BootClassPathHolder.bcp;}//AppClassLoaderstatic class AppClassLoader extends URLClassLoader {public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {final String var1 System.getProperty(java.class.path);public Class? loadClass(String var1, boolean var2) throws ClassNotFoundException {}//ExtClassLoaderstatic class ExtClassLoader extends URLClassLoader {private static volatile Launcher.ExtClassLoader instance;public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {}//创建ExtClassLoaderprivate static Launcher.ExtClassLoader createExtClassLoader() throws IOException {}private static File[] getExtDirs() {String var0 System.getProperty(java.ext.dirs);File[] var1; 这段源码有以下几点Launcher 类在构造函数初始化了 ExtClassLoader 和 AppClassLoader 并设置 AppClassLoader 为线程上下文类加载器。代码里面没有告诉我们 BoostrapClassLoader 从哪里来的,但却为其指定了要加载 class 文件的路径 sun.boot.class.path 。BoostrapClassLoader 是由 c 编写的,内嵌在 jvm 中,所以不能显示的看到他的存在【这个不是从源码中得到】。实践出真知我们通过代码来检验下上面的理论。类加载器的父子关系public class Test {public static void main(String[] args) {System.out.println(Test.class.getClassLoader());System.out.println(Test.class.getClassLoader().getParent());System.out.println(Test.class.getClassLoader().getParent().getParent());} } 这段代码我们可以看到类加载器的父子关系, APPClassLoader-ExtClassLoader-BoostrapClassLoader , 但是 BoostrapClassLoader 无法显示的获取到,只能看到是个 null 。源码中的路径到底加载哪些目录sun.boot.class.pathpublic static void main(String[] args) {String property System.getProperty(sun.boot.class.path);//BoostrapClassLoaderString[] split property.split(;);Arrays.asList(split).forEach(s - System.out.println(s)); } 可以看到是 jre/lib 目录下一些核心 jarjava.ext.dirspublic static void main(String[] args) {String property System.getProperty(java.ext.dirs);//ExtClassLoaderString[] split property.split(;);Arrays.asList(split).forEach(s - System.out.println(s)); } java.class.path public static void main(String[] args) {String property System.getProperty(java.class.path);//AppClassLoaderString[] split property.split(;);Arrays.asList(split).forEach(s - System.out.println(s)); } 可以看到,各个加载器加载的对应路径和前面的介绍是吻合的类加载的双亲委托机制这里直接来一张图processon 图库满了这个先将就下如果看不太懂可以看下以下解释一个 class 文件发送请求加载,会先找到自定义的类加载器,当然这里没画出来。APPClassLoader 得到加载器请求后,向上委托交给 ExtClassLoader , ExtClassLoader 同理会交给 BoostrapClassLoader ,这是向上委托方向。最终到达 BoostrapClassLoader ,会先在缓存中找,没有就尝试在自己能加载的路径去加载,找不到就交给 ExtClassLoader ,同理一直到用户自定义的 ClassLoader ,这就是向下查找方向。前面说的类的唯一性由类和类加载器共同决定, 这样保证了确保了类的唯一性。弄清楚这些,我们可以开始验证自定义的类加载器是否可以加载我们自定义的这个System类了自定义类加载器新建一个 MyClassLoader 继承 ClassLoader ,并重写 loadclass 方法package org.apder; import java.io.InputStream; public class MyClassLoader extends ClassLoader{public MyClassLoader(){super(null);}Overridepublic Class? loadClass(String name) throws ClassNotFoundException {String className null;if (name ! null !.equals(name)){if (name.startsWith(java.lang)){className new StringBuilder(/).append(name.replace(.,/)).append(.class).toString();}else {className new StringBuffer(name.substring(name.lastIndexOf(.)1)).append(.class).toString();}System.out.println(className);InputStream is getClass().getResourceAsStream(className);System.out.println(is);if (is null) return super.loadClass(name);byte[] bytes new byte[is.available()];is.read(bytes);return defineClass(name,bytes,0,bytes.length);}return super.loadClass(name);} } 这里的代码很容易看懂,就不赘述了。测试由于 System 需要用于打印获取结果,这里就用同属 lang 包的 Long 类public class Long {public void testClassLoader(){System.out.println(自定义Long类被Long.class.getClassLoader()加载了);}public static void main(String[] args) {System.out.println(Long);} } 运行自定义 Long 类中 main 方法 报错如下出错原因很简单,这个自定义的 Long 类申请加载后,会被委托到 BoostrapClassLoader,BoostrapClassLoader 会在向下查找的过程中找到 rt.jar 中的 java.lang.Long 类并加载,执行 main 方法时,找不到 main 方法,所以报找不到 main 方法。public class MyLong {public void testClassLoader(){System.out.println(自定义Math类被MyLong.class.getClassLoader()加载了);}public static void main(String[] args) {System.out.println(mylong);} } 我们再定义一个自定义的 java.lang.MyLong 类,执行 main 方法,报错如下很明显的堆栈信息禁止使用的包名 java.lang ,我们点进去 preDefineClass 看看private ProtectionDomain preDefineClass(String name,ProtectionDomain pd){if (!checkName(name))throw new NoClassDefFoundError(IllegalName: name);if ((name ! null) name.startsWith(java.)) {throw new SecurityException(Prohibited package name: name.substring(0, name.lastIndexOf(.)));}if (pd null) {pd defaultDomain;}if (name ! null) checkCerts(name, pd.getCodeSource());return pd; } 可以看到,当如果类的全路径名以 java. 开头时,就会报错,看到这里,开头的答案你是否有了结果呢我们梳理一下过程,如果用自定义的类加载器加载我们自定义的类会调用自定义类加载器的 loadClass 方法。而我们自定义的 classLoader 必须继承 ClassLoader,loadClass 方法会调用父类的 defineClass 方法。而父类的这个 defineClass 是一个 final 方法,无法被重写所以自定义的 classLoader 是无论如何也不可能加载到以 java. 开头的类的。到这里,最开始的问题已经有了答案。我们无法自定义一个叫 java.lang.System 的类。思考如果我把 MyLong 打成 jar 放到 BoostrapClassLoader 的加载路径呢让 BoostrapclassLoader 去加载,具体操作如下,在 jdk 的 jre 目录下创建 classes 目录,然后把 MyLong.jar 复制进去,再通过 vmOptions 追加这个 classes 目录以使 BoostrapClassLoader 加载可以看到仍然加载不了,如果能加载在控制台是会有 load 信息的,如果不是 java.lang.Long ,是可以跨过 APPClassLoader 和 ExtClassLoader 来让 boostraPClassloader 来加载的,这里就不演示了,操作很简单。下面是vm参数-Xbootclasspath/a:c:\classloader.jar -verbose 由一个面试题引起的类加载器思考,既然已经写到这里,干脆把线程上下文类加载器也一并学习了。拓展线程上下文类加载器为什么不和前面三种类加载器放在一起说呢,这个线程上下文类加载器只是一个概念,是一个成员变量,而前三种是确切存在的,是一个类,我们来看一下 Thread 的源码public class Thread implements Runnable {private ClassLoader contextClassLoader;public void setContextClassLoader(ClassLoader cl) {SecurityManager sm System.getSecurityManager();if (sm ! null) {sm.checkPermission(new RuntimePermission(setContextClassLoader));}contextClassLoader cl;}CallerSensitivepublic ClassLoader getContextClassLoader() {if (contextClassLoader null)return null;SecurityManager sm System.getSecurityManager();if (sm ! null) {ClassLoader.checkClassLoaderPermission(contextClassLoader,Reflection.getCallerClass());}return contextClassLoader;} } 特点线程上下文类加载器是一个成员变量,可以通过相应的方法来设置和获取。每个线程都有一个线程类加载器,默认是 AppClassLoader 。子线程默认使用父线程的 ClassLoader ,除非子线程通过上面的 setContextClassLoader 来设置。测试针对以上两点简单测试一下public class Test {public static void main(String[] args) {Thread thread new Thread(()-{});System.out.println(thread.getContextClassLoader());thread.setContextClassLoader(Test.class.getClassLoader().getParent());System.out.println(thread.getContextClassLoader());} } public class Test {public static void main(String[] args) {Thread thread new Thread(()-{});Thread.currentThread().setContextClassLoader(Test.class.getClassLoader().getParent());thread.setContextClassLoader(Test.class.getClassLoader().getParent());System.out.println(thread.getContextClassLoader());} } 可以证明以上三点总结java 三种类加载器一条主线-----路径一个机制-双亲委托两个方向-向上委托,向下查找好了本文就先介绍到这里有问题欢迎留言讨论。【End】查看更多面试题内容请访问《Java最常见200面试题全解析》它包含的模块有Java、JVM 最常见面试题解析Spring、Spring MVC、MyBatis、Hibernate 面试题解析MySQL、Redis 面试题解析RabbitMQ、Kafka、Zookeeper 面试解析微服务 Spring Boot、Spring Cloud 面试解析扫描下面二维码付费阅读关注下方二维码订阅更多精彩内容。转发朋友圈是对我最大的支持。
http://www.zqtcl.cn/news/507904/

相关文章:

  • 做网站需要注意的问题seo推广代运营
  • 采购网站大全wordpress decorum
  • wordpress建站教程道一网页效果图素材
  • 广州网站开发哪家专业免费咨询怀孕医生
  • 洛阳网站的优化阿里云购买域名后怎么建网站
  • 我是做环保类产品注册哪些浏览量大的网站推销自己的产品比较好呢网站功能模块设计
  • 叫人做网站多少钱百度免费网站怎样建设
  • 本地南通网站建设新手编程入门先学什么
  • asp网站开发的背景与环境久久建筑网会员
  • 河北省住房建设厅官方网站个人计算机做服务器建网站
  • 上海自助建站费用页游网站
  • 浙江省住建厅网站沈阳网站建设专家
  • 基础建设文本网站施工企业在施工过程中发现设计文件和图纸有差错的应当
  • 做互联网交易网站的条件17网站一起做网店揭阳
  • 做公司网站合同asp.net sql server网站建设 pdf
  • 建筑兼职网站天津网站优化公司哪家好
  • 怎么做网站设计商城型网站开发网站建设
  • 建设网站目录帮别人做网站要投资吗
  • 网站meta 优化建议桥梁建设设计网站
  • 网站建设 甘肃wordpress rss去掉
  • 网站安全检测大连网龙建站优化推广
  • 人才网官方网站公众号排名优化软件
  • 淘宝返利网站建设软件开发哪里学好
  • 烟台网站制作公司如何注册国外网站
  • discuz企业网站网站可以做音频线吗
  • 怎样制作网站教程哪家好制作网页的的网站
  • 网站没有织梦后台无锡seo公司网站
  • 哈尔滨住房和城乡建设厅网站公司网站建设 费用入账
  • 网站图片缩略图t恤图案设计网站
  • 对招聘网站页面设计做建议网站流量 转化率