在最终方法中使用泛型,该方法返回与其对象相同类型的值 [英] Use of generics in a final method that returns a value of the same type of its object

查看:169
本文介绍了在最终方法中使用泛型,该方法返回与其对象相同类型的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下不可变类:

  A 
B扩展A
C扩展B
D扩展C
...

类A有一个名为 process 获取类型为 A 的参数,然后返回调用对象类型的值:

  public class A {

public final< T extends A> T进程(A a){
Class clazz = getClass();
T result = createObjectOfType(clazz);
返回结果;



public class B extends A {}

public class C extends B {}

这是(非常简单的)测试代码:

  public void test()
{
A a = new A();
B b = new B();
C c = new C();

//返回类型A:

resultAAA = a.process(a); //工作。
resultAAB = a.process(b); //工作。
resultAAC = a.process(c); //工作。

B resultAAA = a.process(a); //运行时错误。
B resultAAB = a.process(b); //运行时错误。
B resultAAC = a.process(c); //运行时错误。

C resultAAA = a.process(a); //运行时错误。
C resultAAB = a.process(b); //运行时错误。
C resultAAC = a.process(c); //运行时错误。

//返回类型B:

resultBBA = b.process(a); //工作。
resultBBB = b.process(b); //工作。
resultBBC = b.process(c); //工作。

B resultBBA = b.process(a); //工作。
B resultBBB = b.process(b); //工作。
B resultBBC = b.process(c); //工作。

C resultBBA = b.process(a); //运行时错误。
C resultBBB = b.process(b); //运行时错误。
C resultBBC = b.process(c); //运行时错误。

//返回类型C:

resultCCA = c.process(a); //工作。
resultCCB = c.process(b); //工作。
resultCCC = c.process(c); //工作。

B resultCCA = c.process(a); //工作。
B resultCCB = c.process(b); //工作。
B resultCCC = c.process(c); //工作。

C resultCCA = c.process(a); //工作。
C resultCCB = c.process(b); //工作。
C resultCCC = c.process(c); //工作。


$ / code>

我想修改源代码来将这些运行时错误编译为编译时错误或警告,而无需重载或重写进程方法。



但是,客户端/测试代码不得更改(不包含强制转换或泛型参数)。

编辑:这个问题没有真正的解决方案。所以我接受了关于重写过程方法的明显答案。这对于客户端代码来说最适合,尽管这是一个维护噩梦。也许有一天Java类型系统可以被修改,以便可以写出这种类型。然后我们可以写一些类似于 public final这个过程(A a)。请参阅此页(在评论部分)如果你有兴趣的话。

自Java 5开始,用于在子类中重写的方法的变体返回类型。这意味着什么?



这意味着重写的方法的返回类型必须是原始方法的子类。这使得子类能够返回适当类型的类型而不是父类型。



假如你在A中有一个你想在子类B中使用的方法,但是你希望它返回一个B实例。使用这种模式:

  class A {
public A myMethod(){...}
}

class B extends A {
@Override public B myMethod(){...}
}
b
$ b

B类覆盖A类中的方法(如果需要,可以通过调用super.myMethod()来调用它,并返回一个B实例。这是允许的,因为B是A的一个子类型(并且在类设计语言中,B是一个A)。

Consider the following immutable classes:

A
B extends A
C extends B
D extends C
...

Class A has a method called process that gets a parameter of type A, and then returns a value of the type of the calling object:

public class A {

    public final <T extends A> T process(A a) {
        Class clazz = getClass();
        T result = createObjectOfType(clazz);
        return result;
        }
    }

public class B extends A { }

public class C extends B { }

This is the (very simple) test code:

public void test()
    {
    A a = new A();
    B b = new B();
    C c = new C();

    // Returns type A:

    A resultAAA = a.process(a); // Works.
    A resultAAB = a.process(b); // Works.
    A resultAAC = a.process(c); // Works.

    B resultAAA = a.process(a); // Runtime error.
    B resultAAB = a.process(b); // Runtime error.
    B resultAAC = a.process(c); // Runtime error.

    C resultAAA = a.process(a); // Runtime error.
    C resultAAB = a.process(b); // Runtime error.
    C resultAAC = a.process(c); // Runtime error.

    // Returns type B:

    A resultBBA = b.process(a); // Works.
    A resultBBB = b.process(b); // Works.
    A resultBBC = b.process(c); // Works.

    B resultBBA = b.process(a); // Works.
    B resultBBB = b.process(b); // Works.
    B resultBBC = b.process(c); // Works.

    C resultBBA = b.process(a); // Runtime error.
    C resultBBB = b.process(b); // Runtime error.
    C resultBBC = b.process(c); // Runtime error.

    // Returns type C:

    A resultCCA = c.process(a); // Works.
    A resultCCB = c.process(b); // Works.
    A resultCCC = c.process(c); // Works.

    B resultCCA = c.process(a); // Works.
    B resultCCB = c.process(b); // Works.
    B resultCCC = c.process(c); // Works.

    C resultCCA = c.process(a); // Works.
    C resultCCB = c.process(b); // Works.
    C resultCCC = c.process(c); // Works.

    }

I want to modify the source code to convert those runtime errors into compile time errors or warnings, without having to overload or override the process method.

However, the client/test code must not change (no casts or generic parameters).

Edit: There is no real solution to this question. So I accepted the obvious answer about overriding the process method. This is what works best for the client code, even though it's a maintenance nightmare. Maybe one day Java type system could be modified so that it would be possible to write "the type of this". Then we could write something like public final this process(A a). See the suggestion in this page (in the comments section) if you're interested.

解决方案

Since Java 5, your code is allowed to have co-variant return types for methods that are overridden in subclasses. What does this mean?

It means that the return type of an overridden method must be a subclass of the original method. This enables subclasses to return types that are of the appropriate type rather than the parent type.

Say you have a method in A that you want to use in subclass B, but you want it to return a B instance. Use this pattern:

class A {
    public A myMethod() { ... }
}

class B extends A {
    @Override public B myMethod() { ... }
}

Class B overrides the method in class A (it can invoke it, if needed, by making a call to super.myMethod()) and returns a B instance. This is allowed because B is a subtype of A (and in class design language, B -is an- A).

这篇关于在最终方法中使用泛型,该方法返回与其对象相同类型的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆