How to Cast Up to Super Class When There Is an Override Function in the Sub Class

how to cast up to super class when there is an override function in the sub class

Because you're overriding the method in a subclass, you're getting dynamic dispatch. The method implementation to call will be based on the dynamic type of the instance that it's called on. Upcasting a Jaguar to a Car only changes the static type of the instance – the dynamic type is still a Jaguar, for that's the type of instance you created.

Therefore upcasting has no bearing whatsoever on the dynamic dispatch of a method – nor should it, as the whole point of dynamic dispatch is to ensure that the correct method implementation for the given instance is called no matter what it's statically typed as.

The kind of behaviour you're expecting is static dispatch – the compiler chooses the implementation to call based on the static type of the instance. This is commonly achieved by overloading (rather than overriding) functions.

For example, an overloaded static method:

class Car {
static func info(for car: Car) {
print("You've got a Car")
}
}

class Jaguar : Car {
static func info(for jaguar: Jaguar) {
print("You've got a Jaguar")
}
}

let jaguar = Jaguar()
Jaguar.info(for: jaguar) // You've got a Jaguar
Car.info(for: jaguar) // You've got a Car

let car = jaguar as Car
Jaguar.info(for: car) // You've got a Car

Here, the compiler resolves which implementation of info(for:) to call based on the static types of what it's being called on and the arguments being passed. If it's either called on Car, or the argument passed is statically typed as a Car, only Car's overload can possibly be statically dispatched to.

Another example of static dispatch is with a protocol extension, where the method isn't a protocol requirement (as making it a requirement gives it dynamic dispatch).

protocol Car {}

extension Car {
func info() {
print("You've got a Car")
}
}

class Jaguar : Car {
func info() {
print("You've got a Jaguar")
}
}

let jaguar = Jaguar()
jaguar.info() // You've got a Jaguar

let car = jaguar as Car
car.info() // You've got a Car

Here, the compiler resolves which implementation of info() to call solely based on the static type of the instance that it's called on.

Casting to Superclass, and Calling Overriden Method

Casting is solely for the benefit of the compiler. The JVM doesn't know anything about it, and it does not affect what method gets called. The JVM tries to resolve a method by looking for something that matches the given signature, starting with the most specific class and working its way up the hierarchy towards the root (java.lang.Object) until it finds something.

The purpose of polymorphism is so code calling some object doesn't have to know exactly what subclass is being used, the object being called takes care of its own specialized functionality. Having a subclass override a method means that objects of that subclass need to handle that method in their own particular way, and the caller doesn't have to care about it.

Casting is for odd edge cases where your code can't know what type something is. You shouldn't need to cast if you know the super type (Parent in your example), the subclass should take care of itself.

why overridden method calling from Subclass if i have done up-casting?

When using inheritance, the compile-time type of the reference to an object on which you call a method is only used to see (at compile time) if the method may be invoked.

But at the invocation time, it does not matter what that compile-time type is. What really matters in this case is the runtime type of the object. It is Test, so the method is searched on Test first.

For methodOne() it is a bit different: it is not overriden by Test, so the version from its superclass (Example) is invoked.

explicit casting from super class to subclass

By using a cast you're essentially telling the compiler "trust me. I'm a professional, I know what I'm doing and I know that although you can't guarantee it, I'm telling you that this animal variable is definitely going to be a dog."

Since the animal isn't actually a dog (it's an animal, you could do Animal animal = new Dog(); and it'd be a dog) the VM throws an exception at runtime because you've violated that trust (you told the compiler everything would be ok and it's not!)

The compiler is a bit smarter than just blindly accepting everything, if you try and cast objects in different inheritence hierarchies (cast a Dog to a String for example) then the compiler will throw it back at you because it knows that could never possibly work.

Because you're essentially just stopping the compiler from complaining, every time you cast it's important to check that you won't cause a ClassCastException by using instanceof in an if statement (or something to that effect.)

How to cast subclass object to superclass object

A superclass cannot know subclasses methods.

Think about it this way:

  • You have a superclass Pet

  • You have two subclasses of Pet, namely: Cat, Dog

  • Both subclasses would share equal traits, such as speak
  • The Pet superclass is aware of these, as all Pets can speak (even if it doesn't know the exact mechanics of this operation)
  • A Dog however can do things that a cat cannot, i.e. eatHomework
  • If we were to cast a Dog to a Pet, the observers of the application would not be aware that the Pet is in fact a Dog (even if we know this as the implementers)
  • Considering this, it would not make sense to call eatHomework of a Pet

You could solve your problem by telling the program that you know sup is of type subclass

public class Testing
{
public static void main(String args[])
{
subclass sub = new subclass();
superclass sup = (superclass) sub;
subclass theSub = (subclass) sup;
theSub.displaySub();
}
}

You could solve the problem altogether by doing something like this:

public class superclass
{
public void display()
}
System.out.println("Display Superclass");
}
}

public class subclass extends superclass
{
public void display()
{
System.out.println("Display Subclass");
}
}

public class Testing
{
public static void main(String args[])
{
subclass sub = new subclass();
superclass sup = (superclass) sub;
sup.display();
}
}

check out this tutorial on more info: overrides

How does Superclass cast on objects work?

  1. You are casting a subclass to a superclass.
    This is upcasting (or implicit casting) as per: Inheritance -> Casting Obects
    This means that this casting can be done implicitly.
    You do not have to put casting operator after the assignment.
    Every Grad object is implicitly an object of class Upgrad because
    of your declaration: Grad extends Upgrad.
    I.e. this will work:
Upgrad u = g;

  1. You have overriden the perYear() method.
    After casting to a superclass and calling this method it will stay as implemented in Grad class because of polymorphism principles and override rules for Java:
    This questions has in fact been answered here and here on Stackoverflow.
    To quote Learning Java by Daniel Leuck & Patrick Niemeyer:

    When there are multiple implementations of a method in the inheritance hierarchy of an object, the one in the “most derived” class (the furthest down the hierarchy) always overrides the others, even if we refer to the object through a reference of one of the superclass types.

  2. This is defferent from hiding a field.
    Hiding or shadowing a field is best described here:
    Subclassing and inheritance -> Shadowed Variables
    A different set of types is used there in the link but the meaning is the same:

    Another important point about shadowed variables has to do with how they work when we refer to an object by way of a less derived type (a parent type). For example, we can refer to a DecimalCalculator object as an IntegerCalculator by using it via a variable of type IntegerCalculator. If we do so and then access the variable sum, we get the integer variable, not the decimal one:

    DecimalCalculator dc = new DecimalCalculator();

    IntegerCalculator ic = dc;

    int s = ic.sum; // accesses IntegerCalculator sum

    As said in Inheritance -> What You Can Do in a Subclass :

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

Testing code:


class Ugrad {

int DM = 140;
int perYear() { return DM/4; }
}

class Grad extends Ugrad {
int DM = 28; // we have *hidden* Upgrad.DM field by
int perYear() { return DM/2; }
}

public class UpgradGrad {
public static void main(String[] args){
Grad g = new Grad();
System.out.println(g.DM); // Grad.DM field is accessed directly, thus output = 28
System.out.println(g.perYear()); // 14
Ugrad u = g; // this will work because of implicit casting to a superclass
System.out.println(u.DM); // g is casted to u. Grad.DM was hiding Upgrad.DM. Thus Upgrad.DM emerges.
System.out.println(u.perYear()); // because g is just referred to as Upgrad, its original Grad.perYear() method will be called
}
}


Related Topics



Leave a reply



Submit