繁体   English   中英

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

[英]Generics in method signatures and casts?

为什么这样做?

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

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

如果可能的 ,泛型方法中的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

VM在运行时很容易,因为由于类型擦除, T只是Object 换句话说:

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

编译成同样的东西:

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

该转换是未选中的 ,这意味着它不会被检查 - 无论是在编译时还是在运行时。 验证,编译和执行:

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";

这永远不会成功。

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

obj.getResult();

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

(MyClass的)obj.getResult();

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

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

public T getResult(Class annotated){return(T)getResult(annotated,new HashMap(0)); }

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

int y=10;
int z=12;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM