方法签名和演员表中的泛型?

时间:2010-11-19 19:14:54

标签: java generics

为什么这样做?

@SuppressWarnings("unchecked")
public <T> T getResult(Class annotated) {
    return (T) getResult(annotated, new HashMap<String, Object>(0));
}

编译器如何知道如何转换返回值?它在编译时无法知道它:它可能是任何东西。它是否每次都在运行时执行?

5 个答案:

答案 0 :(得分:4)

如果可能的话,泛型方法中T的类型是从调用的上下文推断出来的。

String string = foo.getResult(Something.class);

如果无法从上下文中确定T的类型(例如,如果结果直接作为参数传递给本身是通用的方法),则可能必须自己指定类型:

List<String> list = Arrays.asList(foo.<String>getResult(Something.class));

通用方法也可以使用它们在参数中声明的类型,这可以强制参数和结果类型达成一致:

public <T> T getResult(Class<T> type) { ... }

String string = foo.getResult(String.class); // ok
String string = foo.getResult(Something.class); // not ok

在运行时,泛型不存在,因此它只是尝试将结果分配给您尝试将其分配给的任何内容...如果它是错误的类型,则会得到ClassCastException

答案 1 :(得分:3)

VM在运行时很容易,因为T由于type-erasure而只是Object。换句话说:

return (T)getResult(annotated, new HashMap<String, Object>(0));

编译成与此相同的东西:

return (Object)getResult(annotated, new HashMap<String, Object>(0));

答案 2 :(得分:2)

该强制转换未经检查,这意味着已检查 - 无论是在编译时还是在运行时。验证,编译和执行:

static <T> T magicCast(Class<T> clazz, Object o) {
    return (T) o;
}

public static void main(String[] args) {
    magicCast(Integer.class, "hello");
    System.out.println("The magic cast always works.");
}

当然,这很危险。考虑:

public class Test<T> {
    public final T foo;

    public Test(Object foo) {
        this.foo = (T) foo;
    }

    public static void main(String[] args) {
        Test<String> test = new Test<String>(42);

        // after being passed through dozens of methods     
        test.foo.startsWith("hello"); // ClassCastException     
    }
}

持有不是声明类型的子类型的对象的变量的歪曲称为堆污染。这就是为什么编译器被要求发出未经检查的警告的原因 - 除非有人压制了这个警告。

因此建议尽可能进行反射演员;例如:

static <T> T magicCast(Class<T> clazz, Object o) {
    return clazz.cast(o); // reflective cast, checked at runtime
}

当然,如果你在编译时知道这个类,你应该使用普通的强制转换,因为这样可以让编译器执行额外的健全性检查,允许它拒绝像

这样的强制转换。
int x = (Integer) "hello";

永远不会成功。

答案 3 :(得分:0)

不幸的是你没有写你如何调用这个方法。 我相信代码看起来像:

obj.getResult();

在这种情况下答案很简单:编译器将转换添加到MyClass,如果您反编译字节代码,您会看到类似

的内容

(MyClass的)obj.getResult();

如果您调用方法并将结果分配给变量,则会发生同样的情况: MyClass结果= obj.getResult();

顺便说一下,我觉得很遗憾你添加了注释@SuppressWarining(“unchecked”) 如果T是“注释”类型,你应该说:

public T getResult(Class annotated){     return(T)getResult(带注释,新的HashMap(0)); }

这是使用泛型的常用方法。请参阅类Collections,Arrays,AbstractList.toArray()等。

答案 4 :(得分:0)

int y=10;
int z=12;