views:

296

answers:

3

I have two Java class hierarchies that share a common ancestor and implement a common interface. I need to pass a pointer to one of these things to a method in another class.

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

Is there something I can replace the '?' with that will allow me pass in either an 'A' or a 'B'? If I cast 'x' to a java.awt.Component and store it in 'c' and to an I and store it in 'i', I lose the benefit of strong typing.

Do I need to declare

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

and call it with 'm(a, a)' or 'm(b, b)' where

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

I cannot create an

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

and pass that in because neither A nor B is a C.

BTW, can this be done in Scala?

EDIT: The actual problem that I am trying to solve is that I have two classes, one that extends JInternalFrame and another that extends JPanel. Both are abstract and provide some common functionality for widgets displayed in them (JTables where the user can edit rows, delete rows, etc). The code for editing and deleting rows is always the same, regardless of the underlying object types being displayed. I have several methods that allow the user to click a row, select 'Delete' from a popup menu, and, after asking for confirmation, deletes the selected row and database object, for example. Sometimes I need a frame subcomponent and at other times a panel subcomponent. I have created a delegate class for the common functionality and an instance variable in each of the abstract classes of that delegate type. The JInternalFrame and JPanel derived classes then just defer the actual implementations to the delegate. The delegate class, in turn, needs a pointer to the "owner" class for callbacks to get the selected table row, etc., and a pointer to the "Component" nature of each parent for the JOptionPane confirmation dialogs.

Using the Java generics approach has worked very well. The delegate class is now defined as a generic class on <T extends Component & DelegateContainer and each of the owner abstract classes implements DelegateContainer (where the callback methods are declared).

If I were going to rewrite this in Scala, I would probably do something with traits instead of creating a delegate class. The traits could "add" the delete functionality to the JInternalFrame derived concrete class, for example.

Thanks for the prompt replies.

+4  A: 

In this case, if you want to do as you describe, it probably makes sense to create a class C that implements the common functionality between A and B from which both A and B can extend. This way, you can just pass class C as the argument to the D.m method.

Without knowing the exact classes, it's hard to make this call definitively. I'm just basing it on the function that you're trying to create. Since the D.m method apparently needs to be able to operate on either, there must be something in common about them.

Erick Robertson
That won't work in my case. The classes `A` and `B` actually extend other classes that extend `Component`. I am actually trying to create a new class `D` that acts as a delegate to do the common stuff that `A` and `B` are trying to do. I need to pass the `A` and `B` to the constructor of `D` so that it can call back to `A` and `B`.
Ralph
This is pretty convoluted. My instinct says that the whole arrangement needs to be simplified. It's hard to say without details, though.
Erick Robertson
+11  A: 

It's ugly, but you can use generics and constrain the method parameter to extend the class and implement the interface. Here's a complete example:

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

I don't know how this would fit into Scala, I'm afraid.


[ Edit by Rahul G ]

Scala way is the same. Just the syntax is different.

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)
  }
}
Jon Skeet
+1. By the way, added my comment to your answer. Comment box doesn't seem to be the right place for posting codes.
missingfaktor
I didn't know you could edit Jon Skeet posts. Thought they'd be immutable or something like that ... :-)
seanizer
@Missing Faktor: Makes a lot of sense to me.
Jon Skeet
The only reason I didn't upvote this answer is because you used Foo and Bar instead of I and Component. So that makes the other (nearly) identical answer better.
Erick Robertson
+13  A: 

Generics to the rescue !

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

It's not really the best way to do things but in your case it works. You should really split your method in two, one for the I behavior and another for the Component behavior.

Colin Hebert
@Colin: See the **EDIT** above for clarification of the problem. BTW, the generics solution worked very well. Thanks.
Ralph