反射
基本概念
“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”,如Python,Ruby是动态语言;显然C++,Java,C#不是动态语言,但是JAVA有着一个非常突出的动态相关机制:Reflection。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
如何获取反射的源头
Class类 的对象可以表示一个正在运行的java类或者接口
Class对象就是反射的源头
一个类在java到内存中后就存在一个表示该类型的Class对象,Class对象是唯一的
Class对象中存着这个类的所有内容(成员,构造器…)
如果能够获取到一个类的Class对象,就能够做任何事情,所有Class类的对象作为反射的源头
如何获取反射的源头:
1.类名.class
2.对象.getClass()
3.Class.forName(“包名+类名”) 推荐
package reflect01;
import java.lang.reflect.Modifier;
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException {
//1.类名.class
Class cls1=String.class;
System.out.println(cls1);
//2.对象.getClass();
Class cls2="哈哈".getClass();
System.out.println(cls1==cls2);
//3.Class.forName("包名+类名");
Class cls3=Class.forName("java.lang.Object");
System.out.println(cls3);
//根据反射的方式获取到这个类型的父类
Class cls4=cls1.getSuperclass();
System.out.println(cls4);
System.out.println(cls3==cls4);
//获取基本数据类型的class对象
//根据包装类型,TYPE属性获取对应数据类型的Class对象
Class cls5=int.class;
Class cls6=Integer.class;
Class cls7=Integer.TYPE;
System.out.println(cls5==cls6);//int.class 不等于 Integer.class
System.out.println(cls5==cls7);//int.class 等于 Integer.class
//getName()
System.out.println(cls1.getName());
//getMOdifiers() 报错 待会造
System.out.println(cls1.getModifiers());
System.out.println(Modifier.toString(cls1.getModifiers()));//public final
}
}
Java的反射机制,可以实现的功能
- 在运行时判断任意一个对象所属的类;
- 在运行时判断任意一个对象所属的类;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法
- 生成动态代理
我们主要学习如何通过反射获取构造函数、给变量赋值以及调用方法。
预热:反射常用的方法
package reflect01;
public class Modifier {
public static void main(String[] args) throws ClassNotFoundException {
//1.类名.class
Class cls1=String.class;
System.out.println(cls1);
//2.对象.getClass();
Class cls2="哈哈".getClass();
System.out.println(cls1==cls2);
//3.Class.forName("包名+类名");
Class cls3=Class.forName("java.lang.Object");
System.out.println(cls3);
//根据反射的方式获取到这个类型的父类
Class cls4=cls1.getSuperclass();
System.out.println(cls4);
System.out.println(cls3==cls4);
//获取基本数据类型的class对象
//根据包装类型,TYPE属性获取对应数据类型的Class对象
Class cls5=int.class;
Class cls6=Integer.class;
Class cls7=Integer.TYPE;
System.out.println(cls5==cls6);
System.out.println(cls5==cls7);
//getName()
System.out.println(cls1.getName());
//getMOdifiers() 报错 待会造
System.out.println(cls1.getModifiers());
System.out.println(Modifier());
}
}
一、反射之获取构造函数
用法示例
/*
* 通过反射获取构造器,创建对象
* 1.
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
2.
Constructor<?>[] getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法
3.
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
4.
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
创建对象:
通过指定的构造器创建对象,如果私有,放开权限
通过一个类的Class对象的newInstance方法创建这个类的实例,默认调用空构造
*
*/
public static void testConstruction(Class cls) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
//1.获取构造器,通过 类对象.getConstructors,根据类对象的方法获取构造器
Constructor[] arr=cls.getConstructors();//所有的公共的
System.out.println(Arrays.toString(arr));
//根据构造器的newInstance(实参)
PersonOne p=(PersonOne) arr[0].newInstance("张三",15,180.52);
System.out.println(p);
//获取指定类型的构造器
Constructor<PersonOne> con=cls.getDeclaredConstructor(String.class);
//放开构造器的权限
con.setAccessible(true);
PersonOne p2=con.newInstance("lisi");//报错
con.setAccessible(false);
//默认调用空构造
PersonOne p3=(PersonOne) cls.newInstance();
System.out.println(p3);
}
调用
public class Demo03 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
//传入一个类对象,这个对象是Person.class
System.out.println("构造器测试");
testConstruction(PersonOne.class);
}
}
二、反射之使用修改属性
用法示例
//可以在形参加上 泛型
public static void testField(Class<PersonOne> cls) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException{
/*
* Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field[] getFields()
Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
Field[] getDeclaredFields()
获取属性的值: Object get(Object obj)
设置属性的值: void set(Object obj, Object value)
*
*/
//1.获取一个Field对象,这个对象是用来修改属性的
Field name=cls.getDeclaredField("name");//获取 方法中 公共的访问成员接口并封装成一个Field对象
System.out.println(name);//打印的是 包名+类名+属性名
//2.给变量赋值
//2.1通过获取构造器,创建对象
Constructor<PersonOne> personOne=cls.getConstructor(String.class,int.class,Double.TYPE);
//2.2通过构造器(构造器),创建对象
PersonOne personTwo=personOne.newInstance("小黄",20,190.0);
//2.3直接通过对象修改变量
System.out.println("修改之前");
name.setAccessible(true);
System.out.println(name.get(personTwo));//由于name返回的这个字段是私有的,无法直接访问和修改
personTwo.setName("大黄");
System.out.println("修改之前");
System.out.println(name.get(personTwo));
name.setAccessible(false);
}
调用
public class Demo03 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
System.out.println("属性测试");
testField(PersonOne.class);
}
}
三、反射之调用方法
用法示例
//测试方法,通过对象调用成员方法
public static void testMethod(Class<PersonOne> cls) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, IllegalArgumentException, InvocationTargetException{
/*
* 通过反射获取方法,调用方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method[] getDeclaredMethods()
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method[] getMethods()
执行方法:
Object invoke(Object obj, Object... args)
参数1: 调用方法的对象
参数2: 调用方法的实参
返回值: 调用方法的返回值
*/
//1.获取所有方法
Method[] arr=cls.getMethods();
for(Method m:arr){
System.out.println(m);
}
//2.创建对象,直接通过类对象.newInstance.默认空参
PersonOne p=cls.newInstance();
//3.返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field field=cls.getDeclaredField("name");
field.setAccessible(true);
System.out.println(field.get(p));
field.setAccessible(false);
//4.调用方法,传入的对象是 filed
System.out.println(arr[8].invoke(p,"位置"));
}
调用
public class Demo03 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
System.out.println("方法测试");
testMethod(PersonOne.class);
}
}