当return类型为'T'且方法参数包含通配符时,return类型与方法参数发生冲突
Conflict between return type and method parameter when return type is 'T' and method parameter consist of wild card
我正在尝试 运行 一个代码。我和我得到两个编译错误:
1.Reference 到 System.out.println
不明确(获取 char[] 的方法与获取 String 的方法之间存在冲突)
2.Cap#1 无法转换为 T return st.pop()
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Stack <Number> stackNumber = new Stack<Number>();
Test t = new Test();
t.setMethod(stackNumber,new Integer(3));
System.out.println(t.getMethod(stackNumber));
}
public <T extends Number> void setMethod (Stack<? super Number>st,T t)
{
st.add(t);
}
public <T>T getMethod (Stack<? extends Number >st)
{
return st.pop();
}
}
我知道我可以将 getMethod 签名更改为 return Number 并且程序将成功编译,但我想了解为什么使用当前签名我会遇到编译错误?
AFAIK,无边界的 T 被视为 Object 并且声明为 return Object 的函数可以 return 任何对象,因为 Object是所有类(包括Number)的"Father"。有人可以告诉我我在这里不屑一顾吗?
您的两种方法都不应该使用通配符捕获,您有两种通用方法 T
。喜欢,
public <T> void setMethod(Stack<T> st, T t) {
st.add(t);
}
public <T> T getMethod(Stack<T> st) {
return st.pop();
}
如果你想确保 T
出于某种原因必须是 Number
(那么我会使用 Number
),你可以在 T
处定义它。喜欢,
public <T extends Number> void setMethod(Stack<T> st, T t) {
st.add(t);
}
public <T extends Number> T getMethod(Stack<T> st) {
return st.pop();
}
but i want to understand why with current signature i'm getting compilation errors?
错误都是因为 <T>
是在调用站点确定的。
查看编译错误1:
Java 选择最具体适用的方法。可以选择采用引用类型参数的任何 PrintStream.println
方法。
来自 JLS 15.12.2.5:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
任何可以传递给println(char[])
或println(String)
的东西也可以传递给println(Object)
,因此前者的方法比后者更具体。因此,这些将优先于 println(Object)
.
选择
然而,一些可以传递给 println(char[])
的东西不能传递给 println(String)
,因此它们都不比另一个更具体,因此方法调用不明确。
现在查看编译错误2:
public <T>T getMethod (Stack<? extends Number >st)
{
return st.pop();
}
此方法必须在所有情况下都能安全调用。你这样调用它:
System.out.println(t.getMethod(stackNumber));
即您将结果简单地视为一个对象。但是你可以合法地在调用站点上写这个:
String s = t.getMethod(stackNumber);
很明显这会失败,因为从包含数字的堆栈中弹出的内容无法转换为 String
。
因为编译器不能保证它会被调用"safe" T
,这是一个错误。
我正在尝试 运行 一个代码。我和我得到两个编译错误:
1.Reference 到 System.out.println
不明确(获取 char[] 的方法与获取 String 的方法之间存在冲突)
2.Cap#1 无法转换为 T return st.pop()
import java.util.*;
public class Test
{
public static void main(String[] args)
{
Stack <Number> stackNumber = new Stack<Number>();
Test t = new Test();
t.setMethod(stackNumber,new Integer(3));
System.out.println(t.getMethod(stackNumber));
}
public <T extends Number> void setMethod (Stack<? super Number>st,T t)
{
st.add(t);
}
public <T>T getMethod (Stack<? extends Number >st)
{
return st.pop();
}
}
我知道我可以将 getMethod 签名更改为 return Number 并且程序将成功编译,但我想了解为什么使用当前签名我会遇到编译错误? AFAIK,无边界的 T 被视为 Object 并且声明为 return Object 的函数可以 return 任何对象,因为 Object是所有类(包括Number)的"Father"。有人可以告诉我我在这里不屑一顾吗?
您的两种方法都不应该使用通配符捕获,您有两种通用方法 T
。喜欢,
public <T> void setMethod(Stack<T> st, T t) {
st.add(t);
}
public <T> T getMethod(Stack<T> st) {
return st.pop();
}
如果你想确保 T
出于某种原因必须是 Number
(那么我会使用 Number
),你可以在 T
处定义它。喜欢,
public <T extends Number> void setMethod(Stack<T> st, T t) {
st.add(t);
}
public <T extends Number> T getMethod(Stack<T> st) {
return st.pop();
}
but i want to understand why with current signature i'm getting compilation errors?
错误都是因为 <T>
是在调用站点确定的。
查看编译错误1:
Java 选择最具体适用的方法。可以选择采用引用类型参数的任何 PrintStream.println
方法。
来自 JLS 15.12.2.5:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
任何可以传递给println(char[])
或println(String)
的东西也可以传递给println(Object)
,因此前者的方法比后者更具体。因此,这些将优先于 println(Object)
.
然而,一些可以传递给 println(char[])
的东西不能传递给 println(String)
,因此它们都不比另一个更具体,因此方法调用不明确。
现在查看编译错误2:
public <T>T getMethod (Stack<? extends Number >st)
{
return st.pop();
}
此方法必须在所有情况下都能安全调用。你这样调用它:
System.out.println(t.getMethod(stackNumber));
即您将结果简单地视为一个对象。但是你可以合法地在调用站点上写这个:
String s = t.getMethod(stackNumber);
很明显这会失败,因为从包含数字的堆栈中弹出的内容无法转换为 String
。
因为编译器不能保证它会被调用"safe" T
,这是一个错误。