引用实现两个或更多给定接口的任何类的对象

给定任何接口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,那么你可以创建一个对象:

  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(); } } 

主要的注意事项是,这个解决方案显然不能扩展:可能需要编写大量的包装。