Конфликт между типом возвращаемого значения и параметром метода, когда тип возвращаемого значения равен «T», а параметр метода состоит из подстановочного знака - PullRequest
1 голос
/ 12 ноября 2019

Я пытаюсь запустить код. я и я получаю две ошибки компиляции: 1. Ссылка на 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, чтобы вернуть число, и программа будет успешно скомпилирована, но я хочу понять, почему с текущей подписью я получаю ошибки компиляции? AFAIK, T без границ рассматривается как Object и функция, которая объявляет о возвращении Object , может возвращать любой объект, поскольку Object является «отцом» всех классов (включаяНомер). Может кто-то мне, что я здесь уволить?

Ответы [ 2 ]

1 голос
/ 12 ноября 2019

но я хочу понять, почему с текущей подписью я получаю ошибки компиляции?

Ошибки обе, потому что <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.

Поскольку компилятор не может гарантировать, что он будет вызываться с "safe" T, это ошибка.

1 голос
/ 12 ноября 2019

Ни один из ваших методов не должен использовать подстановочные знаки, у вас есть два метода, которые являются общими для некоторого 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();
}
...