java核心技术卷I-反射

反射

能够分析类能力的程序称为反射(reflective )。反射机制的功能极其强大,在下面可以看到, 反射机制可以用来:
1.在运行时分析类的能力。
2.在运行时查看对象, 例如, 编写一个 toString 方法供所有类使用。
3.实现通用的数组操作代码。
4.利用 Method 对象, 这个对象很像中的函数指针。
反射是一种功能强大且复杂的机制。 使用它的主要人员是工具构造者,而不是应用程序
员。

Class 类

在程序运行期间,Java 运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。 虚拟机利用运行时类型信息选择相应的方法执行。然而, 可以通过专门的 Java 类访问这些信息。保存这些信息的类被称为 Class, 这个名字很容易让人混淆。
一个 Class 对象将表示一个特定类的属性。最常用的 Class 方法是 getName。 这个方法将返回类的名字。例如,下面这条语句:

System.out.println(e.getClass().getName() + " " + e.getName());

还可以调用静态方法 forName 获得类名对应的 Class 对象。

String className = "java.util.Random";
Class cl = Class.forName(className );

如果类名保存在字符串中, 并可在运行中改变, 就可以使用这个方法。当然, 这个方法只有在 dassName 是类名或接口名时才能够执行。否则,forName 方法将抛出一个checked exception ( 已检查异常)。无论何时使用这个方法, 都应该提供一个异常处理器( exception handler) 。

获得 Class类对象的第三种方法非常简单。如果 T 是任意的 Java 类型(或 void 关键字,) T.class 将代表匹配的类对象

Class cl1 = Random,class; // if you import java.util
Class cl2 = int.class;
Class cl3 = Double.class;

请注意,一个 Class 对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int 不是类, 但 int.class 是一个 Class 类型的对象

虚拟机为每个类型管理一个 Class 对象。 因此,可以利用 =运算符实现两个类对象比较
的操作

if (e.getClass()== Employee.class) . . .

newlnstance( ), 可以用来动态地创建一个类的实例

e.getClass0.newlnstance();

创建了一个与 e 具有相同类类型的实例。 newlnstance方法调用默认的构造器(没有参数的构造器)初始化新创建的对象。如果这个类没有默认的构造器, 就会抛出一个异常

将 forName 与 newlnstance 配合起来使用, 可以根据存储在字符串中的类名创建一个对象

String s = "java.util.Random";
Object m = Class.forName(s).newlnstance();

捕获异常

异常有两种类型: 未检查异常和已检查异常。 对于已检查异常, 编译器将会检查是否提供了处理器。 然而,有很多常见的异常, 例如,访问 null 引用, 都属于未检查异常。编译器不会査看是否为这些错误提供了处理器。
并不是所有的错误都是可以避免的。如果竭尽全力还是发生了异常, 编译器就要求提供
一个处理器。Class.forName 方法就是一个抛出已检查异常的例子

利用反射分析类的能力

简要地介绍一下反射机制最重要的内容—检查类的结构,在 java.lang.reflect 包中有三个类 Field、 Method 和 Constructor 分别用于描述类的域、 方法和构造器。 这三个类都有一个叫做 getName 的方法, 用来返回项目的名称。Held 类有一个 getType 方法, 用来返回描述域所属类型的 Class 对象。Method 和 Constructor 类有能够报告参数类型的方法,Method 类还有一个可以报告返回类型的方法。这 个类还有一个叫做 getModifiers 的方法, 它将返回一个整型数值,用不同的位开关描述 public 和 static 这样的修饰符使用状况。另外, 还可以利用java.lang.reflect 包中的 Modifier类的静态方法分析getModifiers 返回的整型数值。例如, 可以使用 Modifier 类中的 isPublic、 isPrivate 或 isFinal判断方法或构造器是否是 public、 private 或 final。 我们需要做的全部工作就是调用 Modifier类的相应方法,并对返回的整型数值进行分析,另外,还可以利用 Modifier.toString方法将修饰符打印出来。

Class类中的 getFields、 getMethods 和 getConstructors 方 法 将 分 别 返 回 类 提 供 的public 域、 方法和构造器数组, 其中包括超类的公有成员。Class 类的 getDeclareFields、getDeclareMethods 和 getDeclaredConstructors 方法将分别返回类中声明的全部域、 方法和构造器, 其中包括私有和受保护成员,但不包括超类的成员。

在运行时使用反射分析对象

在编写程序时, 如果知道想要査看的域名和类型,查看指定的域是一件很容易的事情。而利用反射机制可以查看在编译时还不清楚的对象域。
查看对象域的关键方法是 Field类中的 get 方法。如果 f 是一个 Field 类型的对象(例如,通过 getDeclaredFields 得到的对象,) obj 是某个包含 f 域的类的对象,f.get(obj) 将返回一个对象,其值为 obj 域的当前值。

Employee harry = new Employee("Harry Hacker", 35000, 10, 1, 1989);
Class cl = harry.getClass(); // the class object representing Employee
Field f = cl.getDeclaredField('name"): // the name field of the Employee class
Object v = f.get(harry); // the value of the name field of the harry object , i .e., the String object "Harry Hacker"

由于 name 是一个私有域, 所以 get 方法将会抛出一个IllegalAccessException。只有利用 get 方法才能得到可访问域的值。除非拥有访问权限,否则Java 安全机制只允许査看任意对象有哪些域, 而不允许读取它们的值。
反射机制的默认行为受限于 Java 的访问控制。然而, 如果一个 Java 程序没有受到安全管理器的控制, 就可以覆盖访问控制。 为了达到这个目的, 需要调用 Field、 Method 或Constructor 对象的 setAccessible 方法。

f.setAtcessible(true); // now OK to call f.get(harry);

setAccessible 方法是 AccessibleObject 类中的一个方法, 它是 Field、 Method 和 Constructor类的公共超类。这个特性是为调试、 持久存储和相似机制提供的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

局外人一枚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值