Java开发中类的加载及反射机制

开发 后端
JAVA中类文件加载是动态的。JVM指令是被封装在了.class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。

JAVA中类文件加载是动态的。JVM指令是被封装在了.class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。这里所说的用到包括两种方式,***种就是new一个对象的时候(这个时候要特别注意,当设计到多态的时候,就会有一点点变化,这时候编译器会做一些优化,这样以来当加载的时候会提前加载设计到多态的类,关于这一点下面有个例子(example 1)来说明。另一种就是当一个类的静态代码被调用的时候。

java 代码
//example 1
//Zoo.java
abstract class Animal {
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
private Animal am; //Example 1.1
//private Dog am; Example 1.2
private Tiger tiger;
Zoo(){
tiger = new Tiger();
am = new Dog();
}
public static void main(String [] args){
System.out.println("new Zoo before");
Zoo z = new Zoo();
System.out.println("new Zoo after ");
}
}

我们可以看出:当我们将子类对象赋值给父类时,编译器会做一点优化,于是加载器在还没有new子类对象的时候已经加载了父类以及子类(example1.1结果),当不存在多态的时候,我们可以看到是当要new Dog()的时候才会加载Dog以及父类。无论何种方式,在new之前,类确实已经加载到了内存中。

JAVA为我们提供了两种动态机制。***种是隐式机制。其实new一个对象和调用类的静态方法时,就是隐式机制在工作。第二种是显示机制。显示的机制又有两种策略(***种是用java.lang.Class的forName(String str)方法,第二种是用java.lang.ClassLoader的loadClass())。#p#

***种:利用forName方法

当我们查API文档就会发现forName方法有两种形式。分别如下:

public static Class<?> forName(String className)
throws ClassNotFoundException
public static Class<?> forName(String name,
boolean initialize,
ClassLoader loader)
throws ClassNotFoundException

先来说说第二种方法:第二个方法值得注意的就是第二个参数boolean initialize,如果我们把这个参数设置为false,那么当我们加载完类后就不会执行静态代码和静态的初始化动作。只有当我们new一个对象的时候才会初始化。而第三个参数是用来指明类的加载器的。

如果查看java.lang.Class类的源代码,上述两种方法最终都会调用Class类中的私有的native方法forName0(),此方法的声明如下:

private static native Class forName0(String name, boolean init,ClassLoader loader)
throws ClassNotFoundException;

所以当我们调用Class.forName(name )时,其实是在方法内部调用了:

forName0(name, true, ClassLoader.getCallerClassLoader());

当我们调用Class.forName(name, initialize, loader )的时候,实际上此方法内部调用了:

forName0(name, initialize, loader);

下面看一个例子,如果方法中第二个参数为false的情况:

java 代码
//example 2.1
//Zoo.java
abstract class Animal {
static {
System.out.println("Animal static code block ");
}
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
public static void main(String [] args)throws Exception {
System.out.println("new Zoo before");
Zoo z = new Zoo();
Class c = Class.forName("Dog",false,z.getClass().getClassLoader());
System.out.println("initilize before ");
Animal dog = (Animal)c.newInstance();
System.out.println("new Zoo after ");
}
}

类加载完成后并没有立即执行静态初始化代码,而是到了实例化的时候才进行了静态初始化。有时候我们会说静态代码是在类***次被加载时执行的,并且只执行一次。其实这是对与new一个对象,***次访问类的静态代码以及第二个参数为true时而言的,对于动态的加载来说,如果forName方法的第二个参数设置为false,那么就是在实例化的时候才会执行静态初始化。当然默认情况下第二个参数是true。#p#

第二种方法:利用Class对象获取的ClassLoader装载

下面是一个简单的例子:

java 代码
//Example 2.2
//Zoo.java
abstract class Animal {
static {
System.out.println("Animal static code block ");
}
Animal(){
System.out.println("Animal constructor");
}
}
class Tiger extends Animal {
Tiger(){
System.out.println("Tig constructor ");
}
}
class Dog extends Animal {
Dog(){
System.out.println("Dog Constructor ");
}
}
public class Zoo {
public static void main(String [] args)throws Exception {
Class c = Zoo.class;
ClassLoader loader = c.getClassLoader();
System.out.println("loader before");
Class dog = loader.loadClass("Dog");
System.out.println("instance before ");
Animal an = (Animal)dog.newInstance();
}
}

loader完成以后并没有立即进行静态代码的执行。只有当newInstance()的时候才执行静态初始化,这和把public static Class forName(String name, boolean initialize, ClassLoader loader)的第二个参数指定为false的情况完全一样。其实每当我们写完一个编译单元以后就会得到一个.calss文件,这个文件中就包含了该类的Class对象。JVM就是利用这个class对象来进行动态装载类的。

【编辑推荐】

  1. 深入Java布局管理器
  2. Java软件架构设计简介
  3. Java和PHP在Web开发方面的比较
责任编辑:田超 来源: JAVA8
相关推荐

2021-07-05 06:51:43

Java机制类加载器

2023-10-17 09:26:44

Java工具

2011-09-27 10:23:24

Java反射机制

2011-06-08 10:06:32

C#

2017-03-08 10:30:43

JVMJava加载机制

2017-09-20 08:07:32

java加载机制

2012-07-09 14:25:04

程序集加载

2021-01-06 09:01:05

javaclass

2011-07-12 10:24:17

类加载反射

2023-10-31 16:00:51

类加载机制Java

2023-05-10 11:07:18

2012-04-05 13:50:38

Java

2020-05-20 22:13:26

JVM加载机制虚拟机

2011-04-01 14:50:56

Java的反射机制

2024-03-12 07:44:53

JVM双亲委托机制类加载器

2012-01-18 11:24:18

Java

2021-04-29 11:18:14

JVM加载机制

2017-05-17 15:28:15

Java反射机制

2017-03-24 09:44:33

Java反射机制

2011-03-09 09:11:52

java反射机制
点赞
收藏

51CTO技术栈公众号