黑马程序员——Java 基础:反射

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

一、概述
  反射就是将 Java 类中的各种成分映射成相应的 Java 类。在 Java 中提供了 Class、Constructor、Field、Method 等来描述 Java 类和类中的构造函数、字段和方法等,并通过这些类的对象提供从 Java 类中获取构造函数、字段和方法对象等的方法。

二、Class 类
  Java 中用类来描述一类事物,而 Class 类就是描述 Java 类的类,它代表的是类在实例化后或加载后在内存中的字节码。Class 类没有构造函数,需要通过其他方法获得 Class 类对象。

// 使用 Object 类中的 getClass 方法获得 Class 类对象
Class c = new Object().getClass();
// 直接通过类对象的字节码获得对象
String s = "abc";
Class c = String.class;
// 使用 Class 类中的 forName 静态方法获得与传入的字符串相关联的类的对象
Class c = Class.forName("java.lang.String");

  在第三种方法中,传入的字符串可以为变量,并且由于字符串代表的类可能无效,所以会抛出异常,在使用此方法时需要处理异常。
  在对 Class 类的对象进行是否相等的判断时,因为其为字节码,所以应当使用“==”而不是 equals 方法,不过使用 equals 方法也可以得到正确的结果。
  在 Java 中基本数据类型也对应各自的 Class 类对象,如整型对应的 Class 类对象为 int.class,同时这一对象还与各个基本数据类型对应的基本数据类型包装类中的 TYPE 常量的值相等,如 int.class 等于 Integer.TYPE,char.class 等于 Character.TYPE。
Class 类中还提供了 isPrimitive 方法,用于判断 Class 类对象是否为基本数据类型的 Class 类对象。
  空返回值类型 void 也有 Class 类对象,为 void.class。
  在获得了 Class 类对象后,可以使用此对象调用 newInstance 方法创建一个新的对象,如
String s1 = String.class.newInstance();
  也可以通过 getName 方法获得 Class 对象所对应的实体,其中基本数据类型返回值与其关键字相同,类和接口返回的字符串为”L+类名”,数组类型返回的关键字为“[”加上类型名,其中类型名为编码后的单个大写字母,“[“的数量则与数组的维度相同,如 int[2][3] 的 Class 类对象调用 getName 方法的返回值为”[[I“。

二、构造方法的反射
  使用 Class 类的 getConstructor 和 getConstructors 方法,可以从 Class 类对象中获取构造方法对象,并利用此构造方法对象创建新的类的对象。

// 从 Class 类对象中获得构造方法对象并使用构造方法对象创建对象
class Demo {
    public static void main (String[] args) {
        String s = "abc";
        // 从 Class 类对象中获得类中所有构造方法的对象组成的数组
        Constructor[] cons = s.getClass().getConstructors();
        // 从 Class 类对象中获得特定参数类型的构造方法的对象
        Constructor con = s.getClass().getConstructor(StringBuffer.class);
        //使用构造方法对象创建新的对象
        String s1 = (String) con.newInstance(new StringBuffer("bcd"));
    }
}

  需要注意的是,使用构造方法对象创建类的对象时,传入的数据类类型必须与之前获取的方法的参数类型相匹配,此外,使用构造方法对象创建的类的对象的类型为 Object 类,因此需要进行强制类型转换。

三、成员变量的反射
  使用 Class 类的 getField 和 getFields 方法可以获取 Class 类对象中的字段对象或字段对象数组,获得的字段对象可以调用 Field 类的方法修改指定对象中的成员变量的值。

// 创建一个类,其中包含两个成员变量
Class FieldDemo {
    private int x;
    public int y;
    public void FieldDemo (int x,int y) {
        this.x = x;
        this.y = y;
    }
}
// 获取 Class 类对象中的成员变量的字段对象并修改指定对象中的成员变量的值
class Demo {
    public static void main (String[] args) {
        // 创建类的对象并传入初始值
        FieldDemo fd = new FieldDemo(3,5);
        // 获取成员变量 y 的字段对象
        Field fieldY = fd.getClass().getField("y");
        // 获得对象 fd 中 fieldY 对应的变量的值
        int y = (int) fieldY.get(fd);
        //由于变量 x 为私有变量,只能通过 getDeclaredField 方法获得相应的 Field 对象
        Field fieldX = fd.getClass().getDeclaredField("x");
        //使用父类的 setAccessible 方法将对象设置为可以访问
        fieldX.setAccessible(true);
        // 获取对象 fd 中 fieldX 对应的变量的值 
        int x = (int) fieldX.get(fd);
        //将 fd 对象中的 x 和 y 设为新的值
        fieldX.set(fd,2);
        fieldY.set(fd,4);
    }
}

四、成员方法的反射
  使用 Class 类中的 getMethod 和 getMethods 方法可以获得Class 类对象中成员方法对象和成员方法对象的数组。使用获得的 Method 对象可以调用类中的成员方法。

// 从Class 类对象中获取 Method 对象,然后使用该对象调用方法
class Demo {
    public static void main (String[] args) {
        String s = "abc";
        // 获取对象中的 CharAt 方法对象 
        Method method = s.getClass().getMethod("CharAt",int.class);
        String s1 = "abcde";
        //使用 Method 对象调用 CharAt 方法
        char c = method.invoke(s1,3);
    }
}

  如果使用 getMethod 方法获取的是静态方法的对象,在通过该对象调用静态方法时不需要对象,即其格式可能为 method.invoke(null,3) 。

五、数组的反射
  每种数组也有自己的 Class 类对象,如整型数组的 Class 类对象为 Int[].class,数据类型相同且维度相同的数组的 Class 类对象相等。
  Java 中的 Array 类提供了一些静态方法,可以对数组对象进行操作。

// 设计一个打印方法,判断传入的对象是否为数组,如果是数组就打印其中的元素,不是数组就直接打印
public static void printObject (Object obj) {
    Class c = obj.getClass();
    //判断该对象是否为数组
    if (s.isArray()) {
        //获取数组的长度
        int len = Array.getLength(obj);
        //打印数组
        for (i=0;i<len;i++) {
            System.out.print(Array.get(obj,i));
        }
    }
    else System.out.println(obj);
}

  其中 isArray 方法可以判断对象是否为数组,但是没有方法直接通过数组对象判断数组中元素的类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值