反射
概念:在Java虚拟机中,加载类之后,会生成Class(字节码)文件,该对象包括了类的完整结构信息,通过这个Class对象可以看到类的所有结构,称之反射
作用:Java反射是在动态的获取类, 类属性, 类方法, 类构造器等内部一些类的信息
1.获取Class对象
那我们首先要获取Class对象
将类编译成字节码文件
方式一:
//第一张创建方式 类
Class<Person> personClass = Person.class;
方式二:
使用了forName()方法
//第二种创建方式
Class<?> aClass = Class.forName("com.kz.c_reflect.Person");
方式三:
//第三种方式
Class<? extends Person> aClass1 = new Person().getClass();
2.获取Constructor对象
获取Class对象之后我们可以获取字节码文件下的构造器
方式一:
-
Constructor<?>[] getConstructors()
返回包含一个数组Constructor
对象反射由此表示的类的所有公共构造类
对象。
//通过获取的字节码文件获取下面的构造方法 方法 属性等
//获取构造器
Class<Dog> dogClass = Dog.class;
//获取所有的public构造器 需要遍历
System.out.println(dogClass.getConstructors());
方式二:
-
Constructor<T>
getConstructor(类<?>... parameterTypes)
返回一个Constructor
对象,该对象反映Constructor
对象表示的类的指定的公共类
函数。
// 获取空参构造器
System.out.println(dogClass.getConstructor());
方式三:
-
Constructor<?>[]
getDeclaredConstructors()
返回一个反映Constructor
对象表示的类声明的所有Constructor
对象的数组类
。
//获取所有的构造器
Constructor<?>[] dcsc = dogClass.getDeclaredConstructors();
for (Constructor<?> constructor : dcsc) {
System.out.println(constructor);
}
方式四:
-
`Constructor getDeclaredConstructor(类<?>... parameterTypes)
返回一个Constructor
对象,该对象反映Constructor
对象表示的类或接口的指定类
函数。
//获取一个除public之外的构造器
System.out.println(dogClass.getDeclaredConstructor(int.class));
当我们获取了构造器之后我们就可以通过Class对象获取的构造器来实例化对象 方法:newInstance();
//Class对象
Class<Dog> dogClass = Dog.class;
//获取构造器
Constructor<Dog> declaredConstructor = dogClass.getDeclaredConstructor(int.class);
//实例化对象
System.out.println(declaredConstructor.newInstance(20));
3.获取Method对象
获取Class对象之后我们可以获取字节码文件下的方法
方式一:
-
方法[]
getMethods()
返回包含一个数组方法
对象反射由此表示的类或接口的所有公共方法类
对象,包括那些由类或接口和那些从超类和超接口继承的声明。
Class<Dog2> dog2Class = Dog2.class;
//获取所有公开的方法包括父类的公开方法
for (Method method : dog2Class.getMethods()) {
System.out.println(method);
}
方式二:
-
方法 getMethod(String name, 类<?>... parameterTypes)
返回一个方法
对象,它反映此表示的类或接口的指定公共成员方法类
对象。
//获取一个公开的方法
System.out.println(dog2Class.getMethod("eat"));
方式三:
-
方法[]
getDeclaredMethods()
返回包含一个数组方法
对象反射的类或接口的所有声明的方法,通过此表示类
对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法
//获取所有方法 不包括父类
for (Method declaredMethod : dog2Class.getDeclaredMethods()) {
System.out.println(declaredMethod);
}
方式四:
-
方法 getDeclaredMethod(String name, 类<?>... parameterTypes)
返回一个方法
对象,它反映此表示的类或接口的指定声明的方法类
对象
//获取除public声明外的一个方法
System.out.println(dog2Class.getDeclaredMethod("sleep"));
可以通过上面方式获取方法 我们获取方法之后,需要用方法.invokee(Object obj, Object… args)来调用,第一个参数是Class对象,后面均为方法的形参
//首先需要声明一个类对象
Dog2 dog2 = Dog2.class.getDeclaredConstructor().newInstance();
Method sleep = dog2Class.getDeclaredMethod("sleep");
//通过方法调用 第一个参数是类对象 第二个是参数
//私有方法 不能执行
//暴力反射
sleep.setAccessible(true);
sleep.invoke(dog2);
不管是私有的方法 构造器 属性 都不可用 除非使用暴力反射才可setAccessible(true),才可使用private修饰
4:获取Field对象
获取Class对象之后我们可以获取字节码文件下的属性
方式一:
-
Field[]
getFields()
返回包含一个数组Field
对象反射由此表示的类或接口的所有可访问的公共字段类
对象。
Class<Dog3> dog3Class = Dog3.class;
//获取所有公有属性
for (Field field : dog3Class.getFields()) {
System.out.println(field);
}
方式二:
-
Field
getField(String name)
返回一个Field
对象,它反映此表示的类或接口的指定公共成员字段类
对象。
//获取一个公有属性
System.out.println(dog3Class.getField("name"));
方式三:
-
Field[]
getDeclaredFields()
返回的数组Field
对象反映此表示的类或接口声明的所有字段类
对象。
//获取所有属性
for (Field declaredField : dog3Class.getDeclaredFields()) {
System.out.println(declaredField);
}
方式四:
-
`Field getDeclaredField(String name)
返回一个Field
对象,它反映此表示的类或接口的指定已声明字段类
对象。
//获取一个除public修饰外的属性
System.out.println(dog3Class.getDeclaredField("age"));
那我们如何给属性赋值?set()方法
//私有属性 需要暴力反射
age.setAccessible(true);
//第一个值是对象 第二个是值
age.set(dog3,18);
System.out.println(dog3);