Java 方法签名和强制转换中的泛型?

Java 方法签名和强制转换中的泛型?,java,generics,Java,Generics,为什么这样做有效 @SuppressWarnings("unchecked") public <T> T getResult(Class annotated) { return (T) getResult(annotated, new HashMap<String, Object>(0)); } @SuppressWarnings(“未选中”) 公共T getResult(带注释的类){ 返回(T)getResult(带注释的,新的HashMap(0)); }

为什么这样做有效

@SuppressWarnings("unchecked")
public <T> T getResult(Class annotated) {
    return (T) getResult(annotated, new HashMap<String, Object>(0));
}
@SuppressWarnings(“未选中”)
公共T getResult(带注释的类){
返回(T)getResult(带注释的,新的HashMap(0));
}

编译器如何知道如何强制转换返回值?它不能在编译时知道它:它可以是任何东西。它是否每次都在运行时执行此操作?

对于VM来说,在运行时执行此操作很容易,因为
T
只是
对象
的原因。换言之:

return (T)getResult(annotated, new HashMap<String, Object>(0));
return(T)getResult(带注释的,新的HashMap(0));
编译为与此相同的内容:

return (Object)getResult(annotated, new HashMap<String, Object>(0));
return(Object)getResult(带注释的,新的HashMap(0));

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

String string = foo.getResult(Something.class);
如果无法从上下文中确定
T
的类型(例如,如果结果作为参数直接传递给本身为泛型的方法),则您可能需要自己指定类型:

List<String> list = Arrays.asList(foo.<String>getResult(Something.class));
List List=Arrays.asList(foo.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
publictgetresult(类类型){…}
String String=foo.getResult(String.class);//好啊
String=foo.getResult(Something.class);//不好

在运行时,泛型不存在,所以它只是尝试将结果分配给您试图将其分配给的任何对象。。。如果它是错误的类型,您会得到一个
ClassCastException

不幸的是,您没有编写如何调用此方法。 我相信代码看起来像:

obj.getResult()

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

(MyClass)obj.getResult()

如果调用方法并将其结果赋给变量,也会发生同样的情况: MyClass结果=obj.getResult()

顺便说一句,我认为很遗憾您添加了注释@suppresswaring(“未选中”) 如果T为“注释”类型,则应说明:

公共T getResult(带注释的类){ 返回(T)getResult(带注释的,新的HashMap(0)); }

这是处理泛型的常用方法。请参见类集合、数组、AbstractList.toArray()等。

未选中强制转换,这意味着未选中它-无论是在编译时还是在运行时。要验证、编译和执行:

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.");
}

这永远不会成功。

原始代码包含在我们正在编写的api客户端类中。我们想避开强制转换返回值的问题,并且必须传入我们想要返回的类也会有很多额外的代码。所以,如果它被编译为返回对象,那么为什么我们可以这样做:Product p=getResult(…)不必强制转换返回产品?,因为编译器会为您插入强制转换。是的,正如我在回答中的第二个代码示例所示,这种不可见的施法可能会失败。@Matthew,@meriton:这是因为已经有施法了。。。内部
getResult
。根据
getResult
返回
T
并且该结果被分配给
产品的事实,可以推断调用的类型
T
。因此,
T
必须是
Product
,方法内部的强制转换实际上是对
Product
的强制转换。我们需要区分编译时的强制转换和字节码中的强制转换指令。你的评论是指前者,我的评论是指后者。也就是说,getResult()的字节码中没有接收器类型为T的强制转换指令。getResult()的调用者中可以(但不必)有强制转换指令。
int y=10;
int z=12;
static <T> T magicCast(Class<T> clazz, Object o) {
    return clazz.cast(o); // reflective cast, checked at runtime
}
int x = (Integer) "hello";
int y=10;
int z=12;