当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,这是一个错误。