Вопрос по java, generics – Есть ли способ сказать «метод возвращает это» в Java?

5

Есть ли способ сказать "этот метод возвращаетthis "используя Дженерикс?

Конечно, я хочу переопределить этот метод в подклассах, поэтому объявление должно хорошо работать с@Override.

Вот пример:

class Base {
    public Base copyTo (Base dest) {
        ... copy all fields to dest ...
        return this;
    }
}
class X extends Base {
    @Override
    public X copyTo (X dest) {
        super.copyTo (dest);
        ... copy all fields to dest ...
        return this;
    }
}

public <T extends Base> T copyTo (Base dest) не работает вообще: я получаю "Несоответствие типов: не могу конвертировать из базы в T". Если я приведу его к исполнению, переопределение завершится неудачей.

Ваш Ответ

3   ответа
4

это невозможно выразить. Просто объявите метод для возврата типа класса. Java имеет ковариантные возвращаемые типы, так что вы можете переопределить метод, чтобы в любом случае возвращать более конкретный тип.

Если вы хотите иметь какой-то маркер для этого, вы всегда можете ввести свою собственную аннотацию - но не ожидайте, что другие инструменты заметят это.

EDIT: ответ от oxbow_lakes действительно дает что-то, что будет работать в большинстве случаев, но я считаю, что есть способы обмануть его так, что вы на самом деле имеете дело с другим типом. (Во всяком случае, из воспоминаний об экспериментах.) Обратите внимание, что это похоже на работу перечислений Java.

Да, хотя есть способы реализации такого рода вещей без "This"на самом дел Быть этим. Jon Skeet
Отойди от моего (ну, Мартина Одерского) пути; подробно выше oxbow_lakes
Ну, «Это» может быть чем угодно, что реализует интерфейс List <A>, который из-за стирания может быть списком чего угодно. Мне было бы интересно, если бы вы могли обмануть это полностью oxbow_lakes
@ oxbow_lakes: звучит как интересный вызов. Как насчет того, чтобы определить его более точно, прежде чем я приступлю к делу ... мы просто пытаемся создать допустимую реализацию без каких-либо необработанных типов, но где класс - Foo, а метод add возвращает тип, отличный от Foo? Jon Skeet
5

что они сделали в Scala с 2.8 рамки коллекции). Объявите некоторый метод интерфейса, который должен возвращать «себя» Заметка This - это параметр типа, а не ключевое слово!)

public interface Addable<T, This extends Addable<T, This>> {
   public This add(T t);
}

Теперь объявите уровень косвенности - класс "шаблон"

public interface ListTemplate<A, This extends ListTemplate<A, This>> 
    extends Addable<A, This>{
}

public interface List<A> extends ListTemplate<A, List<A>> {
}

Затем реализацияList должен вернутьList отadd метод (я позволю вам заполнить детал

public class ListImpl<A> implements List<A> {

    public List<A> add(A a) {
        return ...
    }
}

Точно так же вы могли бы объявитьSetTemplate иSet чтобы продлитьAddable интерфейс -add метод которого вернул быSet. Круто, да

Ницца. Но не работает, когда я расширяю ListImpl. Aaron Digulla
Он делает, когда я пытаюсь: SubListImpl <A> расширяет ListImpl <A> и добавляет возвращает SubListImpl <A> без проблем компиляции вообще oxbow_lakes
Как я могу заставить add () принимать только это? Aaron Digulla
Обратите внимание, что есть разница между «это» и «это». В Java нет способа заставить конкретный экземпляр быть возвращенным из метода; Вы можете только сказать, что определенный тип должен быть возвращен. Невозможно принудительно заставить переопределенный метод возвращать подтип; ему нужно только вернуть тип, соответствующий методу, который он переопределяет. Мой пример был хитрым трюком, использующим слой косвенности, чтобы он выглядел так, как будто должен быть возвращен подтип. Однако существует только один уровень косвенности, поэтому его нельзя использовать для дальнейшего ограничения подтипов ListImpl oxbow_lakes
0

abstract class Foo<T> {

    Foo<T> get() {
        return this.getClass().cast(this);
    }
}

class Bar extends Foo {

    @Override
    Bar get() {
        return (Bar) super.get();
    }
}
Если вы это сделаете, вы получите непроверенные предупреждения типа от javac oxbow_lakes
javac (jdk6) не дает мне никаких предупреждений. Я что-то упустил? dfa
Должно быть, вы расширили универсальный класс (Foo <T>), но не указали никаких параметров типа (Bar расширяет Foo) oxbow_lakes
Возможно, у вас установлен флажок --Xl: int (или oxbow_lakes
ты прав, я буду держать этот (неправильный) ответ для будущих поколений:) dfa

Похожие вопросы