4

据我了解,Java 泛型会删除泛型方法(或泛型类)中有关参数类型 T 的所有信息。这就是为什么我们不能使用

新的表达方式,例如

new T()

instanceof 表达式,例如

if(obj instanceof T)

在泛型方法中。

我的问题是参数类型 T 在进行强制转换时如何在泛型方法中工作。例如,我在这里有 3 个简单的类:

public class People {

    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public People(String name) {
        super();
        this.name = name;
    }

    @Override
    public String toString() {
        return "People [name=" + name + "]";
    }

}

public class GenericClass<T> {

    public T getCast(People p) {
        return (T)p;
    }
}

public class App 
{
    public static void main( String[] args )
    {
        People p = new People("Kewei");

        GenericClass<Integer> genericClass = new GenericClass<Integer>();
        Object p_object = genericClass.getCast(p);

        System.out.println(p_object);
    }
}

当它(T)p在泛型方法中执行时getCast(People p)。它只是将类型 T 作为对象吗?(T)或者它只是在编译时删除了整个转换?我读过 Bruce Eckel 的 «Thinking in Java»,从中我大致理解为:

Java 编译器在编译时检查方法的入口/离开点,以确保泛型方法的内部一致性,并插入转换代码(在编译时)。

是正确的理解吗?

谢谢。

4

2 回答 2

4

您可以在脑海中想象编译器将具有泛型的代码“重写”为没有泛型的代码。

在泛型类中,T 被擦除到其上限的擦除,在这种情况下是 Object,但可能是其他东西。对 T 的强制转换成为对 T 的上限的强制转换(在这种情况下是 Object,因此它是多余的,编译器可能会跳过它)。该方法同样返回 T 的上限(即 Object)。所以没有运行时检查该方法内的强制转换是否有效。

public class GenericClass {

    public Object getCast(People p) {
        // In this case the cast to T is removed because T's upper bound is Object.
        // But if T's upper bound was, say, Number, then there would still be a cast
        // to the upper bound. e.g. "(Number)p", and the return type would also be Number
        return p;
    }
}

在调用返回 T 的方法的地方,编译器会在 T 的实际类型中插入一个强制类型转换。在这种情况下,在 main 方法中,你有一个GenericClass<Integer>,所以当getCast返回 T 时,它被强制转换为 Integer。所以在这种情况下,运行时检查现在被“移动”到调用方法,而不是带有强制转换的方法。

// somewhere else
GenericClass genericClass = new GenericClass();
p_object = (Integer)genericClass.getCast(p);

调用者也有可能保留一个GenericClass<S>引用(对于其范围内的某些类型参数 S),因此结果被强制转换为 S,而不是特定类型。然后我们将再次重复整个重写过程(即,对 S 的强制转换被重写为对其上限的强制转换,并且调用该方法的地方会将结果强制转换为它们的实际类型参数)。这意味着运行时检查可能会推迟到另一个地方,等等。

于 2012-07-06T01:14:32.877 回答
-1

Java 从不强制转换任何东西。在运行时,它被简单地视为“对象”。JRE 尝试调用该对象上的方法,并且由于它们已被证明在编译它时存在,因此它可以工作。

在运行时没有提到T 类是什么。。所以没有进行任何铸造。

于 2012-07-05T23:06:51.010 回答