java-反射

class

class本身是一种数据类型,class/interface的数据类型是Class,JVM为每个加载的类、接口创建唯一的Class实例。

Class实例包含该class的所有信息,通过Class实例获取class信息的方法称为反射(Reflection)。反射的目的是当获得某个Object实例时,我们可以获得该Object的class信息。

获取一个class的Class实例:

Class cls = String.class;
Class cls = "str".getClass();
Class cls = Class.forName("java.lang.String");

Class实例在JVM中是唯一的

  • == 比较两个实例(只能精确的判断数据类型,不能做子类的比较)

      Class cls1 = String.class;
      String s = "Hello";
      Class cls2 = s.getClass();
      Class cls3 = Class.forName("java.lang.String");
      
      boolean b1 = cls1==cls2;  //true
      boolean b1 = cls1==cls3;  //true
    
  • 使用instanceof(不但匹配当前类型,还匹配当前类型的子类)

      Integer n = new Integer(123);
      boolean b3 = n instanceof Integer; //true
      boolean b4 = n instanceof Number;  //true
      //Integer是Number的子类
      boolean b1 = n.getClass() == Integer.class; //true
      boolean b2 = n.getClass() == Number.class;  //false
    
  • 通常情况下我们使用instanceof进行比较。

从Class实例获取class信息:

  • getName()

  • getSimpleName()

  • getPackage()

      Class cls = String.class;
      String name =  cls.getName();				//"java.lang.String"
      String sname = cls.getSimpleName();			//"String"
      String pkg = cls.getPackage().getName();	//"java.lang"
    

从Class实例判断class类型:

  • isInterface()

  • isEnum()

  • isArray()

  • isPrimitive()

      Runnable.class.isInterface(); 	//true
      java.time.Month.class.isEnum(); //true
      String [].class.isArray();		//true
      int.class.isprimitive();		//true
    

创建class实例:

  • cls.newInstance()

      Class cls = String.class;
      //new String();
      String s = (String)cs.newInstance();
      这里的局限在于,只能调用String类的public、无参的默认构造方法,带参数的构造方法我们没有办法调用。
    

JVM总是动态加载class,可以在运行期根据条件控制加载class。

  • 利用JVM动态加载class的特性,可以在运行期间跟据条件不同加载不同的实现类。

      //Commons logging优先使用Log4j:
      LogFactory factory;
      if(isClassPresent("org.apache.logging.log4j.LOgger")){
      	factory =  createLog4j();
      }else{
      	factory = createJDKLog();
      }
    
      boolean isClassPresent(String name){
      	try{
      		Class.forName(name);
      		return true;
      	}catch(Exception e){
      		return false;
      	}
      }
    

访问字段 Field对象封装了字段的所有信息

通过Class实例获取字段field信息:

  • getField(name):获取某个public的field(包括父类)

  • getDeclaredField(name):获取当前类的某个field(不包括父类)

  • getFields():获取所有public的field(包括父类)

  • getDeclaredFields():获取当前类的所有field(不包括父类)

      Integer n = new Integer(123);
      Class cls = n.getClass();
      Field []fs = cls.getFields();
      for(Field f: fs){
    
      	f.getName();
      	f.getType();
      	f.getModeifiers();
      }
    

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

  • getName()
  • getType()
  • getModifiers() 获得修饰符(private、public、protect)

获取和设置field的值:

  • get(Object obj)

  • set(Object, Object)设置一个实例的该字段的值

      Integer n = new Integer(234);
      Class cls = n.getClass();
      Field f = cls.getDeclaredField("value");
      f.get(n);  //234   相当于n.value
      f.set(n,123);   //相当于n.value=456;
    

通过反射访问Field需要通过SecurityManager设置的规则。

  • SecurityManager的规则阻止对该Field设置accessible:

      例如,规则应用于所有java和javax开头的package的类
    

通过设置setAccessible(true)来访问非public字段(可能会失败)

f.setAccessible(true);

调用方法 Method

通过Class实例获取方法Method信息:

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

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

  • getName()
  • getReturnType()
  • getParameterTypes()
  • getModifiers()

调用Method:

  • Object invoke(Object obj, Object... args)

通过设置setAccessible(true)来访问非public方法。

反射调用Method也遵守多态的规则。


调用构造方法 Constructor

调用public无参数构造方法:

  • Class.newInstance()

通过Class实例获取Constructor信息:

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

通过Constructor实例可以创建一个实例对象:

  • newInstance(Object… parameters)

通过设置setAccessible(true)来访问非public构造方法。


获取继承关系

获取父类的Class:

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

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

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

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

  • bool isAssignableFrom(Class)

      Integer.isAssignableFrom(Number.class);		//false
      Number.isAssignableFrom(Integer.class);		//true
    
posted @ 2019-09-08 01:27  马小八  阅读(143)  评论(0编辑  收藏  举报