一、反射机制概念
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
二、反射机制的作用
- 在运行时判断任意一个对象所属的类;
- 在运行时获取类的对象;
- 在运行时访问java对象的属性,方法,构造方法等。
三、反射机制的优点与缺点
优点:可以实现动态创建对象和编译,体现出很大的灵活性.
编译方式说明:
静态编译:在编译时确定类型 & 绑定对象。如常见的使用new关键字创建对象
动态编译:运行时确定类型 & 绑定对象。动态编译体现了Java的灵活性、多态特性 & 降低类之间的藕合性
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
四、具体使用
反射机制的实现主要通过操作java.lang.Class类。
在Java程序运行时,Java运行环境会为所有类维护一个java.lang.Class对象,存放着对应类型对象的运行时信息。
Java反射机制的实现除了依靠Java.lang.Class类,还需要依靠:Constructor类、Field类、Method类,分别作用于类的各个组成部分:
在使用Java反射机制时,主要步骤包括:
- 获取目标类型的Class对象
- 通过Class对象分别获取Constructor类对象、Method类对象 & Field 类对象
- 通过Constructor类对象、Method类对象 & Field类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作
1、获得class对象
(1) 使用 Class 类的 forName 静态方法
Class<?> classtype3 = Class.forName("java.lang.Boolean");
System.out.println(classtype3);
(2) 直接获取某一个对象的 class
Class<?> classtype2 = Boolean.class;
System.out.println(classtype2);
Class<?> classtype4 = Boolean.TYPE;
System.out.println(classtype4);
(3) 调用某个对象的 getClass() 方法
Boolean flg = true;
Class<?> classtype = flg.getClass();
System.out.println(classtype);
(4) 获取父类 getSuperclass();
Class<?> classtype4 = Class.forName("java.lang.Boolean");
classtype4.getSuperclass();
2、判断是否为某个类的实例
一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:
public native boolean isInstance(Object obj);
3、创建实例以及获取构造方法
(1) 使用Class对象的newInstance()方法来创建Class对象对应类的实例。
(2) 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
4、获取方法
(1) getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
(2) getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
(3) getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
public Method getMethod(String name, Class<?>... parameterTypes)
- getDeclaredMethod 方法返回一个特定的方法,但不包括继承的方法。
5、获取类的成员变量(字段)信息
(1) getFiled:获得指定的公有成员变量
(2) getDeclaredField:获得指定已声明的成员变量,但不能得到其父类的成员变量
(3) getFileds:获得所有公有的成员变量
(4) getDeclaredFields:获得所有已声明的成员变量,但不能得到其父类的成员变量
(5) 获取指定对象的指定字段的值 field.get(obj)
(6) 设置指定对象的指定对象Field值 field.set(obj, “123”);
6、调用方法
当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。invoke 方法的原型为:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
7、获得注解
Class类、Field类、Method类 & Constructor类对象都有如下方法
getAnnotations();
getDeclaredAnnotations();
getAnnotation(annotationClass);
8、关于private
反射机制的默认行为受限于Java的访问控制,无法访问( private )私有的方法、字段。
Java安全机制只允许查看任意对象有哪些域,而不允许读它们的值若强制读取,将抛出异常。
使用Field类、Method类 & Constructor类对象的setAccessible()可以脱离Java程序中安全管理器的控制、屏蔽Java语言的访问检查。
五、代码
public class ReflectionTest {
public static void main(String[] args) throws Exception {
// 1、获得class
// 1.1 使用 Class 类的 forName 静态方法
Class<?> class1 = Class.forName("java.lang.Boolean");
System.out.println(class1);
// 1.2 直接获取某一个对象的 class
Class<?> class2 = Boolean.class;
System.out.println(class2);
Class<?> class3 = Boolean.TYPE;
System.out.println(class3);
// 1.3 调用某个对象的 getClass() 方法
Boolean flg = true;
Class<?> class4 = flg.getClass();
System.out.println(class4);
// 1.4 获取父类调用getSuperclass() 方法
Class<?> superclass = class1.getSuperclass();
System.out.println(superclass);
// 2、判断是否为某个类的实例
System.out.println(Boolean.class.isInstance(flg));
// 3、创建实例以及获取构造器
// 3.1 直接通过class对象创建实例
Class<?> m4 = M4A1.class;
Object m4obj1 = m4.newInstance();
System.out.println(m4obj1.toString());
// 3.2 通过class对象获得构造器来实例化对象
// 获得参数的指定构造器
Constructor constructor = m4.getConstructor(String.class,Double.class);
// 获得所有构造器
Constructor<?>[] constructors = m4.getConstructors();
for(Constructor c:constructors){
System.out.println(c);
}
Object m4obj2 = constructor.newInstance("步枪",38.89d);
System.out.println(m4obj2.toString());
// 4、获取方法
// 4.1 获取所有公用方法(public)
Method[] methods = m4.getMethods();
for(Method m:methods){
System.out.println(m);
}
// 4.2 获取所有非继承的方法
Method[] methods2 = m4.getDeclaredMethods();
for(Method m:methods2){
System.out.println(m);
}
// 4.3 由方法名和参数类型获取一个指定方法
Method method = m4.getMethod("setConment", String.class);
System.out.println(method);
Method method2 = m4.getDeclaredMethod("toString");
System.out.println(method2);
// 5、获取成员变量
// 5.1 获取指定变量
Field field = m4.getDeclaredField("conment");
System.out.println(field);
Field field2 = m4.getField("name");
System.out.println(field2);
// 5.2 获取所有变量
Field[] fields = m4.getFields();
for(Field f:fields){
System.out.println(f);
}
Field[] fields2 = m4.getDeclaredFields();
for(Field f:fields2){
System.out.println(f);
}
// 5.3 设定指定字段的值
// 设置可以访问private
field.setAccessible(true);
field.set(m4obj1, "使用Field类的set方法设定conment的值");
// 5.4 获取指定字段的值
Object value = field.get(m4obj1);
System.out.println(value);
// 6、调用方法
// 获得class对象
Class<?> clazz = M4A1.class;
// 实例化
Object m4a1 = clazz.newInstance();
// 获得方法
Method setConmentMethod = clazz.getMethod("setConment",String.class);
Method getConmentMethod = clazz.getMethod("getConment");
Method tostringMethod = clazz.getMethod("toString");
// 调用方法
setConmentMethod.invoke(m4a1, "测试一下invoke调用方法");
Object result = getConmentMethod.invoke(m4a1);
System.out.println(result);
System.out.println(tostringMethod.invoke(m4a1));
}
}
public class M4A1 {
private String conment;
private Double might;
public String name;
/**
* @Title:M4A1
* @Description:TODO
*/
public M4A1() {
super();
// TODO Auto-generated constructor stub
System.out.println("执行无参构造方法");
}
/**
* @Title:M4A1
* @Description:TODO
* @param conment
* @param might
*/
public M4A1(String conment, Double might) {
super();
this.conment = conment;
this.might = might;
System.out.println("执行带参构造方法");
}
/**
* @return the conment
*/
public String getConment() {
return conment;
}
/**
* @param conment
* the conment to set
*/
public void setConment(String conment) {
this.conment = conment;
}
/**
* @return the might
*/
public Double getMight() {
return might;
}
/**
* @param might
* the might to set
*/
public void setMight(Double might) {
this.might = might;
}
/*
* (non Javadoc)
*
* @Title: toString
*
* @Description: TODO
*
* @return
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "M4A1 [conment=" + conment + ", might=" + might + "]";
}
}
参考
https://www.jianshu.com/p/4c07f1824cd8