本文会从以下几个方面讲起
① 反射的简单解释
② java反射的API接口 及 demo
③ 反射的优缺点、应用场景
一、什么是反射?
java反射:在程序运行中动态获取类的信息,及动态调用对象的方法,这就是java反射
二、java反射的API接口
常用API接口规律
getXX() : 获取类本身 及父类的public属性、方法等
getDeclaredXX() : 获取类本身的所有私有、保护属性、方法等
getDeclaredXX(String name) : 获取类本身的指定name的私有、保护属性、方法等(getDeclaredConstructors 较特殊, 还可以获取public)
以下demo涉及到的类先给出咯
package test.reflect;// 父类public abstract class Vehicle { public String superField = "父类属性"; private String superPrivateField = "父类私有属性"; protected String superProtectedField = "父类保护属性"; public abstract void run(); private void superPrivateMethod() { } protected void superProteMethod() { }}// 飞机子类package test.reflect;public class Airplane extends Vehicle { private String name; private int price; public String publicField; protected String protectedField; private Airplane() { System.out.println("Airplane 构造函数"); } public Airplane(String name, int price) { this.name = name; this.price = price; } public void run() { System.out.println("春节,坐飞机飞回家~~~"); } protected void protectedMethod() { } private void privateMethod() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }}// 高铁子类package test.reflect;public class HighSpeedTrain extends Vehicle { private String name; private int price; public void run() { System.out.println("春节,坐高铁溜回家~~~"); } private HighSpeedTrain() { } protected HighSpeedTrain(String name) { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }}
① 使用反射构建对象
1 private static void demo2() throws Exception {2 3 Class.forName("test.reflect.Airplane").newInstance();4 5 Airplane.class.newInstance();6 7 8 Airplane.class.getDeclaredConstructor(new Class[]{}).newInstance(); // new Class[]{} 使用无惨构造函数9 }
所有类都是Class对象, 获取class 有以下三种
Class.forName(包名+类名)
xx.class
xx.getClass
② 获取属性
getFields() : 获取父子类的所有public属性
getDeclaredFields() : 获取子类的所有private\protected属性
demo如下 :
private static void demo3() throws Exception { // 获取父子类的所有public属性 Field[] fields = Airplane.class.getFields(); for(Field f : fields) { print(f.getName()); } // 获取子类的所有private\protected属性 Field[] fields2 = Airplane.class.getDeclaredFields(); for(Field f : fields2) { print(f.getName()); } // 获取指定属性名的属性 Field f = Airplane.class.getDeclaredField("name"); print(f.getName()); }
结果
1 -------getFields------- 2 3 publicField 4 5 superField 6 7 -------getDeclaredFields------- 8 9 name10 11 price12 13 publicField14 15 protectedField16 17 --------getDeclaredField(String)------18 19 name
③ 获取方法
getMethods() : 获取父子类的所有public方法
getDeclaredMethods() : 获取子类的所有private\protected方法
demo如下 :
private static void demo4() throws Exception { Method[] methods = Airplane.class.getMethods(); for(Method m : methods) { print(m.getName()); } Method[] methods2 = Airplane.class.getDeclaredMethods(); for(Method m : methods2) { print(m.getName()); } Method m = Airplane.class.getDeclaredMethod("getName"); print(m.getName()); }
结果 :
1 ------getMethods-------- 2 run 3 getName 4 setName 5 getPrice 6 setPrice 7 wait 8 wait 9 wait10 equals11 toString12 hashCode13 getClass14 notify15 notifyAll16 ------getDeclaredMethods--------17 run18 getName19 setName20 protectedMethod21 privateMethod22 getPrice23 setPrice24 --------getDeclaredMethod------25 getName
④ 获取构造函数(和前面有所区别,指类本身的构造函数,不包括父类)
getConstructors() : 获取public构造函数
getDeclaredConstructors() : 获取子类的所有private\protected\public构造函数 (注意 : 这里还能获取public的, 和 getDeclaredFields getDeclaredMethods 不同)
demo如下 :
Airplane构造函数是public修饰private static void demo5() throws Exception { Constructor [] constructors = Airplane.class.getConstructors(); for(Constructor c : constructors) { print(c.getName()); } System.out.println("--------------"); Constructor [] constructors2 = Airplane.class.getDeclaredConstructors(); for(Constructor c : constructors2) { print(c.getName()); } System.out.println("--------------"); Constructorc = Airplane.class.getDeclaredConstructor(new Class[]{String.class, int.class}); print(c.getName()); }// 结果-------getConstructors-------test.reflect.Airplane-------getDeclaredConstructors-------test.reflect.Airplanetest.reflect.Airplane-------getDeclaredConstructor(Class )-------test.reflect.AirplaneHighSpeedTrain构造函数是private protected修饰private static void demo6() throws Exception { System.out.println("------getConstructors--------"); Constructor [] constructors = HighSpeedTrain.class.getConstructors(); for(Constructor c : constructors) { print(c.getName()); } System.out.println("------getDeclaredConstructors--------"); Constructor [] constructors2 = HighSpeedTrain.class.getDeclaredConstructors(); for(Constructor c : constructors2) { print(c.getName()); } }// 结果------getConstructors--------------getDeclaredConstructors--------test.reflect.HighSpeedTraintest.reflect.HighSpeedTrain
三、java 反射的优缺点
① 优点 :
- 在运行时检测对象的类型;
- 动态构造某个类的对象;
- 检测类的属性和方法;
- 任意调用对象的方法;
- 修改构造函数、方法、属性的可见性;
- 以及其他。
② 缺点 :性能下降 . 由于反射涉及动态解析类型, 所以使用反射构建对象 比 直接构造对象性能差了一两个数量级
private static void demo7() throws Exception { long start = System.currentTimeMillis(); for(int i = 0; i < 10000; i++) { Airplane a = new Airplane(); } System.out.println(System.currentTimeMillis() - start); start = System.currentTimeMillis(); for(int i = 0; i < 10000; i++) { Airplane a2 = Airplane.class.getDeclaredConstructor().newInstance(); } System.out.println(System.currentTimeMillis() - start); }// 结果454
四、反射应用场景
① junit test, 使用注解@Test , 底层无非是使用反射来获取加了Test的注解标识,从而获取到测试方法。
② spring aop思想, spring 加载bean xml 配置文件, 使用 Class.forName(String beanName) 动态构造bean, 也都是反射的经典例子。