Java泛型类型绑定。为什么不是';这不是吗?

Java泛型类型绑定。为什么不是';这不是吗?,java,generics,Java,Generics,鉴于此通用功能: <T> List<T> function() { return null; } List函数(){return null;} 这是为什么 List<String> l = function(); List l=function(); 而这不 List<String> l = (List<String>) function(); List l=(List)函数(); 因为当你做这样的演员时: (List<

鉴于此通用功能:

<T> List<T> function() { return null; }
List函数(){return null;}
这是为什么

List<String> l = function();
List l=function();
这不

List<String> l = (List<String>) function();
List l=(List)函数();

因为当你做这样的演员时:

(List<String>) function()
它可以推断
T
的正确类型

请注意,如果通过显式提供以下类型来规避类型推断的任务,则可以强制转换:

import java.util.List;

class Test {
    public static <T> List<T> function() { return null; }

    public static void main(String[] args) {
        List<String> l = (List<String>) Test.<String>function();
        //                              ^^^^^^^^^^^^^
    }
}
import java.util.List;
课堂测试{
公共静态列表函数(){return null;}
公共静态void main(字符串[]args){
List l=(List)Test.function();
//                              ^^^^^^^^^^^^^
}
}


我不知道泛型参数的确切类型推断规则。但是,它们是在中指定的。

类型推断似乎是在尝试转换(由编译器)之后发生的

表达式的类型由表达式的左侧确定,在尝试转换时,该左侧尚未“解析”。强制转换本身失败是因为,对于尚未推断的类型,方法调用的结果是类型
List


JLS的第节指出类型推断发生在最后。

第一个使用类型推断,使用结果分配给的变量的类型

在第二种情况下,调用的结果没有分配给任何对象(在转换完成之前),因此返回最通用的类型(
List
),并且
List
不能转换为
List
List
不扩展
List
。所以你不能投

您可以用下一种方法指定T

 List<String> l = this.<String>function();
List l=this.function();

这是因为编译器无法推断方法
函数()
的参数化类型,所以它将
t
绑定到
对象。您不能将
列表
转换为
列表

问题不准确

List<String> m = (List<String>)function();
List m=(List)函数();

产生警告“类型安全:未选中从对象到列表的强制转换”,这是正确的,因为所有到泛型类型的强制转换都是不安全的。

这是因为javac需要推断T,但T不会出现在参数类型中

static<T> T foo(){ .. }

foo(); // T=?


在其他情况下,javac不会,t被简单地推断为Object

编译时返回的编译器错误是什么?无法从一个列表转换到另一个列表。这里的三元条件问题似乎也是如此,但为什么编译器无法在第二种情况下绑定t?我不知道,但我也对答案感兴趣。JLS(第15.12.2.7节)在这里不是很直观。顺便说一句,Oracle站点已经关闭(包括JLS),我必须查看缓存。要到达与您相同的部分:)好吧,如果您(或任何其他人)能对这种行为给出一个简明的“为什么”,我很乐意接受答案。@Bozho,这就是我当前链接指向缓存版本的原因是编译的,所以我认为没有必要这样做。@aioobe我们也不需要强制转换。据我所知,这个问题不是关于如何。为什么类型推断不发生在第二种情况下?因为表达式“function()”的结果没有分配给变量。这是强制转换,强制转换的结果被分配给一个变量。你的解释对我来说不够,因为你不需要将它分配给变量,因为你可以调用function();(没有任何赋值)…禁止像i=“2”这样的表达式的原因是java是类型安全的,不能为变量赋值另一种类型的值。无论如何,如果您的答案是“因为设计Java的专家组决定,当方法调用的结果分配给变量时,应该有类型推断,但当方法调用的结果被强制转换为类型,然后分配给变量时,不应该有类型推断”,那么在这种情况下,它会失败:
public t f(){return null;}
然后是
String s=(String)f();
,因为这样可以顺利编译,而且不应该根据您的原因。不,不会失败。在这种情况下,您没有编译错误,因为f()计算为对象,对象可以转换为字符串:对象是字符串的超类。您的第二种情况不编译,因为正如错误消息所述,列表不能转换为列表,这是因为列表不是列表的超类。它们是两种不同类型,没有继承关系。请阅读,它会产生错误:
无法从一个列表强制转换到另一个列表
是的,但“为什么”在第二种情况下不绑定?编译器有相关信息。这是因为您没有显式强制转换,所以它会在运行时尝试强制转换。但在第一个语句中,我也没有显式强制转换。为了完整性,您的语句“因为您没有显式地进行类型转换,所以它将在运行时尝试对其进行强制转换”这是否意味着强制转换仅在运行时应用?因为这与未编译的代码不兼容:
int i=(int)”1“;
编译器知道这两种类型不可自动强制转换。@edutesoy,这是因为编译器在编译时强制转换,并且它知道它不能将字符串对象强制转换为原始int类型。对于您的情况,编译器知道它返回一个列表,但不知道要推断的参数化类型(因为您不是自己进行类型转换)。因此,它会将参数化类型删除到
列表中,以及您将何时执行,例如
String s=function()。获取(0)
以查看对象是否可转换为变量
s
类型。是的,我知道,请参阅我对aioobe答案的评论,以及他的链接(指向缓存)+1,答案很好,但我想更深入一点,为什么java在有强制转换时无法推断T?它也可以推断类型,因为它拥有所有信息,不是吗?为什么类型推断不适用于“强制转换”?我怀疑这与
static<T> T foo(){ .. }

foo(); // T=?
String s = foo(); // #1: assignment

String bar(){
    return foo(); // #2: return