Java - 当返回类型为自己的方法参数类型使用泛型时,覆盖扩展接口的返回类型

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"?

这不是更有意义吗?

Chr*_*rau 6

现在的基本思想是将此通用返回类型从接口A中的GenericType更改为接口A1中的GenericType

这是不可能的,因为Java Generics是不变的.[1]

正如您所发现的,您不能有一个接口声明一个返回的方法,GenericType<Object>并在子接口中覆盖要返回的方法GenericType<String>:后一个返回类型不是前者的子类型.并且有充分的理由!

你试过

使用不同的泛型类型间接扩展相同的接口.遗憾的是,这是不允许的.

有没有办法这样能够工作:比如应的类型Epublic 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