вернуть это из обобщенного метода, обобщенного с - PullRequest
0 голосов
/ 08 декабря 2018

Почему я не могу сделать это в Java:

public class TestClass {

    public <T extends TestClass> T test(){
        return this; // error here
    }
}

Как я понимаю, this всегда будет экземпляром некоторого класса, который расширяет TestClass, поэтому почему приведенный выше код неразрешено компилятором?Даже если я увеличу TestClass, тогда тип this все равно будет соответствовать extends TestClass.Я получаю следующую ошибку:

Ошибка: (4, 16) Java: несовместимые типы: TestClass не может быть преобразован в T

Ответы [ 3 ]

0 голосов
/ 08 декабря 2018

вы что-то неправильно понимаете:

Как я понимаю, this всегда будет экземпляром некоторого класса, расширяющего TestClass

Это не так, this может быть экземпляром самого TestClass.И вот почему компилятор сломался.Чтобы исправить это, вы должны привести this к T:

return (T) this;

Редактировать 01:

Кстати, если вы хотите что-то сделатьвот так, я бы также порекомендовал вам добавить один из этих двух параметров, чтобы предотвратить RuntimeError:

  • установить TestClass в качестве абстрактного класса
  • , убедиться, что thisне экземпляр TestClass, вы можете сделать это примерно так: this.getClass().equals(TestClass.class)

Надеюсь, это поможет.

0 голосов
/ 08 декабря 2018

«this» представляет класс «TestClass», потому что TestClass - это суперкласс T. Суперкласс нельзя преобразовать в подкласс, но вы можете попробовать принудительное преобразование типа или установить тип возвращаемого значения «TestClass».

public <T extends TestClass> T test() {
    return (T)this;
}

edit 01: принудительное приведение неверно, это может вызвать ошибки во время выполнения.

0 голосов
/ 08 декабря 2018

Скажем, у вас есть SubTestClass extends TestClass, и вы пишете:

TestClass instance = new TestClass();
SubTestClass result = instance.test();

Это законно в отношении подписи вашего test() класса, хотя это чепуха (1).Компилятор выведет, что T - это класс SubTestClass.И тогда становится ясно, что экземпляр TestClass не instanceof SubTestClass.Таким образом, при легальном использовании вашего метода test() возвращение this может привести к несовпадению типов, и это то, что говорит вам компилятор.

С вашей подписью test() невозможно вернуть что-либо, кроме null, потому что null - единственное значение, которое вы можете присвоить переменной неизвестного типа.

Позвольте мне объяснить последнее утверждение (запрошено в комментариях): реализация метода test() должна возвращать некоторое значение, которое соответствует типу T, и конкретный тип (выведенный из ситуации вызовазначение SubTestClass) не выводится для метода - в аргументах или в полях экземпляра нет ничего, что могло бы считывать требование вернуть SubTestClass в этой ситуации.В другой ситуации вызова может потребоваться вернуть AnotherSubTestClass, и он никак не может отличить первое от второй ситуации.

Если вы вернете this (с использованием приведения (T), чтобы сделать егопередать компилятор), он потерпит неудачу ни в первом, ни во втором, ни в обеих ситуациях.Таким образом, вы не можете сделать это без высокого риска сбоя.

Единственное значение, которое вы можете успешно назначить для переменных SubTestClass и AnotherSubTestClass, это значение null.Так что это единственное значение, которое вы можете безопасно вернуть из метода с такой сигнатурой.

(1) Наличие универсального метода, в котором универсальный тип не может быть выведен из параметров, а только из ожидаемого результата.типа, вряд ли может работать - как метод должен знать, что ожидает вызывающая сторона?

...