Интерфейсы, обобщения и ковариантные типы возвращаемых данных

Предположим, у меня есть интерфейс следующим образом:

public interface Foo<T> {
    T doSomething();
}

Теперь разрешены оба следующих варианта?

public class Bar implements Foo<Number> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

С одной стороны, я, кажется, так не думаю, так как Bar2 "орудие Foo дважды ", хотя Integer это подкласс Number, С другой стороны, разве это не случай ковариантного типа возврата на doSomething()? Или компилятор не достаточно умен, чтобы обнаружить его как таковой?

2 ответа

Если Foo должен быть интерфейсом:

Класс не может быть одновременно подтипом двух типов интерфейса, которые являются разными параметризациями одного и того же универсального интерфейса [...], или возникает ошибка времени компиляции.

Так что нет. ( JLS 8.1.5)

И в любом случае это не имело бы смысла, потому что вы бы удручали Bar случается, чтобы вернуться из doSomething, Может быть, это Double,

С другой стороны, вы все равно можете сделать:

class Bar2 extends Bar {
    @Override
    public Integer doSomething() {...}
}

Или компилятор не достаточно умен, чтобы обнаружить его как таковой?

То, что мы и компилятор думаем, здесь не имеет значения. Компилятор привязан к спецификации языка, которая диктует ошибку.

Это не интерфейс, а класс (или абстрактный класс, в котором также отсутствует ключевое слово). abstract), это должно быть как:

public interface Foo<T> {
        T doSomething();
}

Кроме того

public class Bar implements Foo<Number> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

Даст вам ошибку времени компиляции, The interface Foo cannot be implemented more than once with different arguments: Foo<Number> and Foo<Integer>

Но если вы вместо этого сделаете:-

public class Bar implements Foo<Integer> { ... }

public class Bar2 extends Bar implements Foo<Integer> { ... }

Это не даст ошибку времени компиляции, и если вы реализуете doSomething() в Bar2 это будет учитываться, когда вы делаете:

Bar2 bar2=new Bar2();
bar2.doSomething();

или он будет работать doSomething() от Bar

и, очевидно, если вы делаете:-

Bar bar=new Bar();
bar.doSomething();

это будет учитывать doSomething() из Bar поскольку он имеет только один реализованный doSomething() на этот раз, т.е. Bar(который вы должны реализовать с Bar реализует интерфейс Foo:))

Другие вопросы по тегам