反射
问题:开发工具Eclipse是如何知道类中有哪些方法?
答:通过反射技术对类进行了解剖,获得了里面所有的成员。
什么是反射
反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的所有成员。
主要操作:构造方法,成员方法,成员变量反射的前提条件
- 要先获得类的Class对象。
- 该Class对象时通过类的字节码文件创建出来的。
反射在实际开发中使用
- 开发集成开发环境(IDE)。
- 学习各大框架(Spring,Struts,Hibernate),开发框架
反射需要知道的对象
- Constructor:构造方法类,每一个构造方法都是一个Constructor类的对象。
- Method:成员方法类,每一个成员方法都是一个Method类的对象。
Field:成员变量类,每一个成员变量都是一个Field类的对象
instance:实例,就是对象
- nvoke:调用,执行
反射操作
Person类
class Person{
private String name;
private String age;
public Person(String name, String age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
反射之操作构造方法
Class类与构造方法相关的方法
Constructor[] getConstructors()
- 获得所有的构造方法,返回数组
- 只包含非private修饰的
Constructor[] getDeclaredConstructors()
- 获得所有的构造方法,返回数组,包括private修饰的
Constructor getConstructor(Class… parameterTypes)
- 根据参数类型获得对应的构造方法对象
- 只能获得非private修饰的
public static void main(String[] args) throws Exception {
//获得Person的字节码class对象
Class c=Person.class;
//获得无参数构造器
Constructor con=c.getConstructor();
//通过无参数构造器创建对象
Object newInstance = con.newInstance();
System.out.println(newInstance);//Person [name=null, age=null]
//获得有参数构造器
Constructor con2=c.getConstructor(String.class,String.class);
//通过有参数构造器创建对象
Object newInstance2 = con2.newInstance("张三","20");
System.out.println(newInstance2);//Person [name=张三, age=20]
}
Constructor getDeclaredConstructor(Class… parameterTypes)
- 根据参数类型获得对应的构造方法对象,包括private修饰的
Constructor类的成员方法
- T newInstance(Object…initargs)
- 根据参数创建对象。
- T newInstance(Object…initargs)
暴力反射
- public void setAccessible(boolean flag)
- 设置是否取消权限检查,默认是false
- flag=true,表示取消权限检查
- flag=false,表示不取消权限检查
- public void setAccessible(boolean flag)
public static void main(String[] args) throws Exception {
//把前面的Person的有参数构造方法改为private
//获得Person的字节码class对象
Class c=Person.class;
//获得有参数构造器
Constructor con2=c.getDeclaredConstructor(String.class,String.class);
//暴力反射
/*
如果不改变权限会报出下面异常
java.lang.IllegalAccessException: class com.day_17.demo7.Person with modifiers "private"
*/
con2.setAccessible(true);
//通过有参数构造器创建对象
Object newInstance2 = con2.newInstance("张三","20");
System.out.println(newInstance2);//Person [name=张三, age=20]
}
Person类
class Person{
public void run(String a){
System.out.println(a);
}
}
反射之操作成员方法
Class类与成员方法相关的方法
public Method[] getMethods()
- 获得类所有的成员方法对象,包括父类的,返回数组
- 不包含private修饰
public Method[] getDeclaredMethods()
- 获得类所有的成员方法对象,不包括父类的,返回数组
- 包含private修饰
public Method getMethod(String name, Class… parameterTypes)
- 根据方法名和参数类型获得成员方法对象,不包含private
- name:方法的名字
- parameterTypes:根据方法的参数列表创建的Class对象(多少个数据类型就创建多少个Class)
public static void main(String[] args) throws Exception {
//获得Person字节码文件的Class对象
Class c=Person.class;
//获得Person的成员方法
Method m=c.getMethod("run",String.class);
//通过Class创建一个无参数构造的Person的对象
Object newInstance = c.newInstance();
//执行方法
m.invoke(newInstance,"hello");//hello
}
public Method getDeclaredMethod(String name, Class… parameterTypes)
- 根据方法名和参数类型获得成员方法对象,包括private的
Method类的成员方法
- Object invoke(Object obj, Object… args)
- 执行方法
- obj:调用的是哪个对象的方法。
- args:调用方法时要传递的参数
- 返回调用方法执行的结果
- Object invoke(Object obj, Object… args)
Class类快速创建对象的方法
- T newInstance()
- 前提:该类必须有一个public的无参数构造方法
- T newInstance()
public static void main(String[] args) throws Exception {
//把前面的run方法改为private
//获得Person字节码文件的Class对象
Class c=Person.class;
//获得Person的成员方法
Method m=c.getDeclaredMethod("run",String.class);
//暴力反射
/*
如果不改变权限会报出下面异常
java.lang.IllegalAccessException: class com.day_17.demo7.Person with modifiers "private"
*/
m.setAccessible(true);
//通过Class创建一个无参数构造的Person的对象
Object newInstance = c.newInstance();
//执行方法
m.invoke(newInstance,"hello");//hello
}
Person类
class Person{
public String name;
private String age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
反射之操作成员变量
Class类与成员变量相关的方法
Field[] getFields();
- 获得所有的成员变量,不包含private
Field[] getDeclarerdFields();
- 获得所有成员变量,包含private
Field getField(String name);
- 根据名称获得对应的成员变量对象,不包含private的
public static void main(String[] args) throws Exception {
//获得Person的字节码Class对象
Class c=Person.class;
//获得Person的public成员变量name
Field field=c.getField("name");
//通过Class对象创建一个无参数构造的Person对象
Object obj = c.newInstance();
//给对象的name赋值
field.set(obj, "张三");
System.out.println(obj);//Person [name=张三, age=0]
}
Field getDeclaredField(String name);
- 根据名称获得对应的成员变量对象,包含private的
Field类成员方
void setXxx(Xxx value);
- 给对应的成员变量设置为指定的值value
- xxx就是数据类型,
public void set(Object obj, Object value)
- 给指定对象obj对应的成员变量赋值为value
public static void main(String[] args) throws Exception {
//获得Person的字节码Class对象
Class c=Person.class;
//获得Person的private成员变量age
Field field=c.getDeclaredField("age");
//暴力反射
/*
如果不改变权限会报出下面异常
java.lang.IllegalAccessException: class com.day_17.demo7.Person with modifiers "private"
*/
field.setAccessible(true);
//通过Class对象创建一个无参数构造的Person对象
Object obj = c.newInstance();
//给对象的name赋值
field.setInt(obj, 20);
System.out.println(obj);//Person [name=null, age=20]
}
案例
1. ArrayList list = new ArrayList();
在这个泛型为 Integer 的 ArrayList 中存放一个 String 类型的对象。
泛型只是在编译器起作用,在字节码表中类型还是Object,运行的时候才变成泛型规定的类型
public class test2 {
public static void main(String[] args) throws Exception {
//创建一个ArrayList对象
ArrayList<Integer> list=new ArrayList<>();
//添加Integer元素
list.add(11);
list.add(2);
//获得list的class对象
Class c=list.getClass();
//通过class生成一个新的ArrayList对象
Object newInstance = c.newInstance();
//获得ArrayList的add方法
Method m=c.getMethod("add",Object.class);
//添加元素到newInstance集合中
m.invoke(newInstance, "newInstance");
//添加元素到list集合中
m.invoke(list, "list");
System.out.println(list);//[11, 2, list]
System.out.println(newInstance);//[newInstance]
}
}
案例二
/**
* 对象工厂类
* @author pkxing
*
*/
public class ObjectFactory {
/**
* 创建对象
* @param c 对象所属类的Class对象
* @param fileName 属性文件
* @return 创建好的对象
*/
public static <T> T createObject(Class<T> c,String fileName){
try {
// 创建属性集合
Properties pro = new Properties();
// 从文件中加载内容到集合中
FileInputStream fis = new FileInputStream(fileName);
pro.load(fis);
// 关闭流
fis.close();
// 快速创建对象
T obj = c.newInstance();
// 遍历集合
Set<String> names = pro.stringPropertyNames();
for (String name : names) {
// 获得值
String value = pro.getProperty(name);
// name:成员变量名
// System.out.println(name);
// 根据成员变量名获得对应的Field对象
Field f = c.getDeclaredField(name);
// 暴力反射
f.setAccessible(true);
// 获得成员变量的类型
Class typeClass = f.getType();
if(typeClass == int.class){ // 判断成员变量的数据类型是否是int类型
f.setInt(obj, Integer.parseInt(value));
} else if(typeClass == double.class){
f.setDouble(obj, Double.parseDouble(value));
} else {
// 给f对象的赋值
f.set(obj, value);
}
}
// 返回对象
return obj;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class ReflectDemo01 {
public static void main(String[] args) {
// 根据配置文件获得Book对象
Book book = ObjectFactory.createObject(Book.class,"book.properties");
// 根据配置文件获得Student对象
Student stu = ObjectFactory.createObject(Student.class,"student.properties");
System.out.println(book);//Book [id=2, name=金瓶梅, author=康醒, price=9.9]
System.out.println(stu);//Student [id=1, name=Sandy, gender=男, score=100]
}
}