Я наткнулся на любопытство в наследовании java, и я хотел, чтобы вы попросили о нем лучшие идеи:
Предположим, что два интерфейса A и A1
Интерфейс A1 расширяет A
Интерфейс A имеет метод, который возвращает общий тип.
Общий тип будет выглядеть как GenericType<T>
.
Основная идея - теперь изменить этот общий тип возврата из
GenericType<Object>
в интерфейсе A в
GenericType<String>
в интерфейсе A1
Вначале кажется легким (плохие вещи придут позже)
Мы объявляем интерфейс A как
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
и интерфейс A1, например
public interface InterfaceA1 extends InterfaceA
{
@Override
public GenericType<String> getAGenericType();
}
Как вы видите, мы вынуждены писать GenericType<? extends Object>
в самом интерфейсе A, чтобы позволить переопределять его с помощью подклассов общего типа.
(Фактически, общий параметр универсального типа подклассифицирован не сам общий тип)
Теперь предположим, что у GenericType есть свой метод, похожий на:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Теперь попытка создания экземпляра A1 отлично работает.
Скорее попытка создать экземпляр A будет сосать. Чтобы узнать, почему вы посмотрите на этот класс "use the 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 );
}
}
Вы спрашиваете: "А теперь?"
Он не работает в последних строках. На самом деле параметр "что-то" даже не от типа "Объект", это от типа "? Extends Object". Таким образом, вы не можете передать объявленный тип "Объект". Вы ничего не можете передать.
Итак, вы в конечном итоге объявляете красивые интерфейсы, которые, как оказалось, не могут быть созданы правильно.
Есть ли у вас идеи о моделировании такого прецедента, когда подклассы должны будут переопределять тип возвращаемого значения, в то время как тип возвращаемого типа является обобщением?
Или как бы вы обошли такой пример модели?
Или я просто пропустил простую точку в общем объявлении, и мой пример возможен таким образом?
----------- (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 унифицирован с "? extends Object", почему тип параметра не является "Object"?
Разве это не станет более значимым?