一、相关概念介绍
反射:是在Java虚拟机运行时,动态操作类及相关属性的一种能力。
Class 类:Java虚拟机为每个类型管理一个Class对象,包含了与类有关的信息,当通过 javac 编译Java类文件时,生成的同名 .class 文件保存着该类的 Class 对象,JVM 加载一个类即是加载该 .class 文件。
Field:描述类的域(属性),可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
Method :描述类的方法,可以使用 invoke() 方法调用与 Method 对象关联的方法;
Constructor :描述类的构造器,可以用 Constructor 创建新的对象。
二、相关用法
先有Person 类
package com.zzq.myapplication;
public class Person {
String name;
int age;
String id;
public Person(String name, int age, String id) {
this.name = name;
this.age = age;
this.id = id;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String getId() {
return id;
}
private void setId(String id) {
this.id = id;
}
}
1.获取Class类的方法。
Class c1 = Class.forName("com.zzq.myapplication.Person"); // 第1种,forName 方式获取Class对象
Class c2 = Person.class; // 第2种,直接通过类获取Class对象
Person person= new Person();
Class c3 = person.getClass(); // 第3种,通过调用对象的getClass()方法获取Class对象
2.通过Class类获取类对象的方法
Class c = Person.class;
Person person = (Person) c.newInstance(); // 第1种方式:使用Class对象的newInstance()方法来创建Class对象对应类的实例
System.out.println(person);
String name =person.getName();
Constructor constructor = c.getConstructor(name.getClass());
Person person2 = (Person)constructor.newInstance(name); // 第2种方式:先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。
3.获取类信息的部分API
String getName() 获取这个Class的类名。
Constructor[] getDeclaredConstructors() 返回这个类的所有构造器的对象数组,包含保护和私有的构造器;相近的方法 getConstructors() 则返回这个类的所有公有构造器的对象数组,不包含保护和私有的构造器。
Method[] getDeclaredMethods() 返回这个类或接口的所有方法,包括保护和私有的方法,不包括超类的方法;相近的方法 getMethods() 则返回这个类及其超类的公有方法的对象数组,不含保护和私有的方法。
Field[] getDeclaredFields() 返回这个类的所有域的对象数组,包括保护域和私有域,不包括超类的域;还有一个相近的API getFields(),返回这个类及其超类的公有域的对象数组,不含保护域和私有域。
int getModifiers() 返回一个用于描述Field、Method和Constructor的修饰符的整形数值,该数值代表的含义可通过Modifier这个类分析
Modifier 类 它提供了有关Field、Method和Constructor等的访问修饰符的信息,主要的方法有:toString(int modifiers)返回整形数值modifiers代表的修饰符的字符串;isAbstract是否被abstract修饰;isVolatile是否被volatile修饰;isPrivate是否为private;isProtected是否为protected;isPublic是否为public;isStatic是否为static修饰;等等,见名知义。
这里提供一个快速记忆的点子,方法带Declared修饰的方法或者变量,都是能获取到全部权限的,包括private、protected、public,默认。方法名称后带s都是获取所有方法或者是变量。
4.利用反射调用对象的private方法。
Person person = new Person("Tom",21,"233345566");
try {
Class<?> aClass = Class.forName("com.zzq.myapplication.Person");
Method setId = aClass.getDeclaredMethod("setId", String.class);//获取指定的方法
if(!setId.isAccessible()){//如果该方法为私有private ,则需要设置setAccessible(true)
setId.setAccessible(true);
}
setId.invoke(person,"999999999999");//用反射设置id 为999999999999
Log.d(TAG, "testReflect: getId= "+person.getId());
Field id = aClass.getDeclaredField("id");//通过反射获取对象的属性名。
String string = (String) id.get(person);//通过反射获取对象的属性值。
Log.d(TAG, "testReflect: string= "+string);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
二、反射的作用
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。
反射的应用场合:在编译时根本无法知道该对象或类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息。