What
JAVA反射机制是在运行状态中,对任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取以及动态调用对象的方法的功能成为java语言的反射机制。
Why
在不更改源代码的情况下,提供程序的扩展性,使开发更简单(接口加配置文件)
EG:Tomcat 工作原理
How
Class类可以获取字节码文件中的所有内容,反射就是依靠该类完成。想要获取类中的信息,只要获取到字节码文件对应的对象即可。
获取字节码对应的对象
Object类中的getClass方法,使用这种方法,必须要明确具体的类,并创建对象 —-(复杂)
public static void getClass1() { Car car = new Car(); Class clazz = car.getClass(); Car car1 = new Car(); Class clazz1 = car1.getClass(); System.out.println(clazz == clazz1); }
任何数据类型都具备一个静态的数据类型.class来获取对应的Class对象相对简单,但是还是要明确用到类中的静态成员,达不到扩展的效果
public static void getClass2() { Class clazz = Car.class; Class clazz1 = Car.class; System.out.println(clazz == clazz1); }
只要通过给定的类的名称就可以获取该类,更为扩展.可以使用Class中的方法完成,该方法就是forName,只要有名称即可,更为方便,扩展性更强
public static void getClass3() { String className = "ung8023.base.reflect.Car"; Class clazz = null; try { clazz = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(clazz == null ? "null" : clazz); }
获取构造方法
无参构造方法
public static void createObject1() throws ClassNotFoundException, InstantiationException, IllegalAccessException { /* 通过new关键字创建对象,现根据new的类的名称找寻该类的字节码文件,并加载进内存 并创建该字节码文件对象,接着创建该字节码文件的对应的Car对象 */ ung8023.base.reflect.Car car = new ung8023.base.reflect.Car(); //使用反射: String name = "ung8023.base.reflect.Car"; //找寻该名称类文件,并加载进内存,并产生Class对象 Class clazz = Class.forName(name); //生成该类的对象,如果无空参构造函数会报InstantiationException,如果无参构造方法为私有,则IllegalAccessException Object obj = clazz.newInstance(); }
有参构造方法
public static void createObject2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //ung8023.base.reflect.Car car = new ung8023.base.reflect.Car("oooo", 300); /* 当获取指定名称对应类中所体现的对象时,而该对象初始化不使用空参构造方法 既然是通过指定的函数进行对象的初始化,所以应该先获取到该构造函数。 通过字节码文件对象即可完成,通过getConstructor(Class<?> ...param); 通过getDeclaredConstructor();可获取到所有(包括私有)构造方法。 */ //使用反射: String name = "ung8023.base.reflect.Car"; //找寻该名称类文件,并加载进内存,并产生Class对象 Class clazz = Class.forName(name); //获取构造器对象 Constructor constructor = clazz.getConstructor(String.class, int.class); Object car = constructor.newInstance("Aodi", 300); }
获取属性
public static void getField() throws Exception {
Class clazz = Class.forName("ung8023.base.reflect.Car");
Field field = null;//clazz.getField("speed");只能获取共有的
field = clazz.getDeclaredField("maxSpeed");// 只获取本类,但包含私有
//对私有字段访问取消权限检查,暴力访问(不建议)
field.setAccessible(true);
Object obj = clazz.newInstance();
field.set(obj, 100);
Object o = field.get(obj);
System.out.println(o);
}
获取方法
查看所有方法
public static void getMethod() throws Exception{ Class clazz = Class.forName("ung8023.base.reflect.Car"); Method[] methods = clazz.getMethods(); Object obj = clazz.newInstance(); for(int i=0; i<methods.length; i++) { System.out.println(methods[i]); } }
运行无参方法
public static void getMethod_1() throws Exception{ Class clazz = Class.forName("ung8023.base.reflect.Car"); Object obj = clazz.newInstance(); Method method = clazz.getMethod("run", null); method.invoke(obj, null); }
运行带参方法
public static void getMethod_2() throws Exception{ Class clazz = Class.forName("ung8023.base.reflect.Car"); Object obj = clazz.newInstance(); Method method = clazz.getMethod("paramMethod", String.class, int.class); method.invoke(obj, "audi",300); }
Car类源码
public class Car {
private String name;
private int maxSpeed;
public Car(String name, int maxSpeed) {
super();
this.name = name;
this.maxSpeed = maxSpeed;
System.out.println("paramContructorRun");
}
public Car() {
super();
System.out.println("noparamConstructor");
}
private void privateMethod() {
System.out.println("privateMehtod run");
}
public void run() {
System.out.println("run");
}
public void paramMethod(String str, int speed) {
System.out.println("paramMethod run " + str + ":" + speed);
}
public static void staticMethod() {
System.out.println("staticMethod run");
}
}
Sample(以电脑运行为例)
主板增加扩展性,通过声明PCI接口来达到扩展性.读取配置文件,来达到扩展性。
Computer类
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Properties; public class Computer { public static void main(String[] args) throws Exception { run(); } public static void run() throws Exception { MainBoard mainBoard = new MainBoard(); //读取配置文件(一般使用xml,此处使用properties代替) File configFile = new File("pciproperties.properties"); //定义Properties对象 Properties prop = new Properties(); //使用流关联文件 FileInputStream fis = new FileInputStream(configFile); //将文件加载入Properties prop.load(fis); for(int i=0; i < prop.size(); i++) { String pciName = prop.getProperty("pci"+(i+1)); Class pciClass = Class.forName(pciName); PCI pci = (PCI)pciClass.newInstance(); mainBoard.pciRun(pci); mainBoard.pciClose(pci); } fis.close(); } }
PCI接口
public interface PCI { void start(); void close(); }
MainBoard类
public class MainBoard { public void mainBoardRun() { System.out.println("mainboard run"); } public void pciRun(PCI pci) { pci.start(); } public void pciClose(PCI pci) { pci.close(); } }
NetCard类
public class NetCard implements PCI { @Override public void start() { System.out.println("net run"); } @Override public void close() { System.out.println("net close"); } }
SoundCard类
public class SoundCard implements PCI { @Override public void start() { System.out.println("sound run"); } @Override public void close() { System.out.println("soundclose"); } }
pciproperties.properties文件
pci1 = ung8023.base.reflect.sample.NetCard pci2 = ung8023.base.reflect.sample.SoundCard