本文介绍了Java - 当返回类型为自己的方法参数类型使用泛型时,覆盖扩展接口的返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了java继承中的好奇心,并且我希望你对此有更好的想法:假设两个接口A和A1 p>

接口A1扩展A

接口A有一个返回泛型类型的方法。 b

泛型类型将像 GenericType< T> 。



基本思想现在将这个泛型返回类型从接口A中的
GenericType< Object> 更改为
GenericType< String> code>在界面A1中



好吧,起初似乎很简单(不好的事情会晚一些的)

我们声明接口A就像

  public interface InterfaceA {
public GenericType< ;?扩展对象> getAGenericType();
}

和界面A1 like

  public interface InterfaceA1 extends InterfaceA 
{
@Override
public GenericType< String> getAGenericType();

$ / code>

正如你所看到的,我们被迫写了 GenericType< ?在接口A中扩展Object> ,允许使用基于泛型的子类覆盖它。
(实际上泛型类型的泛型参数不是泛型类型本身)现在假设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< ;?扩展对象> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith(something);


$ / code $ / pre

你问:现在呢?



它不适用于最后一行。实际上,参数something甚至不是从Type?extends Object类型的Object类型。所以你不能传递声明的Object类型。你完全不能传递任何东西。



所以你最终声明了一个很好的接口,事实证明它不能正确实例化。



你有什么想法来建模这样一个用例,其中子类将不得不重写返回类型,而返回类型是泛型?



或者你将如何绕过这样的模型案例?或者我只是在通用声明中遗漏了一个简单的点,我的例子可能是这样吗?

-----------(1)由于回答编辑-----------



一个非常好的基本想法是使界面A更抽象!我首先想到了完全一样的想法,但是......(这是必须的)



假设这样做:

我们引入了一个新的接口AGeneric

  public interface InterfaceAGeneric< T> {
public GenericType< T> getAGenericType();

$ / code>

现在我们必须从这个新界面扩展A和A1: p>

  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< Object> 显然起作用。
示例:

  public class LookAtTheInstance 
{
public static void main(String []] args)
{
InterfaceA a = new InterfaceA()
{
@Override
public GenericType< ;?扩展对象> getAGenericType()
{
返回新的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);




$ b $ p
$ b $ p所以我认为解决参数类型的方法


  public interface GenericType< D extends Object> 
{
public void doSomethingWith(D something);
}

是错误的。

如果D与?extends Object统一,为什么参数类型不会被强制为Object?

这样做会更有意义吗?


现在基本的想法是将接口A中GenericType的泛型返回类型改变为接口A1中的GenericType。

解决方案

/ p>

这是不可能的,因为 Java泛型不变。 [1]



正如你发现的那样,你不能有一个接口声明一个返回 GenericType< Object> 并在子接口中覆盖返回 GenericType< String> 的方法:后一种返回类型不是前者的子类型。并且有很好的理由!

您尝试过

这是不可能的:E.g.在一个实现了两个类的类中, public E set(int index,E element)中应该是 E 类型的类型 List< String> 和 List< Object> ?您的子类接口必须产生一个类似的混合类型:子接口中的 getAGenericType 的返回值必须同时实现 GenericType< String> 和 GenericType< Object> 接口。正如我们所看到的,这是不可能的。



编译器不知道你将如何处理 GenericType (尽管它在理论上可以发现,但它不)。如果你有一个 GenericType< String> 类型的变量,并为它分配了一个 GenericType< Object> 最后最好放置一个 Long 实例,其中需要一个 String ,并获得一个 ClassCastException 您不会期望的其中一个。



在您的变量 doSomethingWith code> GenericType< ;?扩展对象> aGenericType2 你可以传递一件事: null 。 null 是唯一具有子类型的对象引用?扩展Object 。 的下限类型? extends Object 是空类型,它不能用Java表示,只隐含地存在为 null 引用的类型。

[1]


i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:

Assume two interfaces A and A1

Interface A1 extends A

Interface A has a method which returns a generic type.

The generic type would be like GenericType<T>.

A basic idea is now to change this generic return type from GenericType<Object> in Interface A intoGenericType<String> in Interface A1

Well seems to be easy at first (bad things will come later on)

We declare Interface A like

public interface InterfaceA {
  public GenericType<? extends Object> getAGenericType();  
}

and Interface A1 like

public interface InterfaceA1 extends InterfaceA
{
  @Override
  public GenericType<String> getAGenericType();
}

As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses". (In fact the generic parameter of the generictype is subclassed not the generic type itself)

Now assume the GenericType has its own method looking like:

public interface GenericType<D>
{
  public void doSomethingWith( D something );
}

Now trying to instantiate A1 works great.

Rather trying to instantiate A will suck. To see why look at this "use the interface" class:

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 );
  }
}

You ask: "And now?"

It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.

So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.

Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?

Or how would you go around such a model case?

Or am I just missing a simple point in the generic declaration and my example is possible this way?

----------- (1) edit due to answers -----------

A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)

Assume doing this:

We introduce a new interface AGeneric

public interface InterfaceAGeneric<T>{
  public GenericType<T> getAGenericType();
}

Now we will have to extend A and A1 from this new interface:

public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}

That works fine, althought it breaks the path of the original inheritance.

If we want A1 still be extendable from A, we have to change A1 to

public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}

and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.

You see the problem?

-

And to point to another circumstance:

If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works. Example:

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 );
  }  
}

So it seems for me that the resolving of the parameter type of the method

public interface GenericType<D extends Object>
{
  public void doSomethingWith( D something );
}

is wrong.

If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?

Wouldnt this make more sence?

解决方案

This is not possible, because Java Generics are invariant. [1]

As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!

You tried to

There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.

The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.

In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.

[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java

这篇关于Java - 当返回类型为自己的方法参数类型使用泛型时,覆盖扩展接口的返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-12 08:23