Java 如何避免;“类型不匹配”;在静态通用工厂方法中?
要么我太蠢了,不能使用谷歌,要么到目前为止还没有人遇到这个问题 我正在尝试编译以下代码:Java 如何避免;“类型不匹配”;在静态通用工厂方法中?,java,generics,generic-method,Java,Generics,Generic Method,要么我太蠢了,不能使用谷歌,要么到目前为止还没有人遇到这个问题 我正在尝试编译以下代码: public interface MyClass { public class Util { private static MyClass _this; public static <T extends MyClass> T getInstance(Class<T> clazz) { if(_this == null) { try {
public interface MyClass {
public class Util {
private static MyClass _this;
public static <T extends MyClass> T getInstance(Class<T> clazz) {
if(_this == null) {
try {
_this = clazz.newInstance();
} catch(Exception e) {
e.printStackTrace();
}
}
return _this;
}
}
}
公共接口MyClass{
公共类Util{
私有静态MyClass_this;
公共静态getInstance(类clazz){
如果(_this==null){
试一试{
_this=clazz.newInstance();
}捕获(例外e){
e、 printStackTrace();
}
}
把这个还给你;
}
}
}
但是,在“return\u this”行中,“我得到错误”类型不匹配:无法从MyClass转换为T
为什么会这样?T扩展了MyClass,那么问题出在哪里?如果我将行更改为“return(T)_this;”,我只会收到一个关于未选中强制转换的警告,但我不喜欢警告;-)有没有一种方法可以在没有错误或警告的情况下实现我想要的功能?这是因为变量
\u this
的类型是MyClass
,而不是T
。即使它碰巧包含一个T
的实例,编译器也无法知道这一点。类型不匹配。。。
…原因如下:
MyClassImpl1 o1 = MyClass.Util.getInstance(MyClassImpl1.class);
// _this now holds a value of type MyClassImpl1...
// ... which causes this line to throw a ClassCastException.
MyClassImpl2 o2 = MyClass.Util.getInstance(MyClassImpl2.class);
表示T
的子类MyClass
声明为返回类型为getInstance
T
- 它返回类型为
的对象MyClass
Double
,同时返回一些Number
解决方案。。。
。。。是将return语句更改为
return (T) _this;
(如果要消除警告,请添加@SuppressWarnings(“未选中”)
)
但是有个问题。。。
正如科林指出的:假设你有
class MyClassImpl1 implements MyClass {
}
class MyClassImpl2 implements MyClass {
}
并执行以下操作:
MyClassImpl1 o1 = MyClass.Util.getInstance(MyClassImpl1.class);
// _this now holds a value of type MyClassImpl1...
// ... which causes this line to throw a ClassCastException.
MyClassImpl2 o2 = MyClass.Util.getInstance(MyClassImpl2.class);
我刚刚验证了这会使编译器满意,并且仍然以您想要的方式约束类型:
public interface MyClass {
public class Util {
private static MyClass _this;
public static MyClass getInstance(Class<? extends MyClass> clazz) {
if(_this == null) {
try {
_this = clazz.newInstance();
} catch(Exception e) {
e.printStackTrace();
}
}
return _this;
}
}
}
假设您有两个
MyClass
、Foo
和Bar
的实现。作为类型为MyClass
的字段,\u该
可以是Foo
或Bar
现在,由于您的getInstance
方法返回
,因此可以通过以下任何方式调用它:
MyClass myClass = Util.getInstance(MyClass.class);
如果这是第一次调用,则此操作不起作用,因为MyClass
是一个接口,不能用newInstance()
实例化
现在,如果
\u this
是Foo
的一个实例,并且您调用了Util.getInstance(Bar.class)
,会发生什么?这就是为什么你不被允许这样做。你到底想在这里完成什么?命名一个静态变量\u这听起来像是在要求trouble@MatrixFrog-唉,我希望在接口中有一个工厂,这样我就不必为每个实现子类编写工厂了。你现在可以笑了;-)@马特b:命名一个接口MyClass也是自找麻烦!但是,该方法显式返回一个MyClass
的实例,而客户端则必须在外部执行强制转换,是吗?@aioobe:如果他们真的进行了强制转换,就会有一个ClassCastException
等待发生。我的假设是客户端代码将返回值分配给类型为MyClass
的对象。我不明白。如果您说getInstance
返回一个MyClass
,那么您必须将结果转换为外部所需的类型。为什么不说它返回一个t
并在内部执行强制转换?@aioobe:如果您只调用MyClass
方法,那么就没有必要在客户端执行强制转换。如果没有看到客户端代码,我们就不可能知道用例。实际上,进一步看,我发现MyClass
是一个空接口。。。隐马尔可夫模型。。。我认为整个例子有点不完整(见我的最新编辑);方法签名取决于它能做什么。嗯。。你能解释一下你的意思吗?(如果我在这里慢了,请原谅。)对不起。我刚刚第三次读了你的答案,我明白你的意思。。。我会更新我的答案。哇,看起来我在推理上犯了一个很大的错误。考虑到这一点,它无论如何都不会按我想要的方式工作。谢谢你的解释。我有一点挑剔;你说“假设你有两个子类MyClass
”。既然MyClass
实际上是一个接口,而不是一个类,你能把“子类”这个词改成“实现”吗?然后在下一句中,你继续说“\u此
可以是MyClass
、Foo
或Bar
。但事实上,它总是一个MyClass
。除了作为一个MyClass
,\u这个可以是一个Foo
或Bar
@asah:Good point。我的解释把MyClass看作是一个具体的类。作为一个接口,它还引发了另一个问题,我已经编辑了我的回答,为您辩护,这个接口被称为MyClass。
Foo foo = Util.getInstance(Foo.class);
Bar bar = Util.getInstance(Bar.class);