泛型类方法的Java静态返回类型被类型擦除了?

问题描述 投票:0回答:1

假设我有一个通用类:

public class GClass implements GInterface<Impl> {
// other code
  @Override
  public Class<SomeClass> getType() {
    return SomeClass.class
  }
}

实现接口:

public interface GInterface<T extends OtherClass> {
// other code
  return Class<SomeClass> getType();
}

然后我调用 getType():

GInterface<?> gi = getInstance();
Class<SomeClass> type = gi.getType(); // <- gives warning

我在这里收到警告有何意义?

getType()
的结果不是泛型的(它不使用泛型类型参数 T),而是静态定义为
Class<SomeClass>
。因此编译器应该知道
Class<SomeClass> type = gi.getType()
是 100% 安全的,对吗?

我错过了什么吗?

我希望调用:

Class<SomeClass> type = gi.getType()
不会生成任何警告。

java generics type-erasure
1个回答
0
投票

在 Java 中,泛型类型是不变的,这意味着即使 SomeClass 是

OtherClass
的子类型,
Class<SomeClass>
也不是
Class<OtherClass>
的子类型。这就是为什么您不能在没有警告的情况下直接将
gi.getType()
返回
Class<SomeClass>
分配给
Class<OtherClass>
类型的变量。

但是,您提供的代码片段包含一些不一致的地方,无法按原样编译。

getType
中的
GInterface
方法应该有一个与其定义一致的返回类型。

这是根据您提供的内容进行更正的版本:

public interface GInterface<T extends OtherClass> {
    Class<? extends OtherClass> getType();
}

public class GClass extends OtherClass implements GInterface<SomeClass> {
    @Override
    public Class<SomeClass> getType() {
        return SomeClass.class;
    }
}

在上面的代码中,

GInterface
中的getType返回一个代表
OtherClass
子类的Class对象。当您重写
GClass
中的 getType 时,您可以指定确切的子类,在本例中为 SomeClass。

现在,当你调用 getType 时:

GInterface<?> gi = getInstance(); // Assuming getInstance() is defined elsewhere and returns an instance of GClass
Class<? extends OtherClass> type = gi.getType(); // This should not give a warning

在这种情况下,

Class<? extends OtherClass>
告诉编译器您期望一个代表OtherClass的某个子类的Class对象,但您没有指定它是什么子类。由于
SomeClass
OtherClass
的子类,因此该分配是安全的,并且不应该出现警告。

如果您看到警告,可能是因为

getInstance()
的定义方式或此处未显示的其他代码。上面更正的代码不应针对将
gi.getType()
分配给类型变量产生警告。如果
getInstance()
返回 GInterface,则意味着类型参数未知,因此
getType()
的返回类型在编译时也将是未知的,即使该方法的签名表明它将返回代表某个子类的 Class 对象
OtherClass

如果您控制

GInterface
并且您确定 getType 将始终返回
Class<SomeClass>
,您可以像这样定义 GInterface 以避免警告:

public interface GInterface<T extends OtherClass> {
    Class<T> getType();
}

然后,在实现这个接口的时候,指定具体的类型:

public class GClass implements GInterface<SomeClass> {
    @Override
    public Class<SomeClass> getType() {
        return SomeClass.class;
    }
}

这样,

GInterface
中的方法签名使用泛型类型参数T,并且实现类
GClass
指定T是
SomeClass
。这应该可以消除调用 getType 时与类型安全相关的任何警告。

© www.soinside.com 2019 - 2024. All rights reserved.