在为存储库(例如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中不够奇怪),即使我使用的是菱形运算符而不是实例化时。由于某些原因,由于类型参数的递归,类型推断不能很好地工作。
答案 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);
严肃地说,你可以放任何满足界限的东西,甚至是一些与你的代码无关的虚假类。