概述
JAVA反射机制是在运行状中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Class类
我们知道类是具有相同属性或者行为的一类事物,那么类本身也可以再被抽象,因为类们也有共同的属性和行为(比如类都有属性,都有构造器,都有方法,都能调用方法),所以把类们又抽象成了一个类Class。
众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。
在学习Class类的过程中我们还需要学习Field类,Method类,Constructor类
- Field类:类属性的抽象
- Method类:类方法的抽象
- Constructor类:类构造器的抽象
获得一个类的Class的方法
- 方法一:通过Class.forName(“类的全路径”)
try {
Class<Person> aClass = (Class<Person>) Class.forName("com.zdd.Servlet.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 方法二:通过类的名字打点class,如:Person.class
Class<Person> personClass = Person.class;
- 方式三:通过调用该类的对象调用getClass()方法
Person person = new Person();
person.getClass();
其中第二种和第三种式最常用的方法
常用方法
Method类反射调用
-
如果底层方法是实例方法,第一个参数就是该对象实例,第二个参数是方法的参数列表,invoke的返回值就是实例方法的返回值。
-
如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
-
如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
假设有个Person类
public class Person {
private String name;
private Integer age;
private Integer gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Person() {
}
public Person(String name, Integer age, Integer gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
public static void selectTasks(){
System.out.println("查找所有任务");
}
public void getTask(int i){
System.out.println(name+"接收了任务"+i);
}
public void completeTask(){
System.out.println(name+"完成了任务");
}
}
用反射的方式调用Person的getTask方法,这个方法有1个参数
public static void main(String[] args) {
//创建实例对象
Person person = new Person("zdd",18,1);
//得到实例对象的Class类
Class<? extends Person> personClass = person.getClass();
Method[] methods = personClass.getDeclaredMethods();
for (Method md : methods){
if (md.getName().equals("getTask")){
try {
md.invoke(person, 1);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
结果
zdd接收了任务1
用反射的方式调用Person的selectTasks方法,这个方法是一个静态方法
public static void main(String[] args) {
//创建实例对象
Person person = new Person("zdd",18,1);
//得到实例对象的Class类
Class<? extends Person> personClass = person.getClass();
Method[] methods = personClass.getDeclaredMethods();
for (Method md : methods){
if (md.getName().equals("selectTasks")){
try {
md.invoke(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
结果
查找所有任务
用反射的方式调用Person的completeTask方法,这个方法没有参数
public static void main(String[] args) {
//创建实例对象
Person person = new Person("zdd",18,1);
//得到实例对象的Class类
Class<? extends Person> personClass = person.getClass();
Method[] methods = personClass.getDeclaredMethods();
for (Method md : methods){
if (md.getName().equals("completeTask")){
try {
md.invoke(person);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
结果
zdd完成了任务
Field类要掌握的方法
Constructor类要掌握的方法
反射的一些操作示例
通过反射来拷贝对象
public static Object copyObject(Object obj) throws Exception{
//获得传递过来的对象的属性和构造器
Class<? extends Object> class1 = obj.getClass();
Field[] fields = class1.getDeclaredFields();
Constructor<? extends Object> constructor = class1.getConstructor(new Class[]{});
//创建一个对象
Object instance = constructor.newInstance(new Object[]{});
for(Field f :fields){
//获得属性的name
String fname = f.getName();
//获得属性的类型
Class<?> type = f.getType();
//获得属性对应的set方法
String setMethodName = "set"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
String getMethodName = "get"+fname.substring(0, 1).toUpperCase()+fname.substring(1);
//获得get方法
Method gmethod = class1.getDeclaredMethod(getMethodName, null);
//调用get方法获得被拷贝的对象的一个属性值
Object gresult = gmethod.invoke(obj, null);
//获得set方法
Method smethod = class1.getDeclaredMethod(setMethodName, new Class[]{gmethod.getReturnType()});
smethod.invoke(instance, new Object[]{gresult});
}
return instance;
}
反射方式访问私有属性
public static void main(String[] args) throws Exception {
Class<?> class1 = Class.forName("cn.tx.reflect.Person");
//获得构造器
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
//根据类的默认构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{});
//根据方法名字来获得属性对象
Field field = class1.getDeclaredField("name");
//破坏掉私有属性
field.setAccessible(true);
field.set(instance, "张三");
//获得属性的类型
Class<?> type = field.getType();
System.out.println(type);
}
反射方式访问私有方法
public static void main(String[] args) throws Exception {
Class<?> class1 = Class.forName("cn.tx.reflect.Person");
//获得构造器
Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
//根据类的默认构造器来获得一个对象
Object instance = constructor.newInstance(new Object[]{});
Method method = class1.getDeclaredMethod("setName", new Class[]{String.class});
Object invoke = method.invoke(instance, new Object[]{"张三"});
//Method mget = class1.getDeclaredMethod("getName", new Class[]{});
Method mget = class1.getDeclaredMethod("getName", null);
Object invoke2 = mget.invoke(instance, new Object[]{});
Method method2 = class1.getDeclaredMethod("printInfo", null);
//破坏私有方法,让我们能调用
method2.setAccessible(true);
Object invoke3 = method2.invoke(null, null);
}