反射
概述
是在运行状态中,获取任意一个类的结构,再由此结构创建对象,获取里面的属性和方法
可以粗略理解为顺藤(根据对象或类的全名)摸瓜(类对象,即Class对象)
Class对象
在Java中,每一个字节码文件,被加载到内存后,都存在一个对应的Class类型的对象
可以把类的.Java文件理解成脑海中的模板,而类的class文件则是一个模板实体,这些class文件被加载到内存后被作为Class对象存放在内存中。
得到Class的几种方式
public static void main(String[] args) throws ClassNotFoundException {
//第一种方式,通过 类名.class 加载(注意,如果以下代码和要获取的类不在一个包,则要使用类的全名获取)
Class<Person> c1 = Person.class;
//第二种方式,通过 类对象获取类的信息
Person person = new Person();
Class<Person> c2 = (Class<Person>) person.getClass();
//第三种方式,通过 类名(字符串)获取
Class<?> c3 = Class.forName("Person");//该方法会抛出ClassNotFoundException异常
}
注意:
只有第三种方式在没有类文件的时候,编译也不会报错
获取Constructor
-
通过指定的参数类型, 获取指定的单个构造方法
getConstructor(参数类型的class对象数组)
例如:
构造方法如下: Person(String name,int age)
得到这个构造方法的代码如下:
Constructor c = p.getClass().getConstructor(String.class,int.class); -
获取构造方法数组
getConstructors(); -
获取所有权限的单个构造方法
getDeclaredConstructor(参数类型的class对象数组) -
获取所有权限的构造方法数组
getDeclaredConstructors();
##获取方法
public static void main(String[] args) throws Exception {
//1.加载类,获得Class对象
Class c1 = Class.forName("com.mytest.Person");
//2.获取方法
//第一个参数为 方法名
//后面的参数为 方法的入参类型
Method setName = c1.getMethod("setName", String.class);
Method getName = c1.getMethod("getName");
//3.创建对象
Person o = (Person)c1.newInstance();
//4.调用方法
//第一个参数为 调用该方法的对象
//后面的参数为 方法的入参
Object invoke1 = setName.invoke(o, "张三");//如果没有返回值的方法执行,得到的就是null
Object invoke2 = getName.invoke(o);
System.out.println(invoke2);
}
忽略权限
在使用反射获取属性和方法的时候,可以通过加上Declared获取被保护的目标
如:
getMethod(); //获取方法(无法获取private修饰的,否则会报NoSuchMethodException)
getDeclaredMethod(); //获取方法 (可以过去private修饰的方法,但是依旧不能使用,需要配合 setAccessible方法)
setAccessible (boolean flag) //如果flag为true 则表示忽略调用者的访问权限检查
例:
Method getName = c1.getDeclaredMethod("getName");
getName.setAccessible(true);