Java Can';t将泛型方法的结果传递给另一个方法?
我有一个简单的泛型方法,它创建一个包含n个元素的列表并返回它:Java Can';t将泛型方法的结果传递给另一个方法?,java,generics,Java,Generics,我有一个简单的泛型方法,它创建一个包含n个元素的列表并返回它: import java.util.*; class A { public static <T> List<T> init(int n) { List<T> l = new ArrayList<T>(); while (n --> 0) l.add(null); return l; } public stati
import java.util.*;
class A {
public static <T> List<T> init(int n) {
List<T> l = new ArrayList<T>();
while (n --> 0) l.add(null);
return l;
}
public static void main(String[] args) {
List<String> x = init(5);
f(x);
}
public static void f(List<String> l) {
System.out.println("l: " + l);
}
}
但是如果我去掉额外的变量:
import java.util.*;
class A {
public static <T> List<T> init(int n) {
List<T> l = new ArrayList<T>();
while (n --> 0) l.add(null);
return l;
}
public static void main(String[] args) {
f(init(5));
}
public static void f(List<String> l) {
System.out.println("l: " + l);
}
}
import java.util.*;
甲级{
公共静态列表初始化(int n){
列表l=新的ArrayList();
而(n-->0)l.add(null);
返回l;
}
公共静态void main(字符串[]args){
f(init(5));
}
公共静态无效f(列表l){
System.out.println(“l:+l”);
}
}
它不再编译
$ javac A.java && java A
A.java:9: f(java.util.List<java.lang.String>) in A cannot be applied to (java.util.List<java.lang.Object>)
f(init(5));
^
1 error
$javac A.java&&javaa
A.java:9:f(java.util.List)不能应用于(java.util.List)
f(init(5));
^
1错误
为什么?
但这是可行的:
import java.util.*;
class A {
public static <T> List<T> init(int n) {
List<T> l = new ArrayList<T>();
while (n --> 0) l.add(null);
return l;
}
public static <T> T id(T t) {
return t;
}
public static void main(String[] args) {
List<String> x = init(5);
f(id(x));
}
public static void f(List<String> l) {
System.out.println("l: " + l);
}
}
import java.util.*;
甲级{
公共静态列表初始化(int n){
列表l=新的ArrayList();
而(n-->0)l.add(null);
返回l;
}
公共静态T id(T T){
返回t;
}
公共静态void main(字符串[]args){
列表x=init(5);
f(id(x));
}
公共静态无效f(列表l){
System.out.println(“l:+l”);
}
}
为什么?在第一个和第三个例子中,你都说你在谈论一个
列表,但在第二个例子中,你说的是f(init(5))
,它可能是一个列表。我不是100%这是唯一的原因,但请检查:)如果您省略了额外的变量,编译器在调用init(5)
时无法推断类型参数T
。它假定T
是Object
,因此编译器错误
将额外变量声明为列表x
时,编译器将T
推断为String
f(init(5));
这将使用直接从init()
接收的参数调用f()
。但是,init()
现在返回T
的列表。对于未指定的T
,Java只使用Object
,因为它是所有对象的基类<代码>列表
不是列表
,因此方法签名和参数不匹配
List<String> x = init(5);
f(x);
这基本上是一样的。现在,由于x
具有类型List
,id()
的类型T
是String
。这样,id()
的返回值也是与签名匹配的List
。Java依靠推理来确定在未明确定义类型变量的情况下类型变量是什么
List<String> x = init(5);
f(id(x));
在您的第一个示例中:
List<String> x = init(5);
f(x);
编译器无法推断您正在调用init
,因为您没有明确地告诉它(通过A.init(5)
),也没有将它分配给适当的变量
在第三个示例中:
List<String> x = init(5);
f(id(x));
List x=init(5);
f(id(x));
编译器推断您正在调用id
,它将列表
返回到f
编译器在泛型推理方面不太聪明。除非通过使用变量或直接将类型参数传递给方法来明确说明类型参数是什么,否则它将无法找出它们
如果您对细节感到好奇,以下是JLS的相关部分:
首先,修复
f(A.<String>init(5)); // compiles
f(A.init(5));//汇编
现在,原因是:编译原始代码是因为java可以推断类型,因为它被分配给一个类型化变量。但当传递给类型化参数时,推理不起作用
该修复程序在调用类型化方法时使用语法显式指定类型。如果无法推断类型参数,那么它如何知道绑定到结果的列表x
是有效的?它是隐式铸造吗?我认为Java不会这样做。如果不给编译器一点线索,它就无法推断。当你说x的类型是一个List
时,你给了它一个线索来推断init
的返回类型是一个List
。但是有一个线索,那就是从init
返回的值被传递到f
,它接受List
。这与Math.sqrt(Math.sqrt(123))
有何不同?请告诉我,我将用一个例子来增强您的答案,值得注意的是,将添加目标类型泛型推理。显然,您的第二个示例将在中起作用。
List<String> x = init(5);
f(id(x));
f(A.<String>init(5)); // compiles