泛化的Class引用

Class引用总是指向某个Class对象它可以制造类的实例,并包含可作用于这些实例的所有方法代码。它还包含该类的静态成员,因此,Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。

但是,Java SE5 的设计者们看准机会,将它的类型变得更具体了一些,而这是通过允许你对Class引用指向的Class对象的类型进行限定而实现的,这里用到了泛型语法。在下面的实例中,两种语法都是正确的:

public class GenericClassReferences{
    public static void main(String[] args){
        Class intClass = int.class;
        Class<Integer> genericIntClass = int.class;
        genericIntClass = Integer.class;
        intClass = double.class;
        // genericIntClass = double.class;
    }
}

普通的类引用不会产生警告信息,你可以看到,尽管泛型类引用只能赋值为指向其声明的类型,但是普通的类引用可以被重新赋值为指向任何其他的Class对象。通过使用泛型语法,可以让编译器强制执行额外的类型检查。

如果你希望稍微放松一些这种限制,应该怎么办呢?乍一看,好像你应该能够执行类似下面这样的操作:

Class<Number> genericNumberClass = int.class

这看起来似乎是起作用的,因为Integer继承自Number。但是它无法工作,因为Integer Class对象不是Number Class对象的子类(这种差异看起来可能有些诡异)

为了在使用泛化的Class引用时放松限制,我使用了通配符,它是Java泛型的一部分。通配符就是"?",表示“任何事物“。因此,我们可以在上例的普通Class引用中添加通配符,并产生相同的结果:

public class WildcardClassReferences{
    public static void main(String[] args){
        Class<?> intClass = int.class;
        intClass = double.class;
    }
}

在Java SE 5中, Class<?>优于平凡的Class,即便它们是等价的,并且平凡的Class如你所见,不会产生编译器警告信息。Class<?>的好处是它表示你并非是碰巧或者由于疏忽,而使用了一个非具体的类引用,你就是选择了非具体的版本。

为了创建一个Class引用,它被限定为某种类型,或该类型的任何子类型,你需要将通配符与extends关键字相结合,创建一个范围。因此,与仅仅声明Class<Number>不同,现在做如下声明:

public class BoundedClassReferences{
    public void main(String[] args){
        Class<? extends Number> bounded = int.class;
        bounded = double.class;
        bounded = Number.class;
        //Or anything else derived from Number;
    }
}

向Class引用添加泛型语法的原因仅仅是为了提供编译期类型检查,因此如果你操作有误,稍后立即就会发现这一点。在使用普通Class引用,你不会误入歧途,但是如果你确定犯了错误,那么直到运行时你才会发现它,而这显得很不方便。

results matching ""

    No results matching ""