原文:格子衫幽默
概述
概念性的东西不用多说,大家可以百度,我这边就copy下:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
介绍
废话不多说,对反射有一定的了解的人应该知道反射常用的一些类和方法。我们就以两个不同方式执行同样操作为起点,看下面两段代码:
//正向方式
Person person = new Person();
person.setName("正射");
System.out.println(person.getName());
//反射方式
Class clz = Class.forName("com.uhande.reflect.Person");
Method method = clz.getMethod("setName", String.class);
Constructor constructor = clz.getConstructor();
Person personReflect = (Person)constructor.newInstance();
method.invoke(personReflect,"反射");
System.out.println(personReflect.getName());
执行结果:
正射
反射
很显然执行结果是一样的。不一样的是前者是知道类和方法,直接执行,后者是在在执行的时候通过给定的字符串才知道执行的类什么。
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
反射常用的Api
相关类:
类名 作用
Class 类的实体,在运行的Java应用程序中表示类和接口
Field 类的成员变量(成员变量也称为类的属性)
Method 类的方法
Constructor 类的构造方法
获取Class类对象的三种方法:
1. 使用 Class.forName 静态方法
Class c1 = Class.forName(“java.lang.String”);
2.直接通过 类名.class 的方式得到
Class c2 = String.class;
3.通过对象调用 getClass() 方法来获取
String str = new String("Hello");
Class c3 = str.getClass();
注意:一个类在 JVM 中只会有一个 Class 实例,即我们对上面获取的 c1、c2和c3进行 equals 比较,发现都是true。
通过反射的Class创建类对象
1.newInstance()
Class personClass = Person.class;
Person person = personClass.newInstance();
2.Constructor 对象的 newInstance()
1). 无参构造
Class clz = Class.forName("com.uhande.reflect.Person");
Constructor constructor = clz.getConstructor();
Person personReflect = (Person)constructor.newInstance();
2). 有参构造
Method method = clz.getMethod("setName", String.class);
Constructor constructor1 = clz.getConstructor(String.class, int.class);
Person personReflect = (Person)constructor1.newInstance("反射",22);
通过反射获取类属性、方法、构造器
通过 Class 对象的 getFields() 方法可以获取 Class 类的属性,但无法获取私有属性
Class clz1 = Person.class;
Field[] fields = clz1.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
使用 Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性
Class clz1 = Person.class;
Field[] fields = clz1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
由于获取方式一样,下面方法一笔带过:
指定字段属性:getDeclaredField(String name);
获取public类型方法:getMethods();
获取所有方法:getDeclaredMethods();
获取特定的方法,name是方法名,parameterTypes为参数类型:getMethod(String name, Class[] parameterTypes);
所有构造:getConstructors();
特定构造:getConstructor(Class[] parameterTypes);
共有注解:getAnnotations();
所有注解:getDeclaredAnnotations();
不难看出也有规律:带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。
总结
反射在业务代码中用的不是很多,主要在设计模式,框架设计上使用较多。
常见于动态代理的实现,还有JDBC原生代码注册驱动,hibernate的实体类,Springde AOP等等。
缺点: 效率低,破坏原有封装,可以调用到私有方法,不安全。
优点: 灵活,解耦
最后
常见的一些关于反射的问题:
1. new 的对象和反射得到的对象的区别
1). 反射的类确保已被加载,new的对象不需要考虑
2). new的可以调用任何公有方法,反射只能调用无参构造
3). new的效率高,反射弱类型相对效率低
4). 反射创建帝乡解耦
2. 常量能否被反射改变值:
对于基本类型的静态变量,java在编译的时候就会把代码中对此常量中引用的地方替换成相应常量值
网友评论