坦率地说,Java 的方式是完全避免这种情况。通常 Java 程序员会加倍努力(并使用许多已建立的模式)来不破坏多态性 - 因此切换类型将被认为是一种不好的做法。
最简单的解决方案和@optional 的直接翻译是使用 instanceof 并在接口中使用可选方法来扩展所需的方法:
interface MyProtocol {
void required1();
void required2();
}
interface MyProtocolWithOptional extends MyProtocol {
void optional1();
void optional2();
}
接着:
public static void test(MyProtocol mp) {
mp.required1();
if (mp instanceof MyProtocolWithOptional) {
((MyProtocolWithOptional)mp).optional1();
}
}
如果您有很多接口并且您的应用程序在运行时是可扩展的,您可以使用能力模式 ( http://java.dzone.com/print/4771 ) 之类的解决方案,其中可以查询每个对象的可用接口(其中有点像 COM,有点不像 COM)。您可以从以下内容开始:
interface ThingWithCapabilities<T> {
T interfaceFor(Class<T> inteface)
}
ThingWithCapabilities 是所有其他人扩展的基本接口。然后在运行时使用它:
public static void test(ThingWithCapabilities mp) {
if (mp.interfaceFor(MyProtocolWithOptions.class) != null) {
mp.interfaceFor(MyProtocolWithOptions.class).optional1();
}
}
好消息是铸件不见了。更好的是,您没有将 MyProtocolWithOptions 实例的生命周期与 ThingWithCapabilities 的生命周期联系起来(例如,您可以拥有一个 MyProtocolWithOptions 实例来满足许多 ThingWithCapabilities 实例的需求;另一方面,如果您碰巧实现了 MyProtocolWithOptions)。如果将它与空对象模式结合使用(其中您有一个无状态的 MyProtocolWithOptions 实例,它什么都不做,并且由每个不具有 MyProtocolWithOptions 功能而不是 null 的 ThingWithCapabilities 返回),您可以获得更好的代码:
public static void test(ThingWithCapabilities mp) {
mp.interfaceFor(MyProtocolWithOptions.class).optional1();
}
除非你正在写一些大的东西,否则这种方法可能很复杂。我只是提到它,因为它很有趣(并且我在一些宠物项目上成功使用过它)。