gpt4 book ai didi

Java 未经检查的重写返回类型

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:15:33 24 4
gpt4 key购买 nike

我有一个包含以下组件的项目:

public abstract class BaseThing {
public abstract <T extends BaseThing> ThingDoer<T, String> getThingDoer();
}

public class SomeThing extends BaseThing {
public ThingDoer<SomeThing, String> getThingDoer() {
return Things.getSomeThingDoer();
}
}

public class SomeOtherThing extends BaseThing {
public ThingDoer<SomeOtherThing, String> getThingDoer() {
return Things.getSomeOtherThingDoer();
}
}

public class Things {
public ThingDoer<SomeThing, String> getSomeThingDoer {
return getThingDoer(SomeThing.class);
}

public ThingDoer<SomeOtherThing, String> getSomeOtherThingDoer {
return getThingDoer(SomeOtherThing.class);
}

private <D extends ThingDoer<T, String> D getThingDoer(Class<T> clazz) {
//get ThingDoer
}
}

public class ThingDoer<T, V> {
public void do(T thing) {
//do thing
}
}

public class DoThing {
private BaseThing thing;

public void doIt() {
thing.getThingDoer().do(thing);
}
}

我在 SomeThing.getThingDoer() 中收到编译器警告上面写着:

Unchecked overriding: return type requires unchecked conversion.

Found ThingDoer<SomeThing, String>, required ThingDoer<T, String>

一切都编译得很好,虽然我没有机会测试 DoThing.doIt()然而,我没有理由相信它不会奏效。

我的问题是,这会中断吗?是否有更好的方法来做到这一点?我可以做 DoThing一个基类,并且都有子类 SomeThingSomeOtherThing但这似乎不是很优雅。

编辑:我想避免制作 BaseThing通用。

最佳答案

让我们先看看你的BaseThing您不想使其通用的类:

public abstract class BaseThing {
public abstract <T extends BaseThing> ThingDoer<T, String> getThingDoer();
}

不是泛型类,但它包含一个泛型方法。通常,像这样的通用方法被设计成类型 <T>由编译器根据方法的某些参数进行绑定(bind)。例如:public <T> Class<T> classOf(T object) .但在你的情况下,你的方法没有参数。这也有点常见,在方法的实现返回一些“通用”通用(我的术语)的情况下,就像来自 Collections 的这个方法一样。实用程序类:public <T> List<T> emptyList() .此方法不带参数,但类型 <T>将从调用上下文推断;它有效,因为 emptyList() 的实现返回一个在所有情况下都是类型安全的对象。由于类型删除,该方法实际上并不知道 T 的类型当它被调用时。

现在,回到您的类(class)。当您创建 BaseThing 的这些子类时:

public class SomeThing extends BaseThing {
public ThingDoer<SomeThing, String> getThingDoer() {
return Things.getSomeThingDoer();
}
}

public class SomeOtherThing extends BaseThing {
public ThingDoer<SomeOtherThing, String> getThingDoer() {
return Things.getSomeOtherThingDoer();
}
}

在这里,您想覆盖 abstract来自基类的方法。 Java 中允许覆盖返回类型,只要返回类型在原始方法的上下文中仍然有效。例如,您可以覆盖返回 Number 的方法使用始终返回 Integer 的特定实现对于那个方法,因为Integer 是一个 Number .

然而,对于泛型,一个 List<Integer> 不是 List<Number> .因此,虽然您的抽象方法被定义为返回 ThingDoer<T, String> (对于某些 T extends BaseThing ),您返回的重载 ThingDoer<SomeThing, String>ThingDoer<SomeOtherThing, String>通常与一些未知的 T 不兼容尽管 SomeThingSomeOtherThing都从 BaseThing 延伸.

调用者(来自抽象 API)期望一些未知的、不可执行的 T您的任何一个具体实现都不能保证满足这一点。事实上,您的具体重载不再是通用的(它们返回特定的、静态绑定(bind)的类型参数)并且与抽象类中的定义冲突。

编辑:定义抽象方法的“正确”方式(没有警告)应该是这样的:

public abstract ThingDoer<? extends BaseThing, String> getThingDoer();

这让调用者清楚地知道它得到了一个 ThingDoer它的第一个类型参数绑定(bind)到扩展 BaseThing东西 (因此它可以像使用 BaseThing 一样使用它)但是调用者不会知道抽象 API 访问时的具体实现。

编辑 #2 - 我们在聊天中讨论的结果......

OP 的原始示例用法是:

BaseThing thing = /* ... */;
thing.getThingDoer().do(thing);

请注意 thing 是如何相同的引用被传递回从同一事物的 getThingDoer() 返回的对象中的方法。方法。 getThingDoer() 返回的对象需要紧密绑定(bind)到 thing 的具体实现类型(根据OP)。对我来说,这闻起来像是破损的封装。

相反,我建议将逻辑操作公开为 BaseThing 的一部分API 并将委托(delegate)封装到 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);
}
}

关于Java 未经检查的重写返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23645753/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com