如何在界面中使用泛型来干净地处理未经检查的转换? [英] How to cleanly handle unchecked conversion with generics in an interface?

查看:148
本文介绍了如何在界面中使用泛型来干净地处理未经检查的转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



 公共类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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆