Java 基础2 - 反射

反射

Class

一般情况下,新建一个对象时可以在程序运行阶段之前就明确知道它的具体类型、属性等信息,然后使用 new 关键字进行生成,而反射这种手段是发生在运行的时候,而且是不知道这些信息的,需要借助于 Class 这个类来完成对象的生成。

每个已经加载的类在内存中都有一份它的信息,每个对象都有指向它的所属类信息的引用,类信息对应的类就是 java.lang.Class

Object 有一个方法可以获取对象的 Class 对象:

public final native Class<?> getClass()

因为这个方法本身不知道具体是个什么类型,所以用了个泛型通配符,如果用的时候知道具体类名,可以手动写明类型:

Class<People> class = People.class;

接口也有 Class 对象:

Class<Comparable> class = Comparable.class;

基本类型没有 getClass() 方法,但有 Class 对象,注意泛型参数就是包装类:

Class<Integer> intClass = int.class;
Class<Double> doubleClass = double.class;
...

数组:

Class<? extends String[]> strArrClass = (new String[3]).getClass();
Class<? extends int[][]> intArrsClass = (new int[3][3]).getClass();

枚举:

enum SIZE {
    SMALL, BIG
};
Class<SIZE> class = SIZE.class;

根据类名直接加载 Class (可能抛出异常 ClassNotFoundException ):

Class<?> class = Class.forName("java.util.HashMap");

使用 Class 获取信息

  1. 名称信息

    其实就是获取类名,有以下几种方法:

    public String getName();
    public String getSimpleName();
    public String getCanonicalName();
    public String getPackage();
    

  2. 字段信息

    Class 获取字段的方法:

    // 返回所有的public字段,包括父类的
    public Field[] getFields() throws SecurityException
    // 返回本类的所有字段,包括非 public 的,但不包括父类
    public Field[] getDeclaredFields() throws SecurityException
    // 返回本类或父类中指定名称的字段
    public Field getField(String name)
    // 返回本类中声明指定名称的字段
    public Field getDeclaredField(String name)
    

    Field 获取字段信息的方法:

    // 获取字段名称
    public String getName()
    // 是否当前程序可读
    public boolean isAccessible()
    // 修改是否可读,以支持访问非 public 字段
    public void setAccessible(boolean flag) throws SecurityException
    // 读取值,Obj就是被读取的目标对象
    public Object get(Object obj)
    // 设置值,Obj就是被写入的目标对象
    public void set(Object obj, Object value)
    
  3. 方法信息

    Class 类获取方法信息的方法跟获取字段信息的方法差不多,见名知意。有个特别点的方法需要留意下:

    public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
    

    对于 invoke 方法,如果这个 Mehtod 是个静态方法,obj 就会被忽略,可以为 nullargs 也可以为 null ,也可以为一个空数组,方法调用的返回值被包装为 Object 返回,如果实际方法调用抛出异常,异常会被包装为 InvocationTargetException 重新抛出,可以通过 getCause() 方法查看原异常。

  4. 创建对象和构造方法

    Class 有个 newInstance() 方法来创造新对象,它默认调用无参的 public 构造函数,如果没有,就会抛出异常。Class 还提供了 getConstructors() 来查看某个类有什么构造函数。

  5. 泛型

    有些类是使用了泛型的,有以下几种方式支持读取类的泛型信息:

    Class

    public TypeVariable<Class<T>>[] getTypeParameters()
    

    Field

    public Type getGenericType()
    

    Method

    public Type getGenericReturnType()
    public Type[] getGenericParameterTypes()
    public Type[] getGenericExceptionTypes()
    

    Constructor

    public Type[] getGenericParameterTypes()
    public Type[] getGenericExceptionTypes()
    
  6. 类型检查与转换

    instanceof 关键字可以判断某个对象是不是某个类的实例,instanceof 后面的类型是在代码中确定的,如果要检查的类型是动态的/运行前不确定的,可以使用 Class 提供的 isInstance() 来判断。

    代码中类型转换一般会在值的左边以 (类型)值 的形式做转换 ,这个类型也是提前知道的,如果是不确定的,可以使用 Class 提供的 cast() 方法来做转换。

    可以使用 Class 提供的 isAssignableFrom() 来判断某个对象能不能赋值给某种类的变量。

  7. Class 的类型信息

    判断是否是数组、接口、基本类型、枚举、注解、内部类等类型。

  8. 类的声明信息

    获取修饰符、用了什么注解、实现了哪些接口、等信息。

  9. 类的加载

    // 使用系统类加载器(也叫应用程序类加载器)加载
    public static Class<?> forName(String className) throws ClassNotFoundException
    // 使用指定的加载器加载
    public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
    

    根据类名加载类就用 forName() 方法,ClassLoader 见后文:类加载器

  10. 数组

    数组类型有个方法可以获取元素类型:

    public native Class<?> getComponentType()
    

    还有个专门的类 Array 可以用于创建数组对象以及对数组进行访问。

  11. 枚举

    枚举类型有个方法可以获取所有枚举常量:

    public T[] getEnumConstants();
    

本文作者:遥遥领先

本文链接:https://www.cnblogs.com/nyfblog/p/16519122.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   为何匆匆  阅读(43)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起