Why does the cast determine which overloaded method gets called? [duplicate] - java

This question already has answers here:
Java method call overloading logic
(3 answers)
Closed 9 years ago.
If java is pass-by-value, and that value is the memory address for the actual type, then why does the overloaded method that's called get decided by the reference/declared type?
class Boss {
void test(Object o){
System.out.println("object");
}
void test(Boss b){
System.out.println("boss");
}
public static void main( String[] args ) {
Boss b = new Boss();
b.test((Object)b); //prints out object, why?
}
}

Dynamic binding applies to the object on which the method is called, not to its parameters and method overloading.
In this case, the method is determined at compile time to be void test(Object o), because that's the overload that matches the argument types.
At run time, the implementation of test(Object o) is chosen based on the object on which it's called. In this case, that's the implementation in Boss.
As an example, say you had had done this:
class Director extends Boss { ... }.
Boss d = new Director();
Boss b = new Boss;
d.test((Object)b);
Then in terms of method overloading, the method chosen at compile time would still be test(Object o). At runtime, the implementation could be in Director, because d references a Director.

Overloading is decided at the compile time i.e the compiler decides which method to execute right during compilation, irrespective of the object that would be passed to it at runtime. And since you are passing a reference variable of Object and not Boss, although the object is of Boss, it executes the overloaded void test(Object b) method.

Related

Java Overloaded AND Overridden Methods

In the following program, I have one single method in class A overloaded 3 times and then in subclass B, all 3 overloaded methods are overridden.
obj3 is an object with reference type A(superclass) and object type B(subclass) and it calls the method from B on execution, which is expected behavior.
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B). Can they both occur together?
My assumption is that this is a classic case of dynamic binding as I believed "binding" is meant to be a permanent action, but a peer suggests that it is both together(static first, then dynamic).
class A{
public void method(Integer n){
System.out.println("Integer: "+n);
}
public void method(String s){
System.out.println("String: "+s);
}
public void method(String s, Integer n){
System.out.println("String: "+s+" Integer: "+n);
}
}
class B extends A{
public void method(Integer n){
System.out.println("Integer(from B): "+n);
}
public void method(String s){
System.out.println("String(from B): "+s);
}
public void method(String s, Integer n){
System.out.println("String(from B): "+s+" Integer(from B): "+n);
}
}
public class Test{
public static void main(String[] args){
A obj1 = new A();
B obj2 = new B();
A obj3 = new B();
System.out.println("Integer form of method");
// Integer form of method
System.out.println("Ref A Obj A");
// Ref A Obj A
obj1.method(1);
// Integer: 1
System.out.println("Ref B Obj B");
// Ref B Obj B
obj2.method(2);
// Integer(from B): 2
System.out.println("Ref A Obj B");
// Ref A Obj B
obj3.method(3);
// Integer(from B): 3
}
}
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B)
Right. The compiler chose the matching signature, and this is static, based on the type of the variable (A in this case).
At runtime, Java finds the implementation of the signature selected by the compiler. This is dynamic, based on the runtime class of obj3 (B, in this case).
You right. Compiler is statically choose between overloads in class A and put that information into .class file in form of method FQN.
Then runtime dynamically choose between implementation of that method.
One more attempt to make it clear:
Overloading
Overloading means that a single class has multiple methods with different parameter types (aka. signatures), and you just happened to give them the same name. Your program will work the very same if you change to individual names for the methods, e.g. methodI(Integer n), methodS(String s), and methodSI(String s, Integer n).
Or, you can imagine the compiler to internally always append such a types list to the method name.
Overloading is resolved by the compiler, based on the compile-time types of the parameter expressions.
E.g. if you write
Object par = "Test";
a.method(par);
you get a compiler error. Even though we all see it's a String that you are passing into the method, the compiler only sees an Object, and finds no matching method. Only if you were to introduce an additional method(Object o), the compiler would choose that one. And runtime would call that method and not the String version!
Overriding
Overriding means that at runtime the JVM calls the method implementation depending on the runtime class of the "object before the dot".
And in this case, "method" is to be read as the overloaded method version that the compiler found to match the parameter list. So, runtime already knows whether methodI(), methodS(), or methodSI() is meant, and only decides from which class to take the implementation.
Personal opinion
Allowing multiple methods to share the same name, but differ in parameter lists (aka overloading), produces too much confusion for its benefit.

Reference types in runtime

My included code's output is pretty ugly, but it's just a code for understanding how different things may work in Java. The questioned line is marked with comments on the bottom half of the code.
class CsTorta extends Torta{
public CsTorta retegez(CsTorta a){
....
}
public CsTorta retegez(Torta a){
System.out.println("This method"); //<-----it calls this one and not the one above
....
}
}
public class NewClass {
public static void main(String[] args) {
Torta tt=new Torta(5);
Torta tcs=new CsTorta(3);
CsTorta cs=new CsTorta(4);
System.out.println("");
System.out.println(tcs.retegez(tcs)); //The line in question uses the cstorta retegez method (marked with "This method")
}
}
While the tcs's type in coding-time is the reference type, in runtime when i call the tcs.retegez method it recognizes its a cstorta type, but the parameter which is the same tcs remains the reference type (thats why it uses the cstorta marked method).
My question is: Is my conclusion correct: that the program only checks the "real" type of the object if it calls a method, and uses the reference type if it does not?
That's pretty much correct. What is needed here is understanding the difference between overloading and overriding.
Overriding occurs when you have a class that declares an instance method, and a subclass that declares the same method (same name, same parameters--the result type is usually the same but could be a subclass). There are multiple methods to choose from, but the exact method is determined at run time.
public class A {
public void method1(String s1, int s2) { ... }
}
public class B extends A {
#Override
public void method1(String s1, int s2) { ... }
}
A object = new B();
object.method1("xxx",2);
The decision about which method1 is run isn't made until run time. object's real type is B, so the method1 declared in B is called.
Overloading is when two methods with the same name, but different parameters, are both present. By different parameters, I mean that the number of parameters is different, or the number of parameters is the same but the types are different. That is, they have different signatures. In that case, the decision on which method to call is made at compile time. (You can have a case where both overriding and overloading occur. The decision about which parameter signature to choose is made at compile time; but if there are multiple overriding methods with the same signature, the choice between those methods is made at run time.)
The key thing to remember is that if the decision is made at compile time, the compiler will not know what the "real" type of the object is. All it knows is how you've declared it. Thus:
public CsTorta retegez(CsTorta a){ // Number 1
....
}
public CsTorta retegez(Torta a){ // Number 2
System.out.println("This method"); //<-----it calls this one and not the one above
....
}
These are overloaded methods.
Your code looks like:
Torta tcs = // the compiler doesn't care
System.out.println(tcs.retegez(tcs));
The compiler has to decide whether to call Number 1 or Number 2. All the compiler knows is that the parameter is a Torta. The actual value could be an object of Torta, CsTorta, or any other class. Or it could be null (all right, you can't call tcs.retegez if it's null, but if you said tcs.retegez(tcs2), then tcs2 could be null.) The compiler doesn't know, and doesn't care. All it knows is that it was declared as a Torta, so it chooses the overloaded method with the Torta parameter.
(To clarify further: the compiler will choose the deepest subclass it can. Example:)
class AnotherTorta extends Torta { ... }
class YetAnotherTorta extends CsTorta { ... }
AnotherTorta t3 = // whatever
YetAnotherTorta t4 = // whatever
tcs.retegez(t3);
// since AnotherTorta can't be cast to CsTorta, it chooses the Torta parameter
tcs.retegez(t4);
// here, t4 can be cast to either a Torta or CsTorta parameter, so it chooses the subclass, CsTorta

Passing null to Ambigious Overloaded Method [duplicate]

This question already has answers here:
How is an overloaded method chosen when a parameter is the literal null value?
(8 answers)
Closed 6 years ago.
Which overloaded method will be called for the below method and why?
I executed this code and it calls the overloaded method with List but why does it happen?
public class AmbigiousOverload {
public static void add(Object o) {
System.out.println("Overloaded method with Object.");
}
public static void add(List l) {
System.out.println("Overloaded method with List.");
}
public static void main(String[] args) {
add(null);
}
}
Output: Overloaded method with List.
The List overload is called because the List overload is the most specific matching overload, as all List implementations are subclasses of Object.
From JLS Sec 15.12.2.5:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
Since any parameter you can pass to add(List) can also be passed to add(Object), add(List) is more specific. As such, given that null can be passed to both, the more specific method is the one chosen.
Note that it wouldn't compile if you had an add(String) overload, since List and String are "equally" specific. (Or any other class: it doesn't have to be String).

Why constructor call is not ambiguous in the following example? [duplicate]

This question already has answers here:
Method overloading and choosing the most specific type
(9 answers)
Closed 8 years ago.
class Test {
public Test(Object obj) {
System.out.println("Object");
}
public Test(String s) {
System.out.println("String");
}
public static void main(String[] args) {
new Test(null); //prints String. Why not Object?
}
}
If I add another constructor with argument of type Integer ,or, for that matter any other type, calling new Test(null); results in compilation error - The constructor Test(Object) is ambiguous. Why no error is generated for the above example? On executing it, constructor with argument String is called. Why constructor with argument type Object is not called? How this ambiguity is resolved?
//prints String. Why not Object?
Because compiler choose most specific type.
If I add another constructor with argument of type Integer ,or, for
that matter any other type, calling new Test(null); results in
compilation error - The constructor Test(Object) is ambiguous.
Now String and Integer are in the same level in the object hierarchy, So, compiler can't choose one out of those two
Because it is determined by the most specific type of the parameter.
Since String is subclass of Object, and null is subtype of anything, then the second constructor is called, because String is more specific than Object.
Compiler is designed to pick up the overloaded method that very closely matches the Value sent in parameter.

Polymorphism and method overloading

I have a quick and straighforward question:
I have this simple class:
public class A
{
public void m(Object o)
{
System.out.println("m with Object called");
}
public void m(Number n)
{
System.out.println("m with Number called");
}
public static void main(String[] args)
{
A a = new A();
// why will m(Number) be called?
a.m(null);
}
}
UPDATE: actually is method with Number actually being called. Sorry about the confusion.
If I call a.m(null) it calls method with Number parameter.
My question is: why is this? where in the java language specification is this specified?
First of all, it actually calls m(Number).
It happens because both methods are applicable, but m(Number) is the most specific method, since any argument of m(Number) can be passed to m(Object), but not vice versa.
If you replace m(Object) by m(String) (or add another method such as m(Date)), compiler would report ambiguity, since the most specific method can't be identified.
See the section Choosing the Most Specific Method in the Java Specification.
This is not polymorphism or overriding. This is method overloading.
I tested this and specific method is being called (not the m(Object)) and according to the spec the specific method is always called. Which overload will get selected for null in Java?
another related question for you to think about:
public static void main(String[] args)
{
A a = new A();
Object n = new Integer(1);
a.m(n); // which method will be called?
}
My 2 cents. Method with Number argument is the one that is called, Because Number extends Object. I had a similar situation in the past, I did override a method and put Component instead of JComponent (by mistake). It took me one week to find out the reason why my method was never called. I figure it out, that if there are some inheritance relationship between the overloaded methods, the JVM matches first the deeper one in the class hierarchy.
Object is the default type in Java. If you refactor your m(Object o) method to m(String o) you'll have a compile time error saying that the call m(null) is ambiguous because Java cannot determine which class between String and Number defaults to null
Other than that, between m(Object o) and m(Number o), calling m(null) will call m(Number o) because it's the most specialized method. You would need to cast null into an Object (or anything not an instance of Number) otherwise.
a.m((String) null);

Categories