Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
//User类,子类
User user = new User();
//Parent类,User的父类
Parent parent = new Parent();
//获取类的类型Class的三种方式
Class z = User.class;
Class c = new User().getClass();
//动态获取
Class l = Class.forName("com.zqq.test.User");
字段操作 Field
Class c = user.getClass();
//获取当前字段类所有,不包含父类字段,返回Field数组
c.getDeclaredFields();
//获取当前类所有public修饰的字段,含父类public修饰的字段,返回Field数组
c.getFields();
//根据名称获取当前类字段 不包括父类,返回Field对象
c.getDeclaredField("age");
//根据字段名称获取public修饰的字段,包括父类字段,返回Field对象
c.getField("pubName");
//是否可以通过放射访问该字段 可以 true 不可以 false
Field.isAccessible();
//设置成可以通过反射访问该字段
Field.setAccessible(true);
Demo
User user = new User();
user.setName("xiaoxiao");
user.setAge(18);
User user1 = new User();
System.out.println(user == user1);
System.out.println(user.getClass() == user1.getClass());
Class c = user.getClass();
//getDeclaredFields 获取当前字段类所有,不包含父类字段
for(Field f : c.getDeclaredFields()){
System.out.println(f.getName());
}
// c.getFields() 获取当前类所有public修饰的字段,含父类public修饰的字段
for(Field f : c.getFields()){
System.out.println(f.getName());
}
// c.getDeclaredField 根据名称获取当前类字段 不包括父类
Field field = c.getDeclaredField("age");
System.out.println("字段信息====:" + field.toString());
//c.getField(name) 根据字段名称获取public修饰的字段,包括父类字段
//System.out.println("本身私有字段====age:" + c.getField("age")); // 报错 java.lang.NoSuchFieldException
System.out.println("本身public字段pubAge======pubAge:" + c.getField("pubAge"));
System.out.println("父类public修饰字段===========pubName :" + c.getField("pubName"));
//获取字段的值
Field nameField = c.getDeclaredField("name");
System.out.println("是否可以通过反射访问该字段:" + nameField.isAccessible());
// isAccessible为false时不可以通过反射访问该字段,设置成true
nameField.setAccessible(true);
System.out.println("是否可以通过反射访问该字段:" + nameField.isAccessible());
Object name = nameField.get(user);
System.out.println("获取到字段的值为:" + name);
//设置字段的值
nameField.set(user,"大小小");
System.out.println(user.getName());
方法操作 Method
Class c = User.class;
//获取public修饰的方法(包括父类),传入方法名称
c.getMethod("say");
//获取所有public修饰的方法(包括父类)
c.getMethods();
//获取当前类的方法(所有作用域)(不包括父类),传入方法名称
c.getDeclaredMethod("getName");
//获取当前类所有方法(不包括父类)
c.getDeclaredMethods();
//返回方法返回值类型
Method.getReturnType();
//返回方法参数类型
Method.getParameterTypes();
//返回方法的修饰符,public、private ...
Modifier.toString(Method.getModifiers());
//通过反射调用方法,传入对象的实例,静态方法实例传null
Method.invoke(new User(),'参数,没有不填');
//设置可以通过反射访问该方法
method.setAccessible(true);
Demo
Class c = User.class;
//获取public的方法(包括父类)
Method method = c.getMethod("say");
//获取所有public的方法包括父类
Method[] methods = c.getMethods();
//获取当前类的方法(所有作用域)(不包括父类)
method = c.getDeclaredMethod("getName");
//获取当前类所有方法(不包括父类)
methods = c.getDeclaredMethods();
System.out.println(method.toString());
System.out.println("方法名称:" + method.getName());
System.out.println("方法返回值类型:" + method.getReturnType());
System.out.println("方法的参数类型:" + method.getParameterTypes());
System.out.println("方法的修饰符:" + Modifier.toString(method.getModifiers()));
//调用方法
method = c.getMethod("say");
//传入对象的实例
method.invoke(new User());
//调用静态方法,实例传null
Method statciMethon = c.getMethod("sayStatic");
statciMethon.invoke(null);
//调用private修饰的方法,需要设置 Method.setAccessible(true),否则会报错 java.lang.NoSuchMethodException
method = c.getDeclaredMethod("sayPrivate");
method.setAccessible(true);
method.invoke(new User());
构造方法
//创建对象 , newInstance只能调用public修饰的无参构造方法,有参或者不是public修饰则创建不了对象
User user = User.class.newInstance();
user.setName("zqq");
System.out.println(user.toString());
//Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例,可以调用任意构造方法
Constructor constructor = User.class.getDeclaredConstructor(String.class);
User u = (User) constructor.newInstance("zqqqqq");
System.out.println(u.toString());
继承关系 ps:看框架源码的时候可以先获取对象的继承关系
Class c = User.class;
//获取父类的Class,返回对象,java单继承
c.getSuperclass();
//获取实现的接口,返回数组,java多实现
c.getInterfaces();
//isAssignableFrom() 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true
Parent.Class.isAssignableFrom(c);
Demo
//获取类类型的方式, 类类型 就是类的类型
Class z = User.class;
Class c = new User().getClass();
//传入类的完整类名
Class l = Class.forName("com.zqq.test.User");
//这三种方式获取的Class都是同一个Class,因为JVM对每个加载的Class只创建一个Class实例来表示它的类型
System.out.println(z == c && c == l);
//获取父类的Class ,阅读源码的时候可以无限往上看看都继承了哪个父类,继承的接口也一样
Class p = l.getSuperclass();
System.out.println("父类class:" + p);
//获取实现的接口
Class[] interfaces = l.getInterfaces();
for(Class inter : interfaces){
System.out.println(inter.toString());
}
// instanceof 判断某个实例是否是某个类型
System.out.println(new User() instanceof com.zqq.test.User);
// isAssignableFrom() 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true
System.out.println(User.class.isAssignableFrom(Parent.class));
System.out.println(Parent.class.isAssignableFrom(User.class));
【往期精彩视频】