引用实现两个或更多给定接口的任何类的对象
给定任何接口I
,可以声明一个variables来保存对实现I
的类C
任何对象的引用:
I i = new C();
我想要做类似的事情。 给定两个接口,我想声明一个variables,该variables持有对实现这两个接口的类的任何对象的引用:
interface Foo { void foo(); } interface Bar { void bar(); } class Humpty implements Foo, Bar { public void foo() { System.out.println("Humpty.foo()"); } public void bar() { System.out.println("Humpty.bar()"); } } class Dumpty implements Foo, Bar { public void foo() { System.out.println("Dumpty.foo()"); } public void bar() { System.out.println("Dumpty.bar()"); } } public class Program { public static void main(String[] args) { // I actually have no idea what the syntax should be. Random random = new Random(); // Fix: I previously used , thanks Jon Skeet and vijucat foobar; if (random.nextBoolean()) foobar = new Humpty(); else foobar = new Dumpty(); foobar.foo(); foobar.bar(); } }
我已经尝试了上面的代码片段,但
导致编译错误。 正确的语法应该是什么? 我想知道在其他静态types的JVM语言中是否也可以这样做:Scala,Kotlin,Ceylon等等。
如果你不介意压制臭名昭着的“未经检查的投射”警告,这是一个“解决方案”:
@SuppressWarnings("unchecked") public class Program { public static void main(String[] args) { // Note the explicit cast needed FooBar foobar = (FooBar) new Humpty(); foobar.foo(); foobar.bar(); // Note the explicit cast needed foobar = (FooBar) new Dumpty(); foobar.foo(); foobar.bar(); } }
也可以看Jon Skeet的答案,这个答案可以在优雅的情况下进行。
老实说,这应该是可能的,没有这么多的角落案件。 Javagenerics的实现是如此的混乱,不理解它们可能表明你知道如何明智地分配你的时间,而不是在技术领域的专家! 🙂
给定两个接口,我想声明一个variables,该variables持有对实现这两个接口的类的任何对象的引用
不幸的是,你不能这样做。 您可以在generics方法中为参数执行此操作,如下所示:
public static void someMethod(T value) { Foo x = value; Bar y = value; }
…或者你也可以为generics类中的实例variables做同样的事情:
class Test { private T value; public Test(T value) { this.value = value; } }
…但是你不能声明一个需要满足这两个约束的variables。
(请注意这里的两个约束的语法 – 它是&
而不是一个逗号。)
你可以只投射物体。 你可以做这样的事情:
Humpty foobar = new Humpty(); ((Foo)foobar).foo(); ((Bar)foobar).bar();
您可以创建一个接口层次结构,但这只适用于相关的接口。 如果Bar和Foo完全不相关,这将不起作用。
interface Foo { void foo(); } interface Bar extends Foo { void bar(); } //implementations of Bar will need to implement both foo() and bar()
Humpty和Dumpty只需要执行Bar,那么你可以创建一个对象:
extends Foo> foobar = new Humpty();
这不是很好,但它的工作原理,它是安全的(模null
引用),并不需要压制任何警告。 Jon Skeet实际上正朝着正确的方向前进,但在中间停了下来:
/** * Existentially quantify over things that implement Foo and Bar. * * FooBar = \exists (T extends Foo & Bar). T */ interface FooBar extends Foo, Bar {} /** * Universally quantify over things that implement Foo and Bar. * * \forall (T extends Foo & Bar). T --> WrappedFooBar * \forall (T extends Foo & Bar). WrappedFooBar --> FooBar */ class WrappedFooBar implements FooBar { private T wrapped; public WrappedFooBar(T wrapped) { this.wrapped = wrapped; } public void foo() { this.wrapped.foo(); } public void bar() { this.wrapped.bar(); } } public class Program { public static void main(String[] args) { Random random = new Random(); FooBar foobar; if (random.nextBoolean()) foobar = new WrappedFooBar(new Humpty()); else foobar = new WrappedFooBar(new Dumpty()); foobar.foo(); foobar.bar(); } }
主要的注意事项是,这个解决方案显然不能扩展:可能需要编写大量的包装。