关于反射的一点理解
最近在看《Spring 3.x企业应用开发实战》这本书,这本书上面写了对于反射的一些理解。虽然之前也看过很多次反射的内容,但是一直感觉自己对反射半懂不懂的。看了这本书上写的,有一种茅塞顿开的感觉,所以在这里记录一下。
首先我们写一个Car类,它拥有两个构造函数、两个方法和三个属性。
1 package com.baobaotao.reflect; 2 3 /** 4 * Created by Jean on 16/4/25. 5 */ 6 public class Car { 7 private String brand; 8 private String color; 9 private int maxSpeed; 10 11 public Car(){} 12 13 public Car(String brand, String color, int maxSpeed) { 14 this.brand = brand; 15 this.color = color; 16 this.maxSpeed = maxSpeed; 17 } 18 19 public void introduce() { 20 System.out.println("brand:" + brand + ";color:" + color 21 + ";maxSpeed:" + maxSpeed); 22 } 23 24 public String getBrand() { 25 return brand; 26 } 27 28 public void setBrand(String brand) { 29 this.brand = brand; 30 } 31 32 public String getColor() { 33 return color; 34 } 35 36 public void setColor(String color) { 37 this.color = color; 38 } 39 40 public int getMaxSpeed() { 41 return maxSpeed; 42 } 43 44 public void setMaxSpeed(int maxSpeed) { 45 this.maxSpeed = maxSpeed; 46 } 47 }
一般而言,我们创建Car的实例和调用方法的时候,是如下的过程:
Car car = new Car(); car.setBrand("红旗CA72",“黑色”,200);
这就是我们传统的直接创造实例和调用方法的过程。
直接创造实例的过程如下:
1.Car car是声明一个引用变量,要求虚拟机分配空间给名字为car的引用变量,就像一个控制Car的遥控器。
2.new Car()是要求Java虚拟机分配堆空间给新建立的Car对象
3.中间的“=”号表示着将这个堆里的Car对象,交给引用类型car来控制。
4.car.setBrand方法,表示通过引用对象car来Car对象来执行setBrand方法。
接下来我们使用反射的方式来调用:
1 package com.baobaotao.reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 6 /** 7 * Created by Jean on 16/4/25. 8 */ 9 public class ReflectTest { 10 public static Car initByDefaultConst() throws Throwable { 11 //通过类装载器获取Car类对象 12 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 13 Class clazz = loader.loadClass("com.baobaotao.reflect.Car"); 14 //获取类的默认构造器对象并通过它实例化Car 15 Constructor cons = clazz.getDeclaredConstructor((Class[])null); 16 Car car = (Car)cons.newInstance(); 17 //通过反射的方法设置属性 18 Method setBrand = clazz.getMethod("setBrand", String.class); 19 setBrand.invoke(car, "红旗CA72"); 20 Method setColor = clazz.getMethod("setColor", String.class); 21 setColor.invoke(car, "黑色"); 22 Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class); 23 setMaxSpeed.invoke(car, 200); 24 return car; 25 } 26 27 public static void main(String[] args) throws Throwable { 28 Car car = initByDefaultConst(); 29 car.introduce(); 30 } 31 }
运行以上程序,在控制台上将打印出以下信息:
brand:红旗CA72;color:黑色;maxSpeed:200
接下来具体说说反射的方法:
Java的执行过程,我们简单理解为几步:
1,Java文件由编译器编译成class文件;
2,class文件由JVM
装载(查找和导入Class文件)
链接(执行校验、准备和解析步骤)
和初始化(对类的静态变量、静态代码块执行初始化工作)
和初始化(对类的静态变量、静态代码块执行初始化工作)
传统的方法,用的是我们所谓的静态编译,指的是静态编译就是在编译的时候把你所有的内容都编译进class里去,然后最后一起执行。
而反射,用的是动态的编译,在编译的时候不急着编译进去,等到了最后JVM装载的过程中,再通过一些对class的操作来执行一些操作。
因为Class本身也是一个特殊的类,反射就是利用了这个特点,直接对class本身进行操作:
1.首先通过ClassLoader获取Car对象的Class
2.然后获取类的默认构造器对象并通过它实例化Car
3.再通过反射来设置属性