Search code examples
javaruntimereference-type

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?


Solution

  • 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