Java未选中覆盖返回类型
我有一个包含以下组件的项目:
public abstract class BaseThing { public abstract ThingDoer getThingDoer(); } public class SomeThing extends BaseThing { public ThingDoer getThingDoer() { return Things.getSomeThingDoer(); } } public class SomeOtherThing extends BaseThing { public ThingDoer getThingDoer() { return Things.getSomeOtherThingDoer(); } } public class Things { public ThingDoer getSomeThingDoer { return getThingDoer(SomeThing.class); } public ThingDoer getSomeOtherThingDoer { return getThingDoer(SomeOtherThing.class); } private <D extends ThingDoer D getThingDoer(Class clazz) { //get ThingDoer } } public class ThingDoer { public void do(T thing) { //do thing } } public class DoThing { private BaseThing thing; public void doIt() { thing.getThingDoer().do(thing); } }
我在SomeThing.getThingDoer()
中收到编译器警告:
未选中覆盖:返回类型需要未经检查的转换。
找到
ThingDoer
,需要ThingDoer
Everthing编译得很好,虽然我还没有机会测试DoThing.doIt()
但我没有理由相信它不会起作用。
我的问题是,这可以打破并有更好的方法吗? 我可以将DoThing
作为基类,并为SomeThing
和SomeOtherThing
设置子类,但这看起来并不优雅。
编辑:我想避免使BaseThing
通用。
让我们首先看一下你不想制作generics的BaseThing
类:
public abstract class BaseThing { public abstract ThingDoer getThingDoer(); }
这不是generics类,但它包含generics方法 。 通常,这样的generics方法被设计为使得类型
基于该方法的某个参数由编译器绑定。 例如: public
。 但在你的情况下,你的方法不带参数。 如果方法的实现从Collections
实用程序类返回类似于此方法的“通用”generics(我的术语),那么这也有点常见: public
。 此方法不带参数,但类型
将从调用上下文中推断出来; 它的工作原理只是因为emptyList()
的实现返回了一个在所有情况下都是类型安全的对象。 由于类型擦除 ,该方法在调用时实际上并不知道T
的类型。
现在,回到你的课堂。 在创建BaseThing
这些子类时:
public class SomeThing extends BaseThing { public ThingDoer getThingDoer() { return Things.getSomeThingDoer(); } } public class SomeOtherThing extends BaseThing { public ThingDoer getThingDoer() { return Things.getSomeOtherThingDoer(); } }
在这里,您希望覆盖基类中的abstract
方法。 只要返回类型在原始方法的上下文中仍然有效, Java中就允许覆盖返回类型。 例如,您可以覆盖一个返回Number
的方法,该方法具有始终为该方法返回Integer
的特定实现,因为Integer
是一个 Number
。
但是,对于generics, List
不是 List
。 因此,虽然您的抽象方法被定义为返回ThingDoer
(对于某些T extends BaseThing
),但是返回ThingDoer
和ThingDoer
通常不会与某些未知的T
兼容,即使SomeThing
和SomeOtherThing
都从BaseThing
扩展。
调用者(来自抽象API)期望一些未知的,无法执行的T
无法保证满足您的任何具体实现。 实际上,您的具体重载不再是通用的(它们返回特定的,静态绑定的类型参数)并且与抽象类中的定义冲突。
编辑 :定义抽象方法的“正确”方式(无警告)应该是这样的:
public abstract ThingDoer extends BaseThing, String> getThingDoer();
这使得调用者明白它正在获取ThingDoer
,其第一个类型参数绑定到扩展BaseThing
东西 (因此它可以像使用BaseThing
使用它)但是调用者在抽象访问时不会知道具体的实现API。
编辑#2 – 我们在聊天中讨论的结果……
OP的原始示例用法是:
BaseThing thing = /* ... */; thing.getThingDoer().do(thing);
注意同一个thing
引用是如何传递回从同一个东西的getThingDoer()
方法返回的对象中的方法。 getThingDoer()
返回的对象需要紧密绑定到具体的实现类型(根据OP)。 对我来说,这闻起来像破碎的封装。
相反,我建议将逻辑操作公开为BaseThing
API的一部分,并将ThingDoer
作为内部实现细节封装到ThingDoer
。 生成的API看起来像:
thing.doTheThing();
并实施有点像:
public class SomeThing extends BaseThing { @Override public void doTheThing() { Things.getSomeThingDoer().do(this); } } public class SomeOtherThing extends BaseThing { @Override public void doTheThing() { Things.getSomeOtherThingDoer().do(this); } }