如何在界面中使用泛型来干净地处理未经检查的转换? [英] How to cleanly handle unchecked conversion with generics in an interface?
问题描述
公共类SomeBaseClass {
}
简化的代码示例
public class SomeClass extends SomeBaseClass {
}
public interface SomeInterface {
public< T extends SomeBaseClass> T someMethod();
$ b $ public class BestClass implements SomeInterface {
// @SuppressWarnings(unchecked)
@Override
public SomeClass someMethod(){
返回null;
}
}
更详细的代码示例
//基本配置类
公共类BaseConfigClass {
}
//所有配置类的一些接口实现
public interface SomeInterface {
public< T extends BaseConfigClass> T getConfig();
}
//类'A'配置
public class ClassAConfig extends BaseConfigClass {
public doThingOnlyClassAKnows(){
}
}
// Class'A'
public class ClassA implements SomeInterface {
// @SuppressWarnings(unchecked)
@Override
public ClassAConfig getConfig( ){
返回null;
// B类配置
public class ClassBConfig extends BaseConfigClass {
public doThingOnlyClassBKnows(){
}
类'B'
public class ClassB implements SomeInterface {
// @SuppressWarnings(unchecked)
@Override
public ClassBConfig getConfig(){
return null;
$ b新类ClassA().getConfig()。doThingOnlyClassAKnows()
new ClassB()。 getConfig()。我有几个 SomeClass $> c $ c>,它们扩展了 SomeBaseClass
,其中一个接口具有返回类型。我正在使用< T扩展SomeBaseClass>
来强制返回类型与预期的一样。
问题是Java对此不满意提供以下警告:
$ b
类型安全性:返回类型SomeClass for someMethod()从类型
BestClass需要未经检查的转换以符合T从
类型SomeInterface
除了只是消除警告,我可以避免这是通过定义接口来实现的:
public interface SomeInterface< T extends SomeBaseClass> {
public T someMethod();
$ b 但是这样做很麻烦,因为这个接口有几个方法,每个方法不同的基础类型;我最终得到了一个非常长的 implements 声明。
一切似乎都按照我的预期工作到现在为止,但我感觉好像我的实现在某种程度上是错误的,因为我必须为由此接口定义的每个方法明确禁止此警告。
是否有一种干净的方法来设计这样的界面没有警告,但不需要一个冗长的 implements
declararion?
解决方案显示警告的原因是因为您的解决方案确实不是类型安全的。具有签名< T的BaseConfigClass>的扩展方法> T getConfig()
可以返回BaseConfigClass的任何子类。特别是,下面的代码会在没有警告的情况下编译:
SomeInterface a = new ClassA();
ClassBConfig bConfig = a.getConfig();
bConfig.doThingOnlyClassBKnows();
,但会在运行时抛出 ClassCastException
。 (实际上,它会抛出一个 NullPointerException
,但我假设你在实际代码中替换了 return null
: - )。
有几个解决方案。首先,在你的例子中,你不使用那个接口。如果删除 SomeInterface
,仍然可以执行 new ClassA()。getConfig()。doThingOnlyClassAKnows()
。如果该接口确实从未使用过,请将其删除!
最简洁的解决方案是您已经提到的解决方案:给接口一个类型参数来告诉它它是什么类型的对象将返回。我知道你不喜欢这样,因为你需要很多类型参数,但它是最干净的解决方案。
如果你真的不想添加类型参数,我会简单地删除泛型:
$ b $ pre $ public interface SomeInterface {
public BaseConfigClass getConfig();
$ b在子类中,仍然可以返回更具体的类型:
public class ClassA implements SomeInterface {
public ClassAConfig getConfig();
}
但是如果你只有一个参考界面,你需要添加一个类型转换:
SomeInterface a = new ClassA();
ClassAConfig aConfig =(ClassAConfig)a.getConfig();
AConfig.doThingOnlyClassAKnows();
Simplified Code Example
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;
}
}
More Detailed Code Example
// 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()
I have several various SomeClass
which extend SomeBaseClass
of which an interface has return types of. I am using <T extends SomeBaseClass>
to enforce that the return type is as expected.
The issue is that Java is unhappy with this an provides the following warning:
Type safety: The return type SomeClass for someMethod() from the type
BestClass needs unchecked conversion to conform to T from the
type SomeInterface
Besides just silencing the warning, I can avoid this by instead defining the interface as such:
public interface SomeInterface<T extends SomeBaseClass> {
public T someMethod();
}
But this ends up being very messy as this interface has several methods which each implement different base types; and I end up with a very long winded implements
declaration.
Everything seems to be working as I would expect it to now but I feel as though my implementation is somehow wrong as I have to explicitly suppress this warning for each method defined by this interface.
Is there a clean way to design an interface like this without the warning but doesn't require a long-winded implements
declararion?
解决方案 The reason the warning is displayed is because your solution is indeed not typesafe. A method with the signature <T extends BaseConfigClass> T getConfig()
can return any subclass of BaseConfigClass. In particular, the following code will compile without warnings:
SomeInterface a = new ClassA();
ClassBConfig bConfig = a.getConfig();
bConfig.doThingOnlyClassBKnows();
but will throw a ClassCastException
at runtime. (Well, actually, it throws a NullPointerException
, but I assume you replaced the return null
in your real code :-).
There are a few solutions. First, in your example, you don't use that interface. If you remove SomeInterface
, you can still do new ClassA().getConfig().doThingOnlyClassAKnows()
. If that interface is indeed never used, remove it!
The cleanest solution is the solution you already mentioned: give the interface a type parameter to tell it what type of object it will return. I understand you don't like this because you would need a lot of type parameters, but it is the cleanest solution.
If you really don't want to add the type parameters, I would simply remove the generics completely:
public interface SomeInterface {
public BaseConfigClass getConfig();
}
In subclasses, you can still can return the more specific type:
public class ClassA implements SomeInterface {
public ClassAConfig getConfig();
}
But if you only have a reference to the interface you will need to add a type cast:
SomeInterface a = new ClassA();
ClassAConfig aConfig = (ClassAConfig) a.getConfig();
aConfig.doThingOnlyClassAKnows();
这篇关于如何在界面中使用泛型来干净地处理未经检查的转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!