第十四章 类型信息1.0

运行时类型信息使得你可以在程序运行时发现和使用类型信息。

本章将讨论 Java 是如何允许我们在运行期识别对象和类的信息。主要有两种方式:一种是传统的RTTI,它假定我们在编译期和运行期已经知道了所有的类型;另一种是“反射机制(reflection)”,它允许我们在运行期获得类的信息。我们先讨论“传统”的RTTI,再讨论反射。

使用RTTI,你可以查询某个Shape引用所指向的对象的确切类型,然后选择或者剔除特例。

[color=blue]Class[/color]

要理解RTTI在Java中是如何工作的,首先必须要知道类型信息在运行期是如何表示的。这项工作是由被称为“Class对象”的特殊对象完成的,它包含了与类有关的信息。事实上,Class对象正是被用来创建类的“常规”对象的。

作为程序一部分,每个类都有一个Class对象。换言之,每当你编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)

因此,Java程序在它开始运行之前并非被完全加载,其各个部分是在必须时才加载的。

一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

Class对象仅在需要的时候才被加载,static初始化是在类加载时进行的。

[color=red]forName()是取得Class对象的引用的一种方法。[/color]它是用一个包含目标类的文本名(注意拼写和大小写)的String作输入参数,返回的是一个Class对象的引用,上面的代码忽略了返回值。[color=red]对forName()的调用是为了它产生的“副作用”:如果类Gum还没有被加载就加载它。在加载的过程中,Gum的static语句被执行。[/color]

如果你已经拥有了一个感兴趣的类型的对象,那就可以通过调用getClass()方法来获取Class引用了,这个方法属于根类Object的一部分,它将返回表示该对象的实际类型的Class引用。Class包含很多有用的方法,下面就是其中的一部分:
package typeinfo.toys;
interface HasBatteries {}
interface Waterproof {}
interface Shoots {}

class Toy {
Toy() {}
Toy(int i) {}
}

class FancyToy extends Toy implements HasBatteries, Waterproof, Shoots{
FancyToy() {
super(1);
}
}

public class ToyTest {
static void printInfo(Class cc) {
System.out.println("Class nameL " + cc.getName() +
"is interface: [" + cc.isInterface() + "]");
System.out.println("Sample name: " + cc.getSimpleName());
System.out.println("Canonical name: " + cc.getCanonicalName());
}

public static void main(String[] args) {
Class c = null;
try {
c = Class.forName("typeinfo.toys.FancyToy");
} catch (ClassNotFoundException e) {
System.out.println("cant find FancyToy");
System.exit(1);
}
printInfo(c);
for(Class face : c.getInterfaces()) {
printInfo(face);
}
Class up = c.getSuperclass();
Object obj = null;
try {
obj = up.newInstance();
} catch (InstantiationException e) {
System.out.println("cannt instantiate");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("cannt access");
e.printStackTrace();
}
printInfo(obj.getClass());
}
}
Output:
Class nameL typeinfo.toys.FancyToyis interface: [false]
Sample name: FancyToy
Canonical name: typeinfo.toys.FancyToy
Class nameL typeinfo.toys.HasBatteriesis interface: [true]
Sample name: HasBatteries
Canonical name: typeinfo.toys.HasBatteries
Class nameL typeinfo.toys.Waterproofis interface: [true]
Sample name: Waterproof
Canonical name: typeinfo.toys.Waterproof
Class nameL typeinfo.toys.Shootsis interface: [true]
Sample name: Shoots
Canonical name: typeinfo.toys.Shoots
Class nameL typeinfo.toys.Toyis interface: [false]
Sample name: Toy
Canonical name: typeinfo.toys.Toy


在传递给forName的字符串中,你必须使用全限定名。在main中Class.getInterfaces()方法返回的是Class对象,它们表示在感兴趣的Class对象中所包含的接口。getSuperClass也一样。

Class的newInstance()方法是实现“虚拟构造器”的一种途径,虚拟构造器允许你声明:“我不知道你的确切类型,但是无论如何要正确地创建你自己。”在前面的示例中,up仅仅只是一个Class引用,在编译期不具备任何更进一步的类型信息。当你创建新实例时,会得到Object引用,但是这个引用指向的是Toy对象。另外,使用newInstance()来创建的类,必须带有默认的构造器。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值