4

I have a subclass ScottishPerson which inherits from the class BritishPerson.

class BritishPerson {
    public String name = "A british name";

    public void salute() {
        System.out.println("Good Morning!");
    }
}

class ScottishPerson extends BritishPerson {
    public String name = "A scottish name "; //Variable overriding
    public String clanName = "MacDonald";

    public void salute() //Method overriding
    {
        System.out.println("Madainn Mhath!");
    }

    public void warcry() {
        System.out.println("Alba Gu Brath!");
    }
}

class Driver {

    public static void main(String[] args) {
        ScottishPerson scottishPerson = new ScottishPerson(); //Created as a subclass, can always be upcasted.
        BritishPerson britishPerson = new BritishPerson(); //Created as the superclass, throws an error when downcasted.
        BritishPerson britishPersonUpcasted =
                new ScottishPerson(); //Created as the subclass but automatically upcasted, can be downcasted again.

        //Checking the methods and parameters of scottishPerson
        scottishPerson.salute();
        scottishPerson.warcry();
        System.out.println(scottishPerson.name);
        System.out.println(scottishPerson.clanName);

        //Checking the methods and parameters of britishPerson
        britishPerson.salute();
        System.out.println(britishPerson.name);

        //Checking the methods and parameters of britishPersonUpcasted
        britishPersonUpcasted.salute();
        System.out.println(britishPersonUpcasted.name);
    }
}

Running the code, this is the output.

Madainn Mhath!
Alba Gu Brath!
A scottish name 
MacDonald
Good Morning!
A british name
Madainn Mhath!
A british name

This is where the confusion lies. Upcasting ScottishPerson to BritishPerson changes the variable name into the one defined un the superclass. Methods and variables that exist only in the subclass such as warcry() and clanName are discarded. However, calling method salute() on the upcasted class still returns the string based on the subclass implementation.

Is it because when I created the object britishPerson I ONLY initialize the BritishPerson class, and that when I created the object britishPersonUpcasted I created both the BritishPerson class and ScottishPerson class which lead to the permanent overriding of the salute() method?

TheValars
  • 281
  • 2
  • 10

5 Answers5

4

The object on which you are actually calling method belongs to ScottishPerson so at compile time it check for the reference variable but the runtime it always executes the methods which belongs to the object not to reference which holding it. The runtime polymorphism actually lie behind this concept.

Gaurav Jeswani
  • 4,410
  • 6
  • 26
  • 47
3

Please have a look at this question for more understanding of upcast and downcast:

What is the difference between up-casting and down-casting with respect to class variable

I also made an example for looking at upcast behavior:

abstract class Animal 
{ 
    public void saySomething()
    {
        System.out.println("Some Animal sound");
    }

    public abstract void getTheBall();
}

class Horse extends Animal
{ 
    public void saySomething()
    {
        System.out.println("Neigh Neigh");
    }

    public void getTheBall()
    {
        System.out.println("I won't, Try a dog, I am a Horse!");
    }
}

class Dog extends Animal 
{ 
    public void saySomething()
    {
        System.out.println("woof woof, waon waon");
    }

    public void getTheBall()
    {
        System.out.println("huf huf, here it is!");
    }
}

public class Main 
{
    public static void main (String [] args) 
    {
        Dog dog = new Dog(); 
        Horse horse = new Horse();
        Animal animal = dog;
        Animal horseAnimal = new Horse();

        //upcasting
        Dog upcastedAnimal = upcastToDog(animal);
        dog.saySomething();
        dog.getTheBall();

        upcastedAnimal.saySomething();
        upcastedAnimal.getTheBall();

        horse.saySomething();
        horse.getTheBall();

        try {
            Dog upcastedDog = upcastToDog(horseAnimal);
        } catch (Exception ex){
            System.out.println(ex.getClass().getSimpleName() + ": Obviously a horse is not a dog!");
        }
    }

    public static Dog upcastToDog(Animal animal){
        return (Dog) animal;
    }
}

Output:

woof woof, waon waon
huf huf, here it is!
woof woof, waon waon
huf huf, here it is!
Neigh Neigh
I won't, Try a dog, I am a Horse!
ClassCastException: Obviously a horse is not a dog!

First of all java will throw exception if incompatible types are trying to be casted.

In the case when cast is possible, overriden methods will always be called from the actual instance. In your case instance is ScottishPerson so methods will be called on ScottishPerson, even if you hold its reference in a BritishPerson.

you can run the example here https://repl.it/B83f/3

In JLS it is covered here "Narrowing Reference Conversion", as he name suggests only reference is narrowed or widened (or upcasted or downcasted) not the instance.

Community
  • 1
  • 1
cpz
  • 1,002
  • 2
  • 12
  • 27
  • I am learning this concept of typecasting and I am unable to understand that you changed the parent class object(Animal) to a child class object(Dog) in `upcastToDog` method, yet you are calling it upcasting. Why? Ain't casting from parent to child class called `downcasting` ? Sorry if I am wrong. – Shashank Gupta Jul 29 '20 at 11:09
1
  • Access to static fields, instance fields and static methods depends on the class of reference variable and not the actual object to which the variable points to.
  • Remember that member variables are shadowed, not overridden.
  • This is opposite of what happens in the case of instance methods.
    In case of instance methods the method of the actual class of the object is called.

Consider the following example.

    class ABCD {
        int x = 10;
        static int y = 20;

        public String getName() {
            return "ABCD";
        }
    }

    class MNOP extends ABCD {
        int x = 30;
        static int y = 40;

        public String getName() {
            return "MNOP";
        }
    }

    public static void main(String[] args) {

      System.out.println(new MNOP().x + ", " + new MNOP().y);

      ABCD a = new MNOP();
      System.out.println(a.x); // 10
      System.out.println(a.y); // 20
      System.out.println(a.getName()); // MNOP
    }

In your scenario, the name property of britishPersonUpcasted object is shadowed by the BritishPerson.

Hope this helps.

tharindu_DG
  • 8,900
  • 6
  • 52
  • 64
1

Variables are not polymorphic in Java. Same variable declared in subclass does not override the value in super class.

To reflect the value associated with super class, you need to pass it to the constructor and set the super class variable using the super keyword. This way:

  public ScottishPerson(String name) {
    super.name = name;
    this.name = name;
  }

Here is your code which I have modified to show that.

class BritishPerson
{
  public String name = "A british name";

    public void salute()
    {
        System.out.println("Good Morning!");
    }

}


class ScottishPerson extends BritishPerson
{
  public String name = "A scottish name "; //Variable overriding
  public String clanName = "MacDonald";

  public ScottishPerson() {
    // TODO Auto-generated constructor stub
  }

  public ScottishPerson(String name) {
    super.name = name;
    this.name = name;
  }

    @Override
    public void salute() //Method overriding
    {
        System.out.println("Madainn Mhath!");
    }

    public void warcry()
    {
        System.out.println("Alba Gu Brath!");
    }

}

public class Driver {



  public static void main(String[] args) {
    // TODO Auto-generated method stub


    ScottishPerson scottishPerson = new ScottishPerson(); //Created as a subclass, can always be upcasted.
    BritishPerson britishPerson = new BritishPerson(); //Created as the superclass, throws an error when downcasted.
    BritishPerson britishPersonUpcasted = new ScottishPerson("Another scottish name"); //Created as the subclass but automatically upcasted, can be downcasted again.

    //Checking the methods and parameters of scottishPerson
    scottishPerson.salute();
    scottishPerson.warcry();
    System.out.println(scottishPerson.name);
    System.out.println(scottishPerson.clanName);

    //Checking the methods and parameters of britishPerson
    britishPerson.salute();
    System.out.println(britishPerson.name);

    //Checking the methods and parameters of britishPersonUpcasted
    britishPersonUpcasted.salute();
    System.out.println(britishPersonUpcasted.name);
  }

}
Joydip Datta
  • 439
  • 3
  • 8
1

You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended).

even-though you want it, you can access it by super keyword

Girdhar Singh Rathore
  • 5,030
  • 7
  • 49
  • 67