一、概念
反射:在程序运行期间,可以动态的创建类的对象、获取类中的成员,对类中的成员进行调用
如果要知道一个类的内部结构,就必须先获取这个类的二进制字节码文件对象
二进制字节码文件对象也称为类对象
类的对象:基于某个类通过new关键字创建出来的一个实例
类对象:类在加载后的产物,它里面封装一个类所包含的所有信息,有:类名、成员变量、成员方法、构造函数、继承的父类、实现的接口
注:任何一个类在加载到内存后所得到的类对象是唯一的
二、获取类对象
// 1.通过对象的getClass()方法
Student s = new Student();
Class c1 = s.getClass();
// 2.通过类的静态属性class
Class c2 = Student.class;
// 3.通过Class的静态方法forName(String s),参数:全限定类名
Class c3 = Class.forName("com.qf.test.Student");
三、类对象的常用方法
1.getName(): 获取全类名,形如: com.qf.test1.Student
2.getSimpleName(): 获取类名,形如: Student
3.getSuperclass(): 获取父类的全类名
4.getInterfaces(): 获取该类实现的所有接口,返回的是Class数组
5.getPackage(): 获取该类的包,返回的是Package对象
6.newInstance(): 创建指定类的对象,注:这个方法只能通过类中的无参构造函数创建对象,如果没有这个构造函数会发生InstantitionException、NoSuchMethodException
四、获取构造函数,创建对象
1.getConstructors(): 获取类中所有public的构造函数 2.getDeclaredConstructors(): 获取类中的所有构造函数 3.getConstructor(Class...c): 获取public构造函数中指定参数的构造函数 4.getDeclaredConstructor(Class...c): 获取指定参数的构造函数 // 如果指定构造函数不存在,会发生NoSuchMethodExceptionprivate Work(Integer i){ System.out.println("私有构造函数:"+ i); } // 注:参数是基本类型和包装类是不同的,例如:在获取这个构造函数对象时,参数必须是Integer.class,不能是int.class
通过构造函数对象创建实例:
newInstance(Object...o)注:
- 创建对象时的实参与获取到的构造函数对象的形参不同,会发生
IllegalArgumentException非法参数异常,原因:1. wrong number of arguments 2.argument type mismatch- 通过私有构造函数创建对象,需要在创建对象之前调用
setAccessible(true)表示允许访问私有内容,否则会发生IllegalAccessException。这种做法不推荐,因为它破坏了封装性。
五、获取成员变量,并赋值
1.getFields(): 获取类中所有public的成员变量
2.getDeclaredFields(): 获取类中的所有成员变量
3.getField(String name): 获取指定的public的成员变量
4.getDeclaredField(String name): 获取指定的成员变量
// 如果指定的成员变量不存在会发生NoSuchFieldException
通过成员变量对象对变量进行赋值和获取:
- 赋值:
set(Object o,Object value)- 获取:
get(Object o)注:
- 赋值的类型与变量的类型不一致会发生
IllegalArgumentException- 为私有成员变量赋值或者获取私有变量的值,需要在赋值、获取之前调用
setAccessible(true)表示允许访问私有内容,否则会发生IllegalAccessException。这种做法不推荐,因为它破坏了封装性。
六、获取成员方法,并调用
1.getMethods(): 获取本类和父类中的所有public的成员方法 2.getDeclaredMethods(): 获取本类中的所有成员方法 3.getMethod(String name,Class...c): 获取类中指定的Public方法 4.getDeclaredMethod(String name,Class...c): 获取类中的指定方法调用方法:
invoke(Object o,Object...args)注:
- 调用方法时,实参的个数类型必须与形参一致,否则会发生
IllegalArgumentException非法参数异常,原因:1. wrong number of arguments 2.argument type mismatch- 调用私有方法,需要在调用之前,使用
setAccessible(true)表示允许访问私有内容,否则会发生IllegalAccessException。这种做法不推荐,因为它破坏了封装性。七、案例
// 泛型擦除 Class c = ArrayList.class; Method m = c.getMethod("add",Object.class); ArrayList<String> list = new ArrayList<>(); m.invoke(list,1); m.invoke(list,"abc"); m.invoke(list,3.3); m.invoke(list,false); m.invoke(list,new Stu()); System.out.println(list);