首页 > 技术文章 > java 反射 类装载器

xinde123 2017-09-27 12:09 原文

前言:

     java语言允许通过程序化的方式间接对Class进行操作,Class文件由类装载器装载后,在jvm中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息,如构造函数,属性和方法等,

java允许用户借由这个与Class相关的元信息对象间接调用Class对象的功能,这就为使用程序化方式操作Class对象开辟了途径。

实例:

下面一个Car类拥有两个构造函数,一个方法及三个属性

package reflect;

public class Car {
    private String brand; //品牌
    private String color; //颜色
    private int maxSpeed; //转速

    public Car(){}

    public Car(String brand, String color, int maxSpeed){
        this.brand = brand;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
    public void say(){
        System.out.println("brand:"+ brand + ", color:"+ color +", maxSpeed:"+ maxSpeed);
    }

//set和get 方法省略

一般情况下,我们会使用如下代码创建Car的实例:

Car car = new Car();
car.setBrand("红旗");

这种是采用传统方式直接调用目标类,下面我们可以使用java反射机制以一种间接的方式操控目标类:

public class ReflectTest {

    public static Car initByDefaultConst() throws Throwable{
        // 1. 通过类装载器获取Car类的对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        //使用全限定名来找class类
        Class clazz = loader.loadClass("reflect.Car");

        /*Class clazz = Class.forName("reflect.Car");*/  //另一种方式获取class

        // 2. 获取类的默认构造器对象并通过它实例化Car
        Constructor cons = clazz.getDeclaredConstructor((Class[])null);
        Car car = (Car)cons.newInstance();

        // 3. 通过反射方法设置属性
        Method setBrand = clazz.getMethod("setBrand", String.class);
        setBrand.invoke(car,"红旗");
        Method setColor = clazz.getMethod("setColor", String.class);
        setColor.invoke(car,"黑色");
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
        setMaxSpeed.invoke(car,200);
        return car;
    }
    @Test
    public void test() throws Throwable{
        Car car = initByDefaultConst();
        car.say();
    }
}

运行以上程序,在控制台打印如下: brand:红旗, color:黑色, maxSpeed:200

上述的程序只是用了很少的api,java反射包为我们提供了很多的方法,可以细查。

其余扩展:

类装载器ClassLoader的工作机制:

   类装载器就是寻找类的节码文件并构造出类在jvm内部表示对象的组件,在java中,类装载器把一个类装入jvm中,需要经过如下步骤:

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

   2.  链接:执行校验,准备和解析步骤,其中解析步骤是可以选择的

    2.1. 校验:检查载入Class文件数据的正确性

    2.2. 准备: 给类的静态变量分配存储空间

    2.3. 解析:将符号引用转换成直接引用

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

JVM装载类使用 “全盘负责委托机制”,

全盘负责”是指当一个ClassLoader装载一个类时(除非显式的使用另一个ClassLoader),该类所依赖及引用的类也由这个ClassLoader载入;

委托机制”是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。

这一点是从安全角度考虑的,试想,如果有一个人编写了一个恶意的基础类(如java.lang.String)并装载到JVM中,将会引起多么可怕的后果,

但是由于有了“全盘负责委托机制”,java.lang.String永远是根装载器来装载的,这样就避免了上述安全隐患的发生。

   

推荐阅读