Overloaded methods priority
Asked Answered
H

5

5

I have a base-class called Element. Some other classes (like Label and Image) both extend this class.

I now have a dispatching class having the following methods:

public class Dispatcher {
    public static AbstractPropertyEditor<Label> createEditor(Label e) {
    ...
    }

    public static AbstractPropertyEditor<Element> createEditor(Element e) {
    ...
    }
}

If now I have an instance of Label (which extends Element) and I want to pass it to createEditor(), why is the most generic method (the second one) called? Wouldn't it be normal that the most specific method (createEditor(Label e)) is called?

I absolutely need the method with the Element-param in order to "catch" all those classes that a) implement Element but do not have their own specific method in this dispatching class..

I'm using Java 6, how to "fix" this?

Edit: Okay, I have to admit it's not at all about generics. But that's where I encountered it the first time.

thanks and regards

Honeybunch answered 14/2, 2010 at 21:1 Comment(2)
You have the instance assigned to a variable of type Label not Element?Supernormal
(and not of T extends Element where T happens to be Label?)Supernormal
C
6

Why don't you:

  • make Element abstract class that provides a default createEditor() implementation
  • make Label override the createEditor().

Thus you won't need the static utilities and will achieve your goal.

If you need Element to be an interface, then:

  • define createEditor() as methods of Element
  • define a EditorFactory interface
  • provide DefaultEditorFactory and ListEditorFactory
  • use the appropriate factories in the implementors of Element:

    public Editor createEditor() {
         editorFactory.createEditor(this);
    }
    

where the concrete EditorFactory is instantiated either during initialization or via some sort of dependecy-injection.


As per your concrete question - it depends on what type you have compiled there. If you call createEditor(obj) it will depend whether it's Element obj = .. or Label obj = ..

Countermark answered 14/2, 2010 at 21:14 Comment(6)
hmmmm... gotta think a while about the consequences the idea of implementing createEditor in Element and subclasses would have... in a first instance, it doesn't sound like a bad idea. and in my situation I might be able to use it that way. But what if you still want those static utility class separate for reasons of separation? How does Java determine in my case which method to call? Does it always call the most generic one? Is there any way to have it called the most specific one?Honeybunch
updated my answer. and see others' answers as well for the exact behaviour.Countermark
seen it, thx. well... the problem is that I don't like to cast that thing into a Label right before calling the method. Otherwise I could directly create methods like createLabelEditor(Label l), createImageEditor(Image i) etc. This would obsolete the method having Element as parameter.Honeybunch
This would obsolete the method having a parameter (as this would refer to the same object). It then would result in having the specific method incompatible to the super class' one due to the return type. Okay, I now have some kind of redundancy but it works when I keep the parameter as a dummy. Not a beautiful solution at all. Comment: your version would fore Editor to be non-generic, which is a must-have.Honeybunch
you can easily "genericize" itCountermark
well I could. but this would result in a method not overriding the other one because the return values would be different and therefore not compatible. Except if I keep the dummy-param. Thanks anyway. I think this is a nasty construct to work around a problem that could be solved. For example an annotation for a method call with which you can provide which method should be called. for example @Call(MOST_SPECIFIC) createEditor(e);. thanks anyway, I'll close it as solved, even though I've just worked around it.Honeybunch
B
2

This really has little to do with generics, and everything to do with method overloading. In Java, the method signature called is determined at compile time, not at runtime, so you have to check and cast at runtime.

So replace this:

 Element label = getLabel();
 AbstractPropertyEditor<?> editor = createEditor(label);   

With this:

 Element label = getLabel();
 AbtractPropertyEditor<?> editor;
 if(label instanceof Label) {
      editor = createEditor((Label) label);
 } else {
      editor = createEditor(label);
 }

The other (more standard/better) way to fix this is to have the createEditor(Element) method check the type and call with a cast the correct overloaded method for subtypes. However, you will have an issue with your return parameters if you do that on the methods as declared.

Baculiform answered 14/2, 2010 at 21:8 Comment(2)
Thanks for the good response, but I would like to avoid instanceof wherever possible. Therefore, this is not an option to me.Honeybunch
@Atmocreations, then I suggest you don't use method overloading with super and subtypes as parameters. Such a pattern inevitably leads to instanceof and casting.Baculiform
P
1

From the Java Language Specification:

When a method is invoked (§15.12), the number of actual arguments (and any explicit type arguments) and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2). If the method that is to be invoked is an instance method, the actual method to be invoked will be determined at run time, using dynamic method lookup (§15.12.4).

Prelude answered 14/2, 2010 at 21:26 Comment(3)
thx. but while this is absolutely correct, it neither helps me with the current problem nor does it explain the way java determines which method is really called at the end.Honeybunch
@Atmocreations: I beg to differ, it clearly states that in the case of non-instance methods, the invoked method will be the one that corresponds to the types of the arguments at compile-time. Since in your case that is the Element one that gets called, it means you are calling the method with an Element at compile time.Prelude
Well... right, excuse me. I must admit that I haven't seen it that way yet.Honeybunch
H
0

Since you are probably doing :

Element element = new Label();

It is determined by the compiler.

Hanway answered 14/2, 2010 at 21:7 Comment(1)
well, seen indirectly (calling different methods depending on the situation) I'm doing this, yes. Does it really depend on the declared type of the var element to determine which method really is invoked? Isn't the method with the "real" type (Label) invoked? And if not, what's the reason for this?Honeybunch
P
0

This is an example of overloaded methods. Even though the actual object at runtime is a Label and not an Element, the choice of which overloaded method to call (in other words, the signature of the method) is NOT dynamically decided at runtime. The reference type (not the object type) determines which overloaded method is invoked!

Example

public class Car {    
}

public class Toyota extends Car {    
}

public class MyCar {

    public void run(Car c) {
        System.out.println("Run any Car");
    }

    public void run(Toyota t) {
        System.out.println("Run Toyota Car");
    }

    public static void main(String[] args) {
        MyCar myCar = new MyCar();

        Car c1 = new Car();
        myCar.run(c1); // Output: Run any Car

        Toyota c2 = new Toyota();
        myCar.run(c2); // Output: Run Toyota Car

        Car c3 = new Toyota();
        myCar.run(c3); // Output: Run any Car    
    }
}

So, in your case

Element obj1 = new Label();
Dispatcher.createEditor(obj); // Method with Element argument is called 
                              // as you are passing Element 

Label obj2 = new Label();
Dispatcher.createEditor(obj); // Method with Label argument is called 
                              // as you are passing Label

On other note, overridden method invocation happens at run time and it depends on Object type (in other words, the type of the actual instance on the heap)

Patiencepatient answered 10/1, 2011 at 22:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.