0

我正在尝试运行代码。我和我得到两个编译错误: 1.ReferenceSystem.out.println不明确(获取 char[] 的方法和获取 String 的方法之间的冲突) 2.Cap#1 无法转换为 T 返回 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 签名以返回 Number 并且程序将被成功编译,但我想了解为什么使用当前签名会出现编译错误?AFAIK,无界限的 T 被视为Object和声明返回Object的函数可以返回任何 Object,因为Object是所有类(包括 Number)的“父亲”。有人可以让我在这里解雇我吗?

4

2 回答 2

1

您的任何一种方法都不应该使用通配符捕获,您有两种针对 some 通用的方法T。喜欢,

public <T> void setMethod(Stack<T> st, T t) {
    st.add(t);
}

public <T> T getMethod(Stack<T> st) {
    return st.pop();
}

如果您想确保由于某种原因T必须是 a (我会在那时使用),请将其定义为. 喜欢,NumberNumberT

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();
}
于 2019-11-11T23:51:42.833 回答
0

但我想了解为什么使用当前签名会出现编译错误?

错误都是因为<T>是在调用站点确定的。

查看编译错误1:

Java 选择最特别适用的方法。可以选择任何PrintStream.println采用引用类型参数的方法。

JLS 15.12.2.5 开始

非正式的直觉是,如果第一个方法处理的任何调用可以传递给另一个方法而不会出现编译时错误,那么一个方法比另一个方法更具体。

您可以传递给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.

因为编译器不能保证它会被“安全”调用T,所以这是一个错误。

于 2019-11-12T00:09:03.297 回答