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