downcasting in java + calling method with variable arguments

Mukund Banka :

When I call a.displayName("Test") ,it calls the method of class Icecream. displayName(String...s) method takes in variable arguments. Output-

test Icecream
test Faloodeh 
test Faloodeh:  Faloodeh
test Faloodeh:  Faloodeh

But when I change the method to displayName(String s)(I have commented out that section in the code), then it calls the method of class Faloodeh. New output-

test Faloodeh 
test Faloodeh 
test Faloodeh:  Faloodeh
test Faloodeh:  Faloodeh

I wanted to know why does that happen.

class Icecream{
    public void displayName(String...s){
        System.out.println(s[0]+" "+"Icecream");
    }
    /*public void displayName(String s){
        System.out.println(s+" "+"Icecream");
    }
    */
    public void describe(String s) {
        System.out.println(s+" "+"Icecream: Ice cream");
    }
}
class Faloodeh extends Icecream {
    public void displayName (String s){
        System.out.println(s+" "+"Faloodeh ");
    }

    public void describe (String s) {
        System.out.println(s+" "+"Faloodeh:  Faloodeh");
    }
}
 class Test {
    public static void main(String arg[]) {
       Icecream a=new Faloodeh ();
       Faloodeh b=( Faloodeh)a;
        a.displayName("test");
        b.displayName("test");
        a.describe("test");
        b.describe("test");
    }
}

**Edit- ** Thanks for the answers. Please help me with another doubt. I changed the code to -

class Icecream{
    public void displayName(String s){
        System.out.println(s+" "+"Icecream");
    }
    /*public void displayName(String s){
        System.out.println(s+" "+"Icecream");
    }
    */
    public void describe(String s) {
        System.out.println(s+" "+"Icecream: Ice cream");
    }
}
class Faloodeh extends Icecream {
    public void displayName (String...s){
        System.out.println(s+" "+"Faloodeh ");
    }

    public void describe (String s) {
        System.out.println(s+" "+"Faloodeh:  Faloodeh");
    }
}
 class Test {
    public static void main(String arg[]) {
       Icecream a=new Faloodeh ();
       Faloodeh b=( Faloodeh)a;
        a.displayName("test");
        b.displayName("test");
        a.describe("test");
        b.describe("test");
    }
}

Now this gives the following output-

test Icecream
test Icecream
test Faloodeh:  Faloodeh
test Faloodeh:  Faloodeh

As you all explained, here b is an object of class Faloodeh. And displayName(String...s) of class Faloodeh doesn't gets override. Still in the output, it displays test Icecream Why so?

Sweeper :

The key point here is that changing displayName(String... s) to displayName(String s) causes the displayName(String s) method in Faloodeh to override the method in its superclass.

Icecream.displayName(String... s) and Faloodeh.displayName(String s) have different signatures, so they do not override each other. But changing the former to accept one String only causes them to have the same signature, which causes overriding to occur.

In Java, method calls are resolved in roughly three steps (for more info: JLS §15.12, I also explained in more detail here):

  1. Find the class to search for applicable methods. This is based on the compile time type of the object on which you are calling the method. In this case, a. a's compile time type is Icecream, so only Icecream's methods will be considered. Notice that it doesn't find the displayName method in Faloodeh because the compile time type of a is Icecream.
  2. Determine which overload of the method to call based on the arguments you passed. There is only one choice here. As both before and after the change, displayName is the only overload that is compatible with the arguments you passed.
  3. Determine which implementation of the method to call based on the runtime type of the object on which you called the method. a's runtime type is Faloodeh. Before the change, displayName is not overridden in Faloodeh, so it calls the superclass implementation. After the change, displayName becomes overridden, so the implementation in Faloodeh is called.

Regarding your edit:

In this case, since the compile time type of b is Faloodeh, the class to search is Faloodeh (Step 1). However, there are 2 methods that matches the arguments you gave (Step 2):

  • displayName(String...) which is declared in Faloodeh, and;
  • displayName(String) which is inherited.

In such a situation, the compiler always favours the overload without variable arity - displayName(String). This is specified clearly in JLS §15.12.2. In particular, Step 2 is further split into three more sub-steps. The first sub-step tries to find a method without allowing variable arity methods, and if any sub-step finds any method, the remaining sub-steps are skipped.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=409419&siteId=1