tags:

views:

91

answers:

5

I have some arraylist with different objects of the same interface type, e.g:

Interface interface {}

class A implements interface {}

class B implements interface {}

I also have an overloaded method that implements all those inherited objects of the interface:

public void doSomething(A obj) {}

public void doSomething(B obj) {}

The compiler also forces me to write an overloaded method with the interface:

public void doSomething(interface obj) {}

Then I go through the values of the list and call the method:

for (interface obj: myList) {
   doSomething(obj);
}

Now since the type of obj is 'interface', the doSomething(interface obj) is called instead of say doSomething(B obj) in case obj were actually of the type B.

Can I make java do otherwise, so it calls doSomething(A obj) when obj is of the type A and doSomething(B obj) when obj is of the type B?

A: 

You can use the Java instanceof operator to check what class implements your interface:

if(obj instanceof A) {
    // do something
} else {
    // do something else
}

But a better approach is to have a method that will just take any object that is an instance of the interface you have created, as mentioned by Atmocreations.

James
+2  A: 

Java uses early binding, meaning that the type of obj is defined during compilation, not at runtime. Since your code says that obj is of type interface, the compiler will always call the method that gets interface as a parameter.

You have two choices to make it call the right method:

  1. (Very ugly) Check obj type using instanceof and cast while calling the object.

    for (interface obj: myList) {
       if(obj instanceof A)
          doSomething((A) obj);
       else if(obj instanceof B)
          doSomething((B) obj);
       else
          doSomething(obj); // Calls the method receiving Interface
    }
    
  2. Implement a visitor method in interface, so both A and B will call method doSomething(this) when visited.

    interface Interface {
        void visit(OtherClass methodHolder);
    }
    
    
    class A implements Interface {
        public void visit(OtherClass methodHolder) {
            methodHolder.doSomething(this);
        }
    }
    
    
    class B implements Interface {
        public void visit(OtherClass methodHolder) {
            methodHolder.doSomething(this);
        }
    }
    
Alexandre Brasil
+1 for the visitor
Bozho
A: 

The polymorphic approach here would be to define doSomthing() in your interface and implement it in A and B, then call it within your loop. Depending on the concrete object, different code will be run.

Bozho
+2  A: 

There's a trick. Disclaimer: It's ugly.

If your class with the doSomething methods is called class Performer, as in:

class Performer {
  void doSomething(A x);
  void doSomething(B x);
  void doSomething(Inf x);
}

You could add to your interface Ifc:

interface Ifc {
  void acceptPerformer(Performer p);
}

In both class A and B implement it like this:

void acceptPerformer(Performer p) {
  p.doSomething(this);
}

And implement your doSomething(Ifc x) method like this:

void doSomething(Ifc x) {
  x.acceptPerformer(this);
}

It sounds odd, but it works. When calling the doSomething method which accepts an interface, it will call the acceptPerformer on the concrete class. When that class re-calls doSomething, it will know which type it is and will call the correct doSomething!

Aviad Ben Dov
You are basically describing a Visitor pattern.
Robin
and a pattern is never ugly ;)
Bozho
In case the original poster wants to do further reading, this is called "double dispatch" and is rarely used (in my experience) in Java where runtime type information is readily available and casting is a normal activity. Still a useful idiom if necessary.
PSpeed
Note: while the "visitor pattern" typically relies on double-dispatch it is not the same as double-dispatch. These examples are similar, though.
PSpeed
A: 

Is the method

public void doSomething(interface obj)

defined as part of the interface? That is the only thing that makes sense if the compiler is forcing you to write the method.

This then begs the question of why you are trying to change the method signature of the interface in your implementations. The interface is meant to be a contract on what the object looks like.

Robin
No I was mixing something up here sorry, the compiler doesn't say anything, it's a runtime error. The method is not part of the interface.
Schtibe