反射(Reflection)详解

Reflection

产生原因:运行时获取、修改数据(类信息、成员数据信息)。

反射入口 java.lang.Class

Class对象分为基本类型(8种)、引用类型:(具体内容在文章末尾)

JVM会为每个对象(基础和引用类型)实例化一个java.lang.Class实例。通过这个Class对象,可以在运行时访问对象的属性和类信息、也可以创建新的对象和类。反射的实现,首先要获取Class实例。

获取Class实例的方法:

  • Object.getClass();
  Class class = object.getClass();
  枚举类型的对象获取的是枚举类的Class,数组对象获取的是数组元素的Class
  • .class
  Objcet.class; 

  int.class.newInstance()
  • Class.forName().
  只能用于引用类型,需要类的完整路径:如java.lang.String

  Class class = Class.forName("java.lang.String");
  • static属性TYPE
  Class<String> class = String.TYPE;
  TYPE的定义:public static final Class<String> TYPE = (Class<String>) String[].class.getComponentType();

获取相关类的Class对象:

  • 父类 getSuperclass()
  • 公共类、接口、枚举等 getClasses()
  • 显示申明的所有类、接口、枚举 getDeclaredClasses()
  • 成员声明类 getDeclaringClasses()

Class对象获取类的信息:

  • 获取类的修饰符(修饰符介绍见本文末)

  int modifier = class.getModifiers() ;

  String modifierStr = Modifier.toString(int modifiers);

  同时因为Field继承了AnnotatedElement,所以在运行时可以获取注解,获取的注解必须是RUNTIME所修饰的注解

获取类成员(Member)

  • 构造函数(Constructor)
getDeclaredConstructor(Class... parameterTypes)获取指定的构造方法,可获取私有方法
getConstructor(Class... parameterTypes) 获取指定的构造方法,不可获取私有方法
getDeclaredConstructors() 获取所有构造方法,可获取私有方法
getConstructor(Class... parameterTypes) 获取所有构造方法,不可获取私有方法
  • 成员变量(Field)

获取变量:

getDeclaredField(String name);// 获取指定的变量   类自有变量  包括取私有变量,但是不能获取继承父类的

getField(String name);  //获取指定的变量,可获取自身和继承自父类的public变量。

getDeclaredFields(); //获取类自有的所有变量集合,包括私有变量,不包括继承变量

getFields(); //获取自身和继承自父类的public变量的集合。

获取变量类型:

Field.getType() :返回Class对象  ,这个变量的类型
Field.getGenericType():返回Type接口  ,如果类型是泛型,getGenericType可以得到这个泛型的参数类型(T),getType()只能得到这个类型的接口类型(Object)。

设置变量的值

Class cls = object.getClass();

Field field = objcet.getField("name");

field.set(object,"new Name");

//修改变量的值时,编译器不会拆装箱操作,设置时必须设置相同的类型

Integer itg;

Class cls = object.getClass();

Field field = objcet.getField("itg");

field.set(object,new Integer(666));

//直接修改final类型的变量会报错`IllegalAccessException` 需要setAccessible(true),
//就可以访问修改了。(由于 `Field` 继承自 `AccessibleObject` , 我们可以使用 
//`AccessibleObject.setAccessible()` 方法告诉安全机制,这个变量可以访问。 )
  • 成员方法(Method:java.lang.reflect.Method)
//获取的方法属性同成员变量。
getDeclaredMethod(String name,Class parameterTypes.....)
getMethod(String name,Class parameterTypes.....)
getDeclaredMethods()
getMethods()

继承于父类的方法因强制执行无法被反射,因此反射方法仅限本类方法。

反射方法得到的数据由:修饰符、返回值、参数、注解、抛出异常五点组成:

getName());  //获得单独的方法名 

toGenericString()); //获得完整的方法信息(包括修饰符、返回值、路径、名称、参数、抛出值) 

int modifiers = declaredMethod.getModifiers();Modifier.toString(modifiers)    /获得修饰符 

getReturnType();   //获得返回值 

getGenericReturnType();//获得完整信息的返回值 

//获得参数类型 
Class[] parameterTypes = method.getParameterTypes(); 
Type[] genericParameterTypes = method.getGenericParameterTypes();

//获得异常名称 
Class[] exceptionTypes = declaredMethod.getExceptionTypes();   
Type[] genericExceptionTypes = declaredMethod.getGenericExceptionTypes();   

 //获得注解 
Annotation[] annotations = declaredMethod.getAnnotations(); 
annotations[i].annotationType();

三种特殊的方法类型:

synthetic(合成,内部类访问权限), varagrs(参数可变), bridge(桥接,泛型相关)

反射 调用方法

invoke() ;
//java.lang.reflect.Method.invoke(Object receiver,Object... args)
//该方法抛异常:java.lang.reflect.InvocationTargetException
receiver 是方法所属于的对象,静态方法可直接传null,args传方法的参数
//当访问private属性的方法时,需要设置setAccessible(true) 否则报`IllegalAccessException`异常

相似概念:Introspection(自省):

区别:

Introspection 是在运行时获取对象的信息,Reflection是获取或者修改对象的信息
Introspection多用于 instanceof 的判断,Reflection多用来实现访问私有方法,创建对象等
总的说,Reflection是多了可进行修改信息。

附录 :

Class对象的基本类型(8种)、引用类型:

基本类型:

  • 整型:默认类型int

    • byte : 8位、有符号的二进制补码表示整数、范围-128~127(-2^7~2^7-1)
    • short : 16位、有符号的二进制补码表示整数、范围-32768~32767(-2^15~2^15-1)
    • int : 32位、有符号的二进制补码表示整数、范围-214748348~2147483647(-2^31~2^31-1)
    • long : 64位 、 范围-9223372036854775808~9223372036854775807(-2^63~2^63-1) 。
      long a =1000000000000L;
  • 浮点类型:默认类型double

    • float : 单精度、32位浮点数,存储大型浮点数组较为节省空间、不能用来表示精确值如货币
    • double : 双精度、64位、也不可表示精确的数。
  • bool值
    boolean : true/false、 默认值false

  • 字符型

    • char : 单一的16位Unicode字符、最大值0(\u0000)、最大值65535(\uffff) 。char letter=”A”;

引用类型:

  • 引用类型都是继承自java.lang.Object
  • 类、枚举、数组、接口
  • java.io.Serializable接口及其实现类、包装类Double、Integer。

修饰符Modifier

修饰符用来定义类、方法、变量,通常在语句首位,分为两大类:访问修饰符和非访问修饰符

访问修饰符:

default:

    缺省值,不写明修饰符,在同一包内可见(类,接口,变量,方法可用)

    接口中变量隐式声明为public static final,方法隐式声明为public

public:

    对所有的类可见(类、接口、方法、变量可用)

    java 中main方法一定为共有的

protected:

    同一个包中的所有子类和其他类都可以访问(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法))

    不同包中的子类可见(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法)),其他类不能访问。

    不同包中的子类不能使用父类的实例对象访问其父类的protect属性的变量和方法。即:superClass.protectParameter不可见。只能subClass.protectParameter访问。

    避免不相关的类访问。

private:

    最严格访问级别,为了隐藏类实现的细节,保护类的数据,外部类和接口不能声明为private。

    只能在同一个类内可见(变量、方法可用,不能修饰外部类和接口(及接口的变量和方法))

访问修饰符在继承中的规则:子类权限必须大于父类,具体如下:

    1.父类public子类必为public.
    2.父类protected子类必须protected/public.
    3. 父类private子类无法继承.

非访问修饰符:

abstract:

    创建抽象类和抽象方法

    一个类不能同时被abstract和final修饰,一个类只要包含抽象方法,就一定要声明为抽象类。抽象类可以包含抽象和非抽象的方法,也可以不包含抽象方法。

    抽象方法不能被声明为static 和final,子类必须实现父类的抽象方法,除非子类也是抽象类

static:

    可以直接通过类名访问static修饰的变量和方法,如StaticClass.variableName /StaticClass.methodName().

    static 变量:也叫类变量,属于类所有,独立于类的实例对象(实例对象可以有多个,类变量只有一份),
    只能修饰成员变量,不可修饰局部变量。

    static 方法:类方法,独立于类的实例对象,方法内不能包含非静态的成员变量。

final:

    final修饰的类不能被继承,方法不能被子类重写,变量为常量不可修改。

    final修饰的变量必须显示初始化并且只能赋值一次。

    final变量不可修改,是指的其引用不可修改,引用变量的值改变,fianl变量包含的数据是可以改变的。:
    final Person p = new Person(24,name);
    p.setAge(25);

    final一般结合static创建常量。static final String CONSTANT_STRING = "I'M CONSTANT STRING"

    final修饰的方法不可被子类修改,可以防止该方法被改动

synchronized:

    说明被修饰的方法在同一个时间只能被一个线程访问,synchronized修饰符可以用应于 所有访问修饰符(public、default、private、protected)

transient:

    序列化对象时,JVM会跳过transient修饰的变量。public transient String str = "I'll be ignored";

volatile

    volatile修饰的成员变量在每次被线程访问时,都需要从共享内存中重新读取该成员变量的值,
    当此成员变量发生变化时,会强制线程将变化值写回共享内存,因此,在任何时刻,多个线程中此成员变量的值都相同。

native

    在JAVA中调用非JAVA语言写的方法(如C、C++) :native void nativeMethod(.....);
    native 不可以和abstract修饰符一起使用。(native虽然在JAVA代码没有方法体,但本地方法是有实现的)
    使用native主要是为了和java环境和操作系统等交互,本地方法在JAVA加载是,放在DLL文件中,方法native方法调用前,本地方法会被加载。

Thanks:

https://blog.csdn.net/u011240877/article/details/54604146

你可能感兴趣的:(Java)