See the following example:
interface I {}
class A implements I {}
class B implements I {}
class Foo{
void f(A a) {}
void f(B b) {}
static public void main(String[]args ) {
I[] elements = new I[] {new A(), new B(), new B(), new A()};
Foo o = new Foo();
for (I element:elements)
o.f(element);//won't compile
}
}
Why doesn't overloading methods support upcasting?
If overloading was implemented at run time, it would provide much more flexibility. E.g, the Visitor Pattern would be simpler. Is there any technical reason that prevents Java from doing this?
Do not use overloaded methods to differentiate between runtime types. Java supports overloading methods and can distinguish between methods with different signatures. Consequently, with some qualifications, methods within a class can have the same name if they have different parameter lists.
There are two types of polymorphism one is Compile-time polymorphism and another is run-time polymorphism. Method overloading is the example of compile time polymorphism and method overriding is the example of run-time polymorphism.
Method overloading is the compile-time polymorphism where more than one methods share the same name with different parameters or signature and different return type. Method overriding is the runtime polymorphism having the same method with same parameters or signature but associated withcompared, different classes.
Compile-time polymorphism is obtained through method overloading. The term method overloading allows us to have more than one method with the same name. Since this process is executed during compile time, that's why it is known as Compile-Time Polymorphism.
Overload resolution involves some non-trivial rules to determine which overload is the best fit, and it'd be hard to do these efficiently at runtime. In contrast, override resolution is easier -- in the hard case you have to just look up the foo
function for the object's class, and in the easy case (e.g. when there's only one implementation, or only one implementation in this code path), you can turn the virtual method into a statically-compiled, non-virtual, non-dynamically-dispatching call (if you're doing it based on the code path, you have to do a quick check to verify that the object is actually the one you expect).
As it turns out, it's a good thing Java 1.4 and lower didn't have runtime override resolution, because that would make generics much harder to retrofit. Generics play a role in override resolution, but this information wouldn't be available at runtime due to erasure.
There is no theoretical reason why it cannot be done. The Common Lisp Object System supports this type of construction — called multiple dispatch — although it does so in a somewhat different paradigm (methods, rather than being attached to objects, are instances of generics (or generic functions), which can do virtual dispatch at run-time on the values of multiple parameters). I believe there have also been extensions to Java to enable it (Multi-Java comes to mind, although that may have been multiple inheritance rather than multiple dispatch).
There may, however, be Java language reasons why it cannot be done, besides the language designers just thinking it shouldn't be done, that I'll leave others to reason about. It does introduce complications for inheritance, though. Consider:
interface A {}
interface B {}
class C implements A {}
class Foo {
public void invoke(A a) {}
public void invoke(B b) {}
}
class Bar extends Foo {
public void invoke(C c) {}
}
class Baz extends Bar {
public void invoke(A a) {}
}
Baz obj = new Baz();
obj.invoke(new C);
Which invoke
is invoked? Baz
? Bar
? What is super.invoke
? It is possible to come up with deterministic semantics, but they will likely involve confusion and surprise in at least some cases. Given that Java aims to be a simple language, I don't think features introducing such confusion are likely to be seen as according with its goals.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With