【问题标题】:Requiring an argument extends a particular class AND implements a particular interface需要一个参数扩展一个特定的类并实现一个特定的接口
【发布时间】:2010-09-01 19:06:31
【问题描述】:

我有两个 Java 类层次结构,它们共享一个共同的祖先并实现一个共同的接口。我需要将指向这些事物之一的指针传递给另一个类中的方法。

interface I { ... }

class A extends java.awt.Component implements I { ... }
class B extends java.awt.Component implements I { ... }

class D {
  Component c;
  I i;
  void m(? x) {
    c = (Component) x;
    i = (I) x;
  }
}

有什么东西可以替换“?”,让我可以传入“A”或“B”吗?如果我将 'x' 转换为 java.awt.Component 并将其存储在 'c' 和 I 并将其存储在 'i' 中,我将失去强类型的好处。

需要申报吗

class D {
  void m(java.awt.Component c, I i) { ... }
}

并用“m(a, a)”或“m(b, b)”在哪里调用它

A a = new A();
B b = new B();

我无法创建

abstract class C extends java.awt.Component implements I {...}

并传递它,因为 AB 都不是 C

顺便说一句,这可以在 Scala 中完成吗?

编辑:我要解决的实际问题是我有两个类,一个扩展JInternalFrame,另一个扩展JPanel。两者都是抽象的,并为其中显示的小部件(用户可以编辑行、删除行等的 JTables)提供一些通用功能。无论显示的基础对象类型如何,编辑和删除行的代码始终相同。例如,我有几种方法允许用户单击一行,从弹出菜单中选择“删除”,并在要求确认后删除选定的行和数据库对象。有时我需要一个框架子组件,有时需要一个面板子组件。我为通用功能创建了一个委托类,并在该委托类型的每个抽象类中创建了一个实例变量。 JInternalFrameJPanel 派生类然后只是将实际实现推迟到委托。反过来,委托类需要一个指向“所有者”类的指针,用于回调以获取选定的表行等,以及一个指向每个父级的“Component”性质的指针,用于JOptionPane 确认对话框。

使用 Java 泛型方法效果很好。委托类现在被定义为<T extends Component & DelegateContainer 上的泛型类,并且每个所有者抽象类都实现了DelegateContainer(其中声明了回调方法)。

如果我要在 Scala 中重写它,我可能会用特征做一些事情,而不是创建一个委托类。例如,特征可以将删除功能“添加”到JInternalFrame 派生的具体类。

感谢及时回复。

【问题讨论】:

  • A 和 B 都是实现 I 的组件……这需要一个 AbstractIComponent……为什么这对你不起作用?
  • @Arne:我不相信这会起作用,因为AB 类不是AbstractIComponent 类型。

标签: java scala interface multiple-inheritance


【解决方案1】:

泛型来拯救!

public class Test {
    public static void main(String... args){
        new D().m(new A());
        new D().m(new B());
    }
}

interface I {  }

class A extends java.awt.Component implements I {}
class B extends java.awt.Component implements I {}

class D {
  Component c;
  I i;
  <T extends java.awt.Component & I> void m(T x) {
    c = x;
    i = x;
  }
}

这并不是最好的做事方式,但在你的情况下它确实有效。您真的应该将您的方法一分为二,一个用于I 行为,另一个用于Component 行为。

【讨论】:

  • 请参阅上面的 EDIT 以澄清问题。顺便说一句,泛型解决方案效果很好。谢谢。
【解决方案2】:

这很丑,但是您可以使用泛型并约束方法参数来扩展类并实现接口。这是一个完整的例子:

interface Foo {}

class Bar {}

class Impl extends Bar implements Foo {}

class D {

    private Foo foo;
    private Bar bar;

    <T extends Bar & Foo> void m(T t) {
        foo = t;
    }
}

public class Test {
    public static void main(String[] args) {
        Impl impl = new Impl();
        D d = new D();
        d.m(impl);
    }
}

恐怕我不知道这将如何适应 Scala。


[Rahul G编辑]

Scala 方式是一样的。只是语法不同而已。

trait Foo
class Bar
class Impl extends Bar with Foo

class D {
  private var foo: Foo = _
  private var bar: Bar = _

  def m[A <: Bar with Foo](a: A) {
    foo = a
    bar = a
  }
}

object Main {
  def main(args: Array[String]) {
    val impl = new Impl
    val d = new D
    d.m(impl)
  }
}

【讨论】:

  • +1。顺便说一句,将我的评论添加到您的答案中。评论框似乎不是发布代码的正确位置。
  • 我不知道你可以编辑 Jon Skeet 的帖子。认为它们是不可变的或类似的东西...... :-)
  • @Missing Faktor:对我来说很有意义。
  • 我不赞成这个答案的唯一原因是您使用 Foo 和 Bar 而不是 I 和 Component。所以这使得另一个(几乎)相同的答案更好。
【解决方案3】:

在这种情况下,如果你想按照你描述的那样做,创建一个类C 实现AB 之间的公共功能可能是有意义的,AB可以延长。这样,您可以将C 类作为参数传递给D.m 方法。

如果不知道确切的类,很难确定地进行此调用。我只是基于您尝试创建的功能。由于D.m 方法显然需要能够对其中任何一个进行操作,因此它们之间肯定有一些共同点。

【讨论】:

  • 这对我来说行不通。 AB 类实际上扩展了其他扩展 Component 的类。我实际上是在尝试创建一个新类D,它充当代理来执行AB 正在尝试做的常见事情。我需要将AB 传递给D 的构造函数,以便它可以回调AB
  • 这很复杂。我的直觉说整个安排需要简化。不过,如果没有细节就很难说。
猜你喜欢
  • 1970-01-01
  • 2017-10-13
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多