java - 在返回与其对象相同类型的值的 final方法中使用泛型

标签 java hierarchy class-hierarchy generics

考虑以下不可变类:

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

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

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 { }

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

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.

    }

我想修改源代码以将那些运行时错误转换为编译时错误或警告,而不必重载或覆盖进程 方法。

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

编辑: 这个问题没有真正的解决方案。所以我接受了关于覆盖 process 方法的明显答案。这是最适合客户端代码的方法,即使它是维护的噩梦。也许有一天可以修改 Java 类型系统,以便可以编写“this 的类型”。然后我们可以写类似public final this process(A a)的东西。请参阅 this page 中的建议(在评论部分)如果您有兴趣。

最佳答案

使用自引用类型:

public class A<T extends A<T>>{

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

public class B<T extends B<T>> extends A<T>{ }

public class C extends B<C> { }

要避免在客户端代码中完全使用泛型参数,您必须创建第二组泛型类,其固定类型实现为 A、B、C 等,如下所示:

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

public class BaseB<T extends BaseB<T> extends BaseA<BaseB<T>> {}

public class B extends BaseB<B> {}

public class C extends BaseB<C> {}

这里的问题是 b instance A 不会为真,但它可能感觉足够接近以至于客户端代码不会关心。

关于java - 在返回与其对象相同类型的值的 final方法中使用泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29188497/

相关文章:

java - Java 是否提供了一种允许从层次结构中的包进行特殊访问的方法?

java - 在 Spring Boot 中添加依赖文件后,我有/newart.jsp 抛出我犯错误的地方

qt - 在异构数据层次结构的不同 View 之间拖放

jquery - 将一个 div 放入另一个 div 中,用一条线将两者连接起来

javascript - 如何从以下 xml 制作层次结构数组?

java - 如何选择在 Eclipse 的类层次结构中显示哪个类?

java - 如何使用 apache-camel 构建管道和过滤器 eip 模式

java - RESTeasy/JAXB 的 JSON 解析错误

java - OSX 中的 SWT 系统托盘

scala - 如何在也只接受子类的 Scala 中进行结构类型化?