Java类加载机制(阿里)何时初始化类

上传人:枫** 文档编号:489996674 上传时间:2023-08-30 格式:DOC 页数:8 大小:183.50KB
返回 下载 相关 举报
Java类加载机制(阿里)何时初始化类_第1页
第1页 / 共8页
Java类加载机制(阿里)何时初始化类_第2页
第2页 / 共8页
Java类加载机制(阿里)何时初始化类_第3页
第3页 / 共8页
Java类加载机制(阿里)何时初始化类_第4页
第4页 / 共8页
Java类加载机制(阿里)何时初始化类_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《Java类加载机制(阿里)何时初始化类》由会员分享,可在线阅读,更多相关《Java类加载机制(阿里)何时初始化类(8页珍藏版)》请在金锄头文库上搜索。

1、Java类加载机制(阿里)-何时初始化类阿里的面试官问了两个问题,可以不可以自己写个类答案:如果包名相同是不可以,因为根据类加载的双亲委派机制,会去加载父类,父类发现冲突了就不再加载了,但是如果包的名不同就可以重写。比如:acaom.alibaba.aavaavalangtSpyrsitnetmlc.nl(a.sSgtslga.java.la1n2;g3.Stump.biz.activities.constaingargs)Loader();ass().getClassLoader();能否在加载类的时候,对类的字节码进行修改答案:可以,使用Java探针技术,可以参考:阅读目录什么是类加载器类

2、加载器与类的”相同“判断类加载器种类双亲委派模型类加载过程自定义类加载器J热部署实现什么是类加载器负责读取Jav字节代码,并转换成avaa类的一0个实例;类加载器与类的”相同“判断类加载器除了用于加载类外,还可用于确定类在Java虚拟机中的唯一性。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。这里指的相同”包括类的a对象的a方法、a方法、方法、a关键字等判断出来的结果。类加载器种类通俗一点来讲,要判断两个类是否“相同”,前提是这两个类必须被同一个类加载器加载,否则这个两个类不“相同”。启动类加载器,Bootstrap扩展类加载器,Extension应用程序类加载器,Ap

3、plica自定义类加载器,通过继承a加载Ja,或者被-参数限定的类加I载,a或者被ava系统变量指定的类,加载caa中的类库实现,一般是加载我们的自定义类双亲委派模型类加载器Jav类如同其它的Jav类一样,也是要由类加载器来加载的;除了启动类加载器,每个类都有其父类加载器(父子关系由组合不是继承)来实现)所谓双亲委派是指每次收到类加载请求时,先将请求委派给父类加载器完成(所有加载请求最终会委派到顶层的器中),如果父类加载器无法完成这个加载(该加载器的搜索范围中没有找到对应的类),子类尝试自己加载。加载启动类加载器BootstrapClassloader扩展类加载器ExtensionClassl

4、oader应用程序类加载器ApplicationClassloader自定义类加载器JserClassloader自定义类加载器UserClasslodder双亲委派好处避免同一个类被多次加载;-每个加载器只能加载自己范围内的类;类加载过程类加载分为三个步骤:加载,连接,初始化;图片来自参考资料;如下图,是一个类从加载到使用及卸载的全部生命周期,连按(Linking)加载Loading加载脸证Vcriilciition卸载Unloading椎备Pre卩oration使用Using解析Resolution初始化Inilialization根据一个类的全限定名(如cn.edu.hdu.test.H

5、elloWorld.class)来读取此类的二进制字节流到JVM内部;将字节流所代表的静态存储结构转换为方法区的运行时数据结构hotspot选择将Class对象存储在方法区中,Java虚拟机规范并没有明确要求一定要存储在方法区或堆区中)转换为一个与目标类型对应旳ava.lang.Class对象;连接验证验证阶段主要包括四个检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证准备为类中的所有静态变量分配内存空间,并为其设置一个初始值(由于还没有产生对象,实例变量将不再此操作范围内);解析将常量池中所有的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法

6、)。这个阶段可以在初始化之后再执行。初始化在连接的准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员自己写的逻辑去初始化类变量和其他资源,举个例子如下:在准备阶段和都等于0在初始化阶段和分别等于和6*所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是方法,即类接口初始化方法,该方法只能在类加载的过程中由调用;编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量;如果超类还没有被初始化,那么优先对超类初始化,但在方法内部不会显示调用超类的方法,由负责保证一个类的方法

7、执行之前,它的超类方法已经被执行。必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。(所以可以利用静态内部类实现线程安全的单例模式)如果一个类没有声明任何的类变量,也没有静态代码块,那么可以没有类方法;何时触发初始化为一个类型创建一个新的对象实例时(比如、反射、序列化)调用一个类型的静态方法时(即在字节码中执行指令)调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时(即在字节码中,执行或者指令),不过用修饰的静态字段除外,它被初始化为一个编

8、译时常量表达式调用中的反射方法时(比如调用中的方法,或者包中其他类的方法)初始化一个类的派生类时(虚拟机规范明确要求初始化一个类时,它的超类必须提前完成初始化操作,接口例外)启动包含方法的启动类时。自定义类加载器要创建用户自己的类加载器,只需要继承类,然后覆盖它的方法即可n即指明如何获取类的字节码流。如果要符合双亲委派规范,则重写方法(用户自定义类加载逻辑);要破坏的话,重写方法双亲委派的具体逻辑实现)。例子:类加载成功。privatebytegetData(StringclassName)Stringpath=classPath+File.separatorChar+className.re

9、place(.,File.separatorChar)+.class;tryInputStreamis=newFileInputStream(path);ByteArrayOutputStreamstream=newByteArrayOutputStream();bytebuffer=newbyte2048;intnum=0;while(num=is.read(buffer)!=-1)stream.write(buffer,0,num);returnstream.toByteArray();catch(IOExceptione)e.printStackTrace();returnnull;pu

10、blicstaticvoidmain(Stringargs)throwsClassNotFoundException,InstantiationException,IllegalAccessExceptionClassLoaderpcl=newPathClassLoader(D:ProgramFileseclipseNewworkspacecp-libbin);Classc=pcl.loadClass(classloader.TestClassLoad);/注意要包括包名System.out.println(c.newInstance();/打印类加载成功.JAVA热部署实现首先谈一下何为热部

11、署(hotswap),热部署是在不重启Java虚拟机的前提下,能自动侦测到class文件的变化,更新运行时class的行为。Java类是通过Java虚拟机加载的,某个类的class文件在被classloader加载后,会生成对应的Class对象,之后就可以创建该类的实例。默认的虚拟机行为只会在启动时加载类,如果后期有一个类需要更新的话,单纯替换编译的class文件,Java虚拟机是不会更新正在运行的class。如果要实现热部署,最根本的方式是修改虚拟机的源代码,改变classloader的加载行为,使虚拟机能监听class文件的更新,重新加载class文件,这样的行为破坏性很大,为后续的JVM

12、升级埋下了一个大坑。另一种友好的方法是创建自己的classloader来加载需要监听的class,这样就能控制类加载的时机,从而实现热部署。热部署步骤:1、销毁自定义classloader(被该加载器加载的class也会自动卸载);2、更新class3、使用新的ClassLoader去加载class卸载JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):-该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。-加载该类的ClassLoader已经被GC。-该类的java.lang.Class对象没有在任何地方被引用,如不能在任何

13、地方通过反射访问该类的方法延伸出来问题进行分析:看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的。随着编程经验的日积月累,越来越感觉到了解虚拟机相关要领的重要性。闲话不多说,老规矩,先来一段代码吊吊胃口。publicclassSSClassstaticSystem.out.println(SSClass);publicclassSuperClassextendsSSClassstaticSystem.out.println(SuperClassinit!);publicstaticintvalue=123;publicSupe

14、rClass()System.out.println(initSuperClass);publicclassSubClassextendsSuperClassstaticSystem.out.println(SubClassinit);staticinta;publicSubClass()System.out.println(initSubClass);publicclassNotInitializationpublicstaticvoidmain(Stringargs)System.out.println(SubClass.value);运行结果:SSClassSuperClassinit!123答案答对了嚒?也许有人会疑问:为什么没有输出SubClassinit。ok解释一下:对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。上面就牵涉到了虚拟机类加载机制。如果有兴趣,可以继续看

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号