简化代码示例
public class SomeBaseClass {
}
public class SomeClass extends SomeBaseClass {
}
public interface SomeInterface {
public <T extends SomeBaseClass> T someMethod();
}
public class BestClass implements SomeInterface {
// @SuppressWarnings("unchecked")
@Override
public SomeClass someMethod() {
return null;
}
}
更详细的代码示例
// Base config class
public class BaseConfigClass {
}
// Some interface for all config classes to implement
public interface SomeInterface {
public <T extends BaseConfigClass> T getConfig();
}
// Class 'A' Config
public class ClassAConfig extends BaseConfigClass {
public doThingOnlyClassAKnows() {
}
}
//Class 'A'
public class ClassA implements SomeInterface {
// @SuppressWarnings("unchecked")
@Override
public ClassAConfig getConfig() {
return null;
}
}
// Class 'B' Config
public class ClassBConfig extends BaseConfigClass {
public doThingOnlyClassBKnows() {
}
}
// Class 'B'
public class ClassB implements SomeInterface {
// @SuppressWarnings("unchecked")
@Override
public ClassBConfig getConfig() {
return null;
}
}
...
new ClassA().getConfig().doThingOnlyClassAKnows()
new ClassB().getConfig().doThingOnlyClassBKnows()
我有几个SomeClass
扩展SomeBaseClass
,其接口的返回类型为。{1}}。我正在使用<T extends SomeBaseClass>
来强制返回类型符合预期。
问题是Java对此不满意,并提供以下警告:
类型安全:类型为someMethod()的返回类型SomeClass BestClass需要未经检查的转换才能符合T的要求 输入SomeInterface
除了静音警告之外,我可以通过定义界面来避免这种情况:
public interface SomeInterface<T extends SomeBaseClass> {
public T someMethod();
}
但这最终会非常混乱,因为这个接口有几个方法,每个方法都实现不同的基类型;我最终得到了一个很长的implements
声明。
现在看来一切正常,但我觉得我的实现有点不对,因为我必须为这个接口定义的每个方法明确地抑制这个警告。
是否有一种干净的方式来设计这样的界面而没有警告,但不需要冗长的implements
声明?
答案 0 :(得分:2)
显示警告的原因是因为您的解决方案确实不是类型安全的。签名<T extends BaseConfigClass> T getConfig()
的方法可以返回BaseConfigClass的任何子类。特别是,以下代码将在没有警告的情况下编译:
SomeInterface a = new ClassA();
ClassBConfig bConfig = a.getConfig();
bConfig.doThingOnlyClassBKnows();
但会在运行时抛出ClassCastException
。 (嗯,实际上,它会抛出一个NullPointerException
,但我认为你替换了真实代码中的return null
: - 。
有一些解决方案。首先,在您的示例中,您不使用该界面。如果您删除SomeInterface
,则仍可以执行new ClassA().getConfig().doThingOnlyClassAKnows()
。如果确实从未使用过该接口,请将其删除!
最干净的解决方案是您已经提到的解决方案:为接口提供一个类型参数,告诉它将返回什么类型的对象。我知道你不喜欢这样,因为你需要很多类型参数,但它是最干净的解决方案。
如果你真的不想添加类型参数,我会完全删除泛型:
public interface SomeInterface {
public BaseConfigClass getConfig();
}
在子类中,您仍然可以返回更具体的类型:
public class ClassA implements SomeInterface {
public ClassAConfig getConfig();
}
但是如果你只有对界面的引用,你需要添加一个类型转换:
SomeInterface a = new ClassA();
ClassAConfig aConfig = (ClassAConfig) a.getConfig();
aConfig.doThingOnlyClassAKnows();