Я наткнулся на любопытство в наследовании Java, и я хотел, чтобы вы спросили об этом:
Предположим, два интерфейса A и A1
Интерфейс A1 расширяет A
В интерфейсе A есть метод, который возвращает универсальный тип.
Универсальный тип будет выглядеть как GenericType<T>
.
Основная идея состоит в том, чтобы изменить этот универсальный тип возврата сGenericType<Object>
в интерфейсе A в GenericType<String>
в интерфейсе A1
Поначалу кажется, что все просто (плохие вещи появятся позже)
Мы объявляем интерфейс A как
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
и интерфейс А1, например
public interface InterfaceA1 extends InterfaceA
{
@Override
public GenericType<String> getAGenericType();
}
Как вы видите, мы вынуждены написать GenericType<? extends Object>
в самом интерфейсе А, чтобы разрешить переопределение его общими «подклассами».(На самом деле универсальный параметр универсального типа находится в подклассе, а не сам универсальный тип)
Теперь предположим, что GenericType имеет свой собственный метод, похожий на:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Теперь попытка создания экземпляра A1 прекрасно работает,
Скорее, попытка создать экземпляр A будет отстойной.Чтобы понять, зачем смотреть на этот класс «use interface»:
public class LookAtTheInstance
{
@SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
Вы спрашиваете: «А сейчас?»
Он не работает на последних строках.На самом деле параметр «что-то» даже не из типа «Объект», а из Типа «расширяет Объект».Таким образом, вы не можете передать объявленный тип «Объект».Вы вообще ничего не можете передать.
Таким образом, вы в конечном итоге объявляете о хороших интерфейсах, которые, как выясняется, не могут быть правильно созданы.
У вас есть идеи, как смоделировать такое использование?случай, когда подклассы должны будут переопределить тип возвращаемого значения, в то время как тип возвращаемого значения является универсальным?
Или как бы вы обходили такой типовой случай?
Или я просто пропускаюпростая точка в обобщенном объявлении, и мой пример возможен таким образом?
----------- (1) изменить из-за ответов -----------
Очень хорошая базовая идея - сделать интерфейс более абстрактным!Сначала у меня была точно такая же идея, но ... (это должно прийти)
Предположим, что вы делаете это:
Мы представляем новый интерфейс AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Теперьнам придется расширить A и A1 из этого нового интерфейса:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
Это прекрасно работает, хотя и нарушает путь первоначального наследования.
Если мы хотим, чтобы A1 все еще можно было расширять изA, мы должны изменить A1 на
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
, и проблема снова возникает.Это не работает, так как мы косвенно расширяем один и тот же интерфейс различными универсальными типами.К сожалению, это не разрешено.
Вы видите проблему?
-
И указать на другое обстоятельство:
Если вы разыгрываете GenericType<? extends Object>
к GenericType<Object>
это, очевидно, работает.Пример:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
@Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
@Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
@SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
Так что мне кажется, что разрешение типа параметра метода
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
неверно.
Если D объединено с "«расширяет объект», почему тип параметра не обязательно должен быть «объектом»?
Разве это не создает больше смысла?