Omn*_*est 13 java generics methods types return
我偶然发现了java继承的好奇心,我希望你能提出更好的想法:
假设有两个接口A和A1
接口A1扩展A.
接口A有一个返回泛型类型的方法.
通用类型就像GenericType<T>.
现在,一个基本思想是将此通用返回类型从GenericType<Object>接口A 更改
为
GenericType<String>接口A1
好吧一开始似乎很容易(后来会出现不好的事情)
我们声明接口A之类的
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
Run Code Online (Sandbox Code Playgroud)
和接口A1一样
public interface InterfaceA1 extends InterfaceA
{
@Override
public GenericType<String> getAGenericType();
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我们被迫GenericType<? extends Object>在接口A本身中编写,以允许使用基于泛型的"子类"覆盖它.(实际上,generictype的泛型参数是子类,而不是泛型类型本身)
现在假设GenericType有自己的方法,如下所示:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Run Code Online (Sandbox Code Playgroud)
现在尝试实例化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 );
}
}
Run Code Online (Sandbox Code Playgroud)
你问:"现在?"
它不适用于最后一行.实际上,参数"something"甚至不是来自"Object"类型,它来自Type"?extends Object".所以你不能传递声明的"对象"类型.你根本无法传递任何东西.
所以你最终声明了很好的接口,事实证明,它无法正确实例化.
您是否有想法如何建模这样的用例,其中子类必须覆盖返回类型,而返回类型是泛型?
或者你会如何解决这种模型案例?
或者我只是错过了泛型声明中的一个简单点,我的例子可能就是这样吗?
-----------(1)因答案编辑-----------
一个非常好的基本想法是使界面A更抽象!我首先有完全相同的想法,但......(这必须到来)
假设这样做:
我们引入了一个新的接口AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Run Code Online (Sandbox Code Playgroud)
现在我们必须从这个新界面扩展A和A1:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
Run Code Online (Sandbox Code Playgroud)
这很好,虽然它打破了原始继承的道路.
如果我们希望A1仍然可以从A扩展,我们必须将A1更改为
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
Run Code Online (Sandbox Code Playgroud)
又有一个问题.这不起作用,因为我们间接扩展了具有不同泛型类型的相同接口.遗憾的是,这是不允许的.
你看到了问题?
-
并指出另一种情况:
如果你投的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 );
}
}
Run Code Online (Sandbox Code Playgroud)
所以对我来说似乎解析了方法的参数类型
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
Run Code Online (Sandbox Code Playgroud)
是错的.
如果D与"?extends Object"统一,为什么参数类型不被强制为"Object"?
这不是更有意义吗?
现在的基本思想是将此通用返回类型从接口A中的GenericType更改为接口A1中的GenericType
这是不可能的,因为Java Generics是不变的.[1]
正如您所发现的,您不能有一个接口声明一个返回的方法,GenericType<Object>并在子接口中覆盖要返回的方法GenericType<String>:后一个返回类型不是前者的子类型.并且有充分的理由!
你试过
使用不同的泛型类型间接扩展相同的接口.遗憾的是,这是不允许的.
有没有办法这样能够工作:比如应的类型E中public E set(int index, E element)在实现这两个类List<String>和List<Object>?您的子类接口必须生成类似的混合:getAGenericType子接口的返回值必须同时实现接口GenericType<String>和GenericType<Object>接口.正如我们所看到的,这是不可能的.
编译器不知道你要用type参数做什么GenericType(虽然它理论上可以找到,但它没有).如果你有一个类型的变量GenericType<String>并分配GenericType<Object>给它,你很可能最终将一个Long实例放在一个String预期的位置,并获得一个ClassCastException你不会期望的实例.
在doSomethingWith变量的方法中,GenericType<? extends Object> aGenericType2你可以传递一件事:null.null是唯一具有子类型的对象引用? extends Object.下限类型? extends Object是null类型,它不能用Java表示,只隐式存在作为null引用的类型.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java