我在使用多个通配符
的通用方法获取语法时遇到了问题首先我需要两个不同的通配符,因为(虽然我已经看到'?'可以用来表示两种不同的类型)编译器在使用'?'时会怎么知道方法中含糊不清。
所以下面我有非常非法的版本,我使用'*'作为第二个通配符(我可以使用其他一些通配符吗?)
似乎方法中存在编程错误但我可以从类型'*'构造类型'T'(我有这样的构造函数 - 基本上将Google协议缓冲区放入并制作一个“完全成熟的对象” “出于它”
private <T, ? extends Database<*>, * extends GeneratedMessage> T getItem(String key, ? db, Hashtable<String, T> table, String message) throws GadsDataException {
T returnValue = table.get(key);
if (returnValue == null) {
* temp = null;
try {
temp = db.get(key);
}
catch (InvalidProtocolBufferException e) {
throw new GadsDataException( message + key + " and hit: ", e);
}
if (temp != null) {
returnValue = new T(temp);
table.put(key, returnValue);
}
}
return returnValue;
}
在绝望中我尝试了一个没有任何通配符的版本(我不喜欢它,因为它不像第一个那样保留类型关系)。但编译器也不太关心它。我想我应该看看另一张海报上提到的“变形金刚”的事情。
private <T, D, G> T getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
T returnValue = table.get(key);
if (returnValue == null) {
G temp = null;
try {
temp = db.get(key);
}
catch (InvalidProtocolBufferException e) {
throw new GadsDataException( message + key + " and hit: ", e);
}
if (temp != null) {
returnValue = new T(temp);
table.put(key, returnValue);
}
}
return returnValue;
}
所以我仍然坚持构造函数(正如其他海报所表明的那样)。我尝试通过制作一个'人工'基类
来让编译器感到高兴/**
* This is created as a base class for all objects that can
* construct themselves from a Google Protocol Buffer with one
* parameter.
*
* This is just done for the sake of templatizing the methods
* inside of the GadsLite API
*
*/
public class ConstructorOneParameter {
ConstructorOneParameter(GeneratedMessage G) {
// don't actually do anything... the derived
// class does all the work
// We're doing this just to templatize the GadsLite methods
}
}
然后我用它来识别模板方法中的类型。编译器仍然不高兴。
private <T extends ConstructorOneParameter, D extends Database<G>, G extends GeneratedMessage> T
getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
T returnValue = table.get(key);
if (returnValue == null) {
G temp = null;
try {
temp = db.get(key);
}
catch (InvalidProtocolBufferException e) {
throw new GadsDataException( message + key + " and hit: ", e);
}
if (temp != null) {
returnValue = new T(temp);
table.put(key, returnValue);
}
}
return returnValue;
}
有几个人建议工厂,所以我更改了行“returnValue = new T(temp);” into“returnValue = MessageObjectFactory create(temp);”然后对于工厂我有:
public class MessageObjectFactory {
public static <G extends GeneratedMessage, R extends Object> R create(G message) {
R returnValue = null;
if (message instanceof ArtccData.Artcc) {
returnValue = new Artcc((ArtccData.Artcc)message);
}
return returnValue;
}
}
我现在正在做一种类型作为概念证明。不幸的是,即使所有内容都是Object的子类,编译器也不满意“returnValue = new Artcc(...”行抱怨“无法从Artcc转换为R”。是否有“变压器工厂”的具体示例?
答案 0 :(得分:1)
首先关闭 - 在通用参数部分中声明通配符(?
)时,绝对零点。该部分用于声明您将在实际方法签名中引用的类型变量&amp;身体。如果你在那里放一个通配符,你显然不能引用它们 - 如果你没有引用它们,它们就不属于通用参数(因为你的方法不会根据它们的值而变化)。 / p>
你问
当我使用'?'时,编译器将如何知道?方法中含糊不清。
我觉得很困惑。很明显它不会,正是为什么你在通用参数块中给出了类型名称!
因此,在第一个示例中,您尝试使用通配符完成了什么?如果您将?
替换为U
而*
替换为V
(显然实际字母是任意名称),为什么不会起作用,如:
private <T, V extends GeneratedMessage, U extends Database<V>> T getItem(String key, U db, Hashtable<String, T> table, String message) throws GadsDataException {
...
V temp = null;
...
}
(您可能会注意到我切换了后两个参数的顺序 - 不允许前向引用,因此V
必须出现在依赖于它的U
之前。
这类似于第二个示例,除了它维护数据库和消息参数类型的约束。编译器对你的版本不喜欢什么?
答案 1 :(得分:1)
首先,你必须找到比
更好的方法new T(...)
因为这是不允许的
答案 2 :(得分:1)
由于我的所有类型T都有
T(G)
形式的构造函数,我不明白为什么我不能new T(temp)
。我还编辑了原始问题,以显示上一条评论中描述的失败黑客。
Java泛型是一种保证类型安全的工具,而不是根据参数创建不同的代码。编译器擦除大多数类型变量,因此在运行时实际类型T
根本不知道 - 因此我们不能调用它的任何构造函数(或创建此类型的数组,方式)。通过这种方式,我们可以将泛型方法(或类)与创建方法时尚不存在的类型一起使用。
实际上,编译器无法保证所有可能的类都有这样的构造函数,因为以后的子类总是没有。
因此,在您的情况下,您应该考虑使用某种工厂对象,它需要G
并返回正确的T
对象,(例如Transformer<G, T>
类型,就像Andrzej提出的那样。)