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);