Java反射

Class
  简介
  总结1
  获取Class实例
  获取class信息
  判断class类型
  创建class实例
  总结
访问字段
  field
  Field对象
  SecurityManager
  总结
调用方法
  method
  Method对象
  SecurityManager
  多态
  总结
调用构造方法
  newInstance
  Constructor对象
  SecurityManager
  总结
获取继承关系
  getSuperclass()
  getInterfaces()
  isAssignableFrom()
  总结

Class

简介

class / interface的数据类型都是Class,每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来
在这里插入图片描述

JVM持有的每个Class实例都指向一个数据类型(class 或 interface)
在这里插入图片描述
一个Class实例包含了该class的完整信息
在这里插入图片描述

总结1
  • JVM为每个加载的class创建对应的Class实例,并在实例中保存该class的所有信息
  • 如果获取了某个Class实例,则可以获取到该实例对应的class的所有信息
  • 通过Class实例获取class信息的方法称为反射(Reflection)
获取Class实例
  • Type.class
Class cls = String.class;
  • getClass()
String s = "name";
Class cls = s.getClass();
  • Class.forName()
Class cls = Class.forName("java.lang.String");
获取class信息
  • getName()
Class cls = String.class;
Stirng fname = cls.getName(); // "java.lang.String"
  • getSimpleName()
String sname = cls.getSimpleName(); // "String"
  • getPackage()
String pkg = cls.getPackage().getName(); // "java.lang"
判断class类型
  • isInterface() 是否是接口
Runnable.class.isInterface();// true
  • isEnum() 是否是枚举
java.time.Month.class.isEnum(); // true
  • isArray() 是否是数组
String[].class.isArray();	// true
  • isPrimitive() 是否是基本类型
int.class.isPrimitive();	// true
创建class实例
  • newInstance()
Class cls = String.class;
String s = (String)cls.newInstance();	// new String()
总结
  • JVM为每个加载的class创建对应的Class实例来保存class的所有信息
  • 获取一个class对应的Class实例后,就可以获取该class的所有信息
  • 通过Class实例获取class信息的方法称为反射(Reflection)
  • JVM总是动态加载class,可以在运行期根据条件控制加载class

访问字段

field

通过Class实例获取field信息:

  • getField(name) 获取某个public的field(包括父类)
  • getDeclaredField(name) 获取当前类的某个field(不包括父类)
  • getFields() 获取所有的public的field(包括父类)
  • getDeclaredFields() 获取当前类的所有field(不包括父类)
Field对象

Field对象包含一个field的所有信息

  • getName() 名称
  • getType() 类型
  • getModifiers() 修饰符
  • get(Object) 获取一个实例的该字段的值
  • set(Object, Object) 设置一个实例的该字段的值
SecurityManager

setAccessible(true)可以允许访问非public字段,但是可能会失败:

  • 定义了SecurityManager
  • SecurityManager的规则组织对该Field设置accessible:例如,规则应用于所有java和javax开头的package的类
总结
  • Field对象封装了字段的所有信息
  • 通过Class实例的方法可以获取Field实例:getField / getFields / getDeclaredField / getDeclaredFields
  • 通过Field实例可以获取字段信息:getName / getType / getModifiers
  • 通过Field实例可以读取或设置某个对象的字段:get(Object instance) / set(Object instance, Object fieldValue)
  • 通过设置setAccessible(true)来访问非public字段

调用方法

method

通过Class实例获取method信息

  • getMethod(name, Class…):获取某个public的method(包括父类)
  • getDeclaredMethod(name, Class…):获取当前类的某个method(不包括父类)
  • getMethods():获取所有public的method(包括父类)
  • getDeclaredMethods():获取当前类的所有method(不包括父类)
Method对象

Method对象包含一个method的所有信息

  • getName() 方法名称
  • getReturnType()
  • getParameterType()
  • getModifiers()

方法调用

  • 调用无参数的Method :Object invoke(Object obj)
Integer n = new Integer(123);
Class cls = n.getClass();
Method m = cls.getMethod("toString");
String s = (String)m.invoke(n); 
// 相当于 String s = n.toString()
  • 调用带参数的Method :Object invoke(Object obj, Object…args)
Integer n = new Integer(123);
Class cls = n.getClass();
Method m = cls.getMethod("compareTo", Integer.class);
int r = (Integer)m.invoke(n, 456); 
// 相当于 int r = n.compareTo(456)
SecurityManager

setAccessible(true)可以允许访问非public方法,但是可能会失败:

  • 定义了SecurityManager
  • SecurityManager的规则组织对该Method设置accessible:例如,规则应用于所有java和javax开头的package的类
多态

从父类的Class实例获取的Method,作用于子类实例时:

  • 实际调用方法是子类覆写的方法
  • 保证了多态的正确性
class Person {
  	public void hello() {
      	System.out.println("Person:hello");
    }
}
class Student extends Person {
  	public void hello() {
      	System.out.println("Student:hello");
    }
}
Method m = Person.class.getMethod("hello");
m.invoke(new Student());
// Student:hello
总结
  • Method对象封装了方法的所有信息
  • 通过Class实例的方法可以获取Method实例:getMethod / getMethods / getDeclaredMethod / getDeclaredMethods
  • 通过Method实例可以获取方法信息:getName / getReturnType / getParameterTypes / getModifiers
  • 通过Method实例可以调用某个对象的方法:Object invoke(Object instance, Object…parameters)
  • 通过设置setAccessible(true)来访问非public方法

调用构造方法

newInstance

Class.newInstance()只能调用public无参构造方法

Constructor对象

Constructor对象包含一个构造方法的所有信息,可以创建一个实例:

Class cls = Integer.class;
// Integer(int)
Constructor cons1 = cls.getConstructor(int.class);
Integer n1 = (Integer)cons1.newInstance(123);
//Integer(String)
Constructor cons2 = cls.getConstructor(String.class);
Integer n1 = (Integer)cons1.newInstance("123");

通过Class实例获取Constructor信息:(都是本类的,和父类无关)

  • getConstructor(Class…):获取某个public的Constructor
  • getDeclaredConstructor(Class…):获取某个Constructor
  • getConstructors():获取所有public的Constructor
  • getDeclaredConstructors():获取所有Constructor
SecurityManager

setAccessible(true)可以允许访问非public构造方法,但是可能会失败:

  • 定义了SecurityManager
  • SecurityManager的规则组织对该Constructor设置accessible:例如,规则应用于所有java和javax开头的package的类
总结
  • Constructor对象封装了构造方法的所有信息
  • 通过Class实例的方法可以获取Constructor实例:getConstructor / getConstructors / getDeclaredConstructor / getDeclaredConstructors
  • 通过Constructor实例可以创建一个实例对象:newInstance(Object…parameters)
  • 通过设置setAccessible(true)来访问非public构造方法

获取继承关系

getSuperclass()

获取父类的Class:

  • Class getSuperclass()
  • Object的父类是null
  • interface的父类是null
getInterfaces()

获取当前类直接实现的interface:

  • Class[] getInterfaces()
  • 不包括间接实现的interface
  • 没有interface的class返回空数组
  • interface返回继承的interface
isAssignableFrom()

判断一个向上转型是否成立:

  • bool isAssignableFrom()
// Integer i= 1;
// Number x = i是否成立
Number.class.isAssignableFrom(Integer.class); // true
总结
  • 通过Class对象可以获取继承关系:
    • getSuperclass()
    • getInterfaces()
  • 通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否正确
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章