参考博客:
https://www.cnblogs.com/ysocean/p/6516248.html
https://www.sczyh30.com/posts/Java/java-reflection-1/
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射的核心是 JVM 在运行时才动态加载类或调用方法 / 访问属性,它不需要事先(写代码时或编译期)知道运行对象是谁;
很多人都认为反射在实际的 Java 开发应用中并不广泛,其实不然。当我们在使用 IDE(如 Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射最重要的用途就是开发各种通用框架,各框架大量使用了动态代理,而动态代理的实现依赖于反射技术.
以下我会全部使用 clazz 表示某个类的 Class 实例
(1)、获取 Class 对象
// Class 类的 forName 静态方法
Class.forName("xxx");
// 直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
Class clazz = Person.class;
// 通过对象的 getClass() 方法,通常用在方法参数
Person p = new Person();
Class clazz = p.getClass();
(2)、判断是否为某个类的实例
instanceof
关键字判断是否为某个类的实例;public native boolean isInstance(Object obj);
(3)、创建实例
使用 Class 对象的 newInstance()
方法创建 Class 对象对应的实例;(调用无参构造函数)
Class clazz = Person.class;
Person person = clazz.newInstance();
通过 Class 对象获取指定的 Constructor
对象(带参数的构造函数),在调用 Constructor
对象的 newInstance()
方法创建实例
Class clazz = Person.class;
// 获取 Person 类带一个 String 类型的参数的构造器
Constructor con = clazz.getConstructor(String.class);
// 根据构造器创建实例
Person person = con.newInstance("xiaojian");
(4)、获取构造器
// 通过 Class 类的实例获取 Constructor,参数为指定构造器的参数的类型的Class对象
Class clazz = Person.class;
Constructor c = clazz.getConstructor(String.class);
// 再由构造器使用 newInstance()方法 创建实例对象
Person person = c.newInstance("xiaojian");
(5)、获取方法
getDeclaredMethods
方法返回接口或接口声明的所有方法,包括公共、保护、默认和私有方法,但不包括继承方法;
public Method[] getDeclaredMethods() throws SecurityException
getMethods
方法返回某个类的所有公用 (public) 方法,包括其继承类的公用方法;
public Method[] getMethods() throws SecurityException
getDeclaredMethod
方法可返回所有方法 (不包括继承方法), 其中第一个参数为方法名称,后面的参数为方法的参数对应的 Class 的对象。并且,如果获取的是私有方法(并且不是当前类的,是包里其他的类的私有方法),使用 invoke()
方法调用之前,必须给 Method 对象 setAccessible(true)
来设置或取消访问检查,以达到访问私有对象的目的。Field 也一样。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
// 如
Method method = clazz.getMethod("study",String.class,String.class);
method.setAccessible(true);
method.invoke(clazz.newInstance(),"xiaojian","abc");
getMethod
方法返回某个特定非私有的方法(包括其继承类的公用方法),其中第一个参数为方法名称,后面的参数为方法的参数对应的 Class 的对象
public Method getMethod(String name, Class<?>... parameterTypes)
// 如
clazz.getMethod("study",String.class,String.class);
(6)、调用方法
从类中获取方法后,使用
invoke()
方法调用这个方法
public class ReflectTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 使用带参数的构造器,创建实例对象
Class clazz = Person.class;
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object object = constructor.newInstance("小贱",38);
System.out.println(object);
System.out.println("====== 方法调用 ======");
// 调用没有参数的公共 eat 方法
Method m1 = clazz.getMethod("eat");
// invoke 的参数是方法的类的实例对象,不是 Class 对象
m1.invoke(object);
System.out.println("mm");
// 调用父类 Object 的方法
Method m = clazz.getMethod("hashCode");
Object o = m.invoke(object);
System.out.println(o);
System.out.println("mm");
// 调用带一个参数的公共 eat 方法
Method m2 = clazz.getMethod("eat",String.class);
m2.invoke(object,"米饭");
// 调用带三个参数的私有 eat 方法
Method m3 = clazz.getDeclaredMethod("eat",String.class,String.class,int.class);
// 不是当前 main 方法的类 ReflectTest,调用其他类的私有方法,必须 `setAccessible(true)`
m3.setAccessible(true);
System.out.println(m3.toGenericString());
Object result = m3.invoke(object,"牛肉面","可乐",3);
System.out.println(result);
}
}
// 其他的类
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃");
}
public void eat(String food){
System.out.println("吃" + food);
}
// 私有方法
private String eat(String food,String drink,int count){
return count + "份" + food + "," + count + "份" + drink + ".";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
(7)、获取成员变量
getFields
访问所有公有的成员变量,包括父类的;
public Field[] getFields() throws SecurityException;
getDeclaredFields
所有已声明的成员变量,包括私有 (private修饰的) 变量,不包括父类的;
public Field[] getDeclaredFields() throws SecurityException;
getField
访问指定的 成员变量**(非私有的、父类的)**;
public Field getField(String name) throws NoSuchFieldException,SecurityException
// 获取成员变量值
Object object = clazz.newInstance();
Field field = clazz.getField("xxx");
System.out.println(field.get(object));
// 重新设置成员变量值为 "abc"
field.set(object,"abc");
System.out.println(field.get(object));
getDeclaredField
访问指定的成员变量**(所有的、不包括父类的)**,访问或修改该成员变量前要 setAccessible(true)
。
public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException
// 获取成员变量值
Object object = clazz.newInstance();
Field field = clazz.getField("xxx");
field.setAccessible(true);
System.out.println(field.get(object));
// 重新设置成员变量值为 "abc"
field.set(object,"abc");
System.out.println(field.get(object));
public class ReflectTest_Field {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class clazz = Class.forName("com.xiaojian.basics.basics_test.Son");
Object object = clazz.newInstance();
System.out.println("====== 获取公有的成员变量,包括父类的 ======");
// 获取公有的成员变量,包括父类的
Field[] fields1 = clazz.getFields();
for(Field field : fields1){
System.out.println(field.getName());
}
System.out.println("====== 获取所有的成员变量,包括私有的,不包括父类的 ======");
// 获取所有的成员变量,不包括父类的
Field[] fields2 = clazz.getDeclaredFields();
for(Field field : fields2){
System.out.println(field.getName());
}
System.out.println("====== 获取成员变量,公共的 ======");
Field field1 = clazz.getField("son_pub");
System.out.println(field1.get(object));
field1.set(object,"重新set son_pub");
System.out.println(field1.get(object));
System.out.println("====== 获取成员变量,父类的 ======");
Field field2 = clazz.getField("father_pub");
System.out.println(field2.get(object));
field1.set(object,"重新set father_pub");
System.out.println(field1.get(object));
System.out.println("====== 获取成员变量,私有的 ======");
Field field3 = clazz.getDeclaredField("son_pri");
// 不止是修改前,访问该成员变量前,都要设置 setAccessible
field3.setAccessible(true);
System.out.println(field3.get(object));
field1.set(object,"重新set son_pri");
System.out.println(field1.get(object));
}
}
class Son extends Father{
public String son_pub = "son pub";
private String son_pri = "son pri";
}
class Father{
public String father_pub;
private String father_pri;
}
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。