Java 通用拼图

Java Generic puzzle

我有 Java classes:

abstract class Parent {
    abstract void test(Object pObject, Map<String, Object> pData);
}

public class Test extends Parent {
    @Override
    void test(Object pObject, Map<String, Object> pData) {
    }
}

并想将代码重构为:

abstract class Parent<T> {
    abstract void test(T pObject, Map<String, Object> pData);
}

public class Test extends Parent {
    @Override
    void test(Object pObject, Map<String, Object> pData) {
    }
}

Eclipse(4.4.2 如果重要的话)告诉我测试 class 中的代码无效(编译时错误)并且正确的 test() 方法签名必须是:

@Override
void test(Object pObject, Map pData) {
}

我的问题是为什么!?

实际上,真实的故事要长一些。我有很多 children class(如测试),不想更改它们,更喜欢使用通用的(即 <T> class)新 [= Parent class 的 31=]。在这两种情况下,test() 方法的第二个参数必须是 Map<String, Object>

有什么想法吗?

My question is WHY!?

当您扩展 Parentraw 版本时,class 中的所有通用信息都会被忽略。因此,您正在扩展一个 Parent,它看起来像:

abstract class Parent {
    abstract void test(Object pObject, Map pData);
}

为了保留 Map 参数的类型参数,您可以指定扩展 Parent<Object>。现在这段代码应该可以正常编译了:

public class Test extends Parent<Object> {
    @Override
    void test(Object pObject, Map<String, Object> pData) {
    }
}

在第一个例子中,Parent 是一个普通的 class 并且您已经按照预期的方式对其进行了子类化,一切都很好。

在第二个示例中,您没有扩展 Parent<T>,而是扩展了已删除的泛型 Parent,它从 class 中删除了所有泛型,即使它们不涉及 [=14] =].

尝试

public class Test extends Parent<Object> {
    @Override
    void test(Object pObject, Map<String, Object> pData) {
    }
}

我看到到达您想要的位置的唯一方法是保持 Parent class 不变,并引入另一个 class 为您提供模板功能,如下所示:

abstract class TemplatedParent<T> {
    abstract void test(T pObject, Map<String, Object> pData);
}

abstract class Parent extends TemplatedParent<Object> {}

这样您可以保留旧代码,而需要模板功能的新代码必须直接扩展 TemplatedParent