从存储库加载后实例化生成的类

时间:2013-04-02 14:08:50

标签: java generics

在为存储库(例如Web服务或数据库)编写类型处理程序时,我需要在从存储库加载值之后实例化该类型。

假设我从存储库中获取String值,并且有一个构造函数,其中包含一个String参数。如果返回类型有一个类型参数,除了实例化原始类型之外我还能做什么?似乎原始类型只存在与遗留代码的兼容性,所以我不想使用它们。

通常?可以用作类型参数(如果你知道类型在运行时是正确的),但在这种情况下不能,因为你不能用通配符实例化类作为类型参数。

编辑:一些示例代码:

假设我有一个像这样的PrimaryKey类:

public class PrimaryKey<R extends RepositoryObject<R>> {
    private String value;
    public PrimaryKey(String value) {
        this.value = value;
    }
}

一组扩展RepositoryObject的类,其定义如下:

public class RepositoryObject<R extends RepositoryObject<R>> {
    private PrimaryKey<R> pk;
    public RepositoryObject(PrimaryKey<R> pk) {
        this.pk = pk;
    }
    PrimaryKey<R> getPrimaryKey() {
        return pk;
    }
}

子类的示例:

public class User extends RepositoryObject<User> {
    public User(PrimaryKey<User> userId) {
        super(userId);
    }
}

现在,类PrimaryKey的类型处理方法如下所示:

public PrimaryKey<?> getValue(String stringValue) {
    return new PrimaryKey<>(stringValue);
}

但这会导致编译器错误(在Maven构建中,在Eclipse IDE中不够奇怪),即使我使用的是菱形运算符而不是实例化时。由于某些原因,由于类型参数的递归,类型推断不能很好地工作。

2 个答案:

答案 0 :(得分:1)

在Java 7中,您通常可以使用diamond operator来绕过this limitation

Container<?> c = new Container<>(arg);

否则,您可以使用帮助工厂方法:

<T> Container<T> makeContainer(String arg) {
    return new Container<T>(arg);
}

...

Container<?> c = makeContainer(arg);

修改

在您更新后,我可以看到您正在使用递归类型参数<R extends RepositoryObject<R>>。此编译错误是由于javac在通配符捕获和递归类型参数方面的限制。请参阅此相关帖子,例如:Java CRTP and Wildcards: Code compiles in Eclipse but not `javac`

不幸的是,使用原始类型作为解决方法是必要的,但它可以隐藏为实现细节:

public PrimaryKey<?> getValue(String stringValue) {
    @SuppressWarnings("rawtypes") //a raw type is necessary to placate javac
    final PrimaryKey<?> pk = new PrimaryKey(stringValue);
    return pk;
}

答案 1 :(得分:0)

class SomeBogusClass extends RepositoryObject<SomeBogusClass> { }

return new PrimaryKey<SomeBogusClass>(stringValue);

严肃地说,你可以放任何满足界限的东西,甚至是一些与你的代码无关的虚假类。