前言
本篇为反射,反射技术,指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。
一、反射
通过反射技术不知可以创建对象,还可以对对象的成员变量进行更改或者查看,由于构造器、成员变量、成员方法都有可能是私有的,使用普通创建或调用是无法对私有方法或变量进行获取,而反射可以。
1.获取字节码对象
反射获取的是类下信息,即字节码对象,使用Class就可以获取到,由3种方法可以获取
我们先定义一个Person类:
public class Person {
private String name;
private int age;
private String gender;
public Person(){
}
private Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
private void eat(String str){
System.out.println(name+"和"+str+"一起吃饭.");
}
}
因为后面不使用get和set方法,所以省略了。
首先可以通过类直接调用Class方法:
//第一种方法直接通过方法名调用class方法
Class<Person> pc = Person.class;
//第二种可以通过Class.forName()的方式进行获取,括号内需要填写全类名
Class<?> aClass = Class.forName("cn.reflex.demo1.Test1");
//第三种需要先创建对象,通过调用对象的getClass方法来获取
Person person=new Person();
Class<? extends Person> aClass1 = person.getClass();
获取得到字节码文件后就可以对类进行操作
二、获取构造器
获取构造器可以使用getConstructor()来获取,括号内若不填写内容,就是无参构造器,若有参,则需要传入参数。如果构造器是私有的,则可以使用getDeclaredConstructor(),私有需要setAccessible(true);来进行暴力反射,代码如下:
//获取构造器
public class Test1 {
public static void main(String[] args) throws Exception {
//将文件转化为字节码对象
Class<Person> pc = Person.class;
//创建构造器,私有用getDeclaredConstructor,非私有用getConstructor
Constructor<Person> personConstructor = pc.getDeclaredConstructor(String.class,int.class,String.class);
//暴力反射
personConstructor.setAccessible(true);
//通过构造器创建实例对象
Person person = personConstructor.newInstance("张三",18,"男");
System.out.println(person);
}
}
三、获取成员变量
获取成员变量与构造器欸四,但获取成员变量关键字为getDeclaredField,因为成员变量一般都是私有状态,则一般使用getDeclaredField和setAccessible(true);进行暴力反射。
代码如下:
//获取成员变量
public class Test2 {
public static void main(String[] args) throws Exception {
//创建对象
Person person=new Person();
//获取字节码文件
Class<Person> pc = Person.class;
//获取成员变量,因为成员变量一般为私有,可直接使用getDeclaredField方法提取
Field personName = pc.getDeclaredField("name");
Field personAge = pc.getDeclaredField("age");
Field personGender = pc.getDeclaredField("gender");
//私有成员变量需要setAccessible暴力反射.
personName.setAccessible(true);
personAge.setAccessible(true);
personGender.setAccessible(true);
//get可以获取数据,需要传入成员对象,set可以修改数据,需要传入成员对象和修改后的值
personName.set(person,"张三");
System.out.println(personName.get(person));
}
}
四、获取成员方法
获取方法的方式一样,方法名为getDeclaredMethod或getMethod,如果要获取的方法是私有的,则使用getDeclaredMethod,共有则用getMethod。
代码如下:
public class Test3 {
public static void main(String[] args) throws Exception {
//创建对象
Person person = new Person();
//获取字节码队形
Class<? extends Person> aClass = person.getClass();
/*
获取类的某个方法,私有可以使用getDeclaredMethod且需要setAccessible暴力反射
公有的可直接使用getMethod
需要传入方法名和参数类型列表
*/
Method eat = aClass.getDeclaredMethod("eat", String.class);
eat.setAccessible(true);
//可通过invoke直接调用方法,需要传入调用的对象名,和参数列表.
eat.invoke(person, "李四");
}
}
这样就可以对成员内的方法或变量进行操作。
总结
本篇简单介绍了反射的基本创建和反射获取成员内的数据及方法。