首页 > 编程知识 正文

java为什么要用反射机制,java类加载机制面试题

时间:2023-05-04 20:20:12 阅读:32575 作者:4327

问题: java如何加载代码? 写完. java文件后,编译生成. class字节码文件,当程序运行时,JVM虚拟机将该. class文件加载到JVM存储器中,并描述该class的各种信息的元信息对象

Java语言允许通过程序间接处理此类,如获取构造函数、属性和方法。 用户还可以通过与此类关联的元对象间接调用类对象的各种方法。

Java将. class文件加载到JVM内存中的操作称为类加载,用户在代码访问中调用这些class中的属性和方法称为反射(有关Java反射机制的详细信息)。

1 .类加载进程类加载器是指查找类的字节码文件,然后构造类在JVM内部表示对象的组件。 在Java中,要将应该是类加载器的类加载到JVM中,必须执行以下操作:

1.装载:查找和导入Class文件

加载是将类的class文件加载到内存中并创建java.lang.Class对象。 也就是说,在程序中使用类时,系统将创建java.lang.Class对象。 的加载由类加载器完成,通常由JVM提供

通常,类加载器不需要将类加载到“首先使用”之前。 javavirtualmachinespecification允许预加载特定类。

2.链接

加载类后,将生成相应的类对象,并进入将类的二进制数据合并到JRE中的连接阶段。 类连接分为以下三个阶段,其中分析步骤是可选的

(1)检查)检查加载的class文件数据的正确性。 主要包括4种类型的验证、文件格式验证、元数据验证、字节码验证、符号引用验证。

)准备)类准备阶段负责为类的静态变量分配内存并设置默认初始值。

)3)分析:将类的二进制数据中的符号引用直接替换为引用。

符号参照:符号参照是用一系列符号描述参照目标的,只要不发生冲突,可以是任何字面形式的字面量。 布局与内存无关。

直接引用:可以指向目标的指针、偏移或直接定位的句柄。 此引用与内存中的布局有关,并且一定会加载。

3.初始化:对静态变量,静态代码块执行初始化工作

准备阶段和初始化阶段看起来有点矛盾,其实并不矛盾。 如果类中有语句,则private static int a=10,其执行过程如下: 首先,字节码文件加载到内存中,然后执行验证链接这一步骤,在验证通过后的准备阶段,为a分配内存。 由于变量a是静态的,因此此时a与int类型的默认初始值相同

2、在类加载的时机创建类的实例。 也就是说,静态方法调用反射(class.forname("com.lyj.load " ) )访问new对象所在的类或接口,或将类分配给该静态变量

对于final类型的静态变量,如果在编译时可以确定该变量的值,则该变量相当于“宏变量”。 由于Java编译器在编译过程中将此变量出现的位置直接替换为其值,因此即使程序使用该静态变量,也不会初始化该类。 相反,如果final类型的静态Field的值在编译时不能确定,则在运行之前无法确定该变量的值。 通过该类访问该静态变量时,该类将被初始化。

3 .类加载器类加载工作由除此之外,下面几种情形需要特别指出:及其子类负责。ClassLoder是重要的Java运行时系统组件,它在运行时查找并加载字节码文件。

JVM在运行时生成三个类加载器。

ClassLoder

1.根装载器

2.ExtClassLoader(扩展类装载器)

根加载器是由c而不是ClassLoader的子类编写的,因此不会显示在java中,而是负责加载JRE的核心类库,如JRE目录下的rt.jar和charsets.jar

ExtClassLoader是ClassLoder的子类,负责加载JRE扩展目录ext下的jar类包。

AppClassLoader负责装载classpath路径下的类软件包。 这三个类加载器是父子关系。 也就是说,根加载器是ext类加载器的父加载器,而ext类加载器是app类加载器的父加载器。

缺省情况下,使用AppClassLoader装载APP应用程序中的类

4 .班载机构3.AppClassLoader(应用类装载器)主要有以下三类:

全面负责:全面负责,就是一个班装载机负

责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。缓存机制。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。

特别强调下双亲委派机制: 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式 。

该机制除了能避免类重复加载外,还很好的解决了类加载的安全问题。若一个人写了个恶意的基础类(如java.lang.String) ,在该加载机制的限制下,JVM的 java.lang.String 类就永远是由根装载器来装载,该恶意基础类并不会被加载,成功避免了 java 核心API库被人恶意篡改了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。