Up/Downcasting and Polymorphism

invisibleufo101·2024년 9월 14일

Java

목록 보기
10/10
post-thumbnail

Class Type-Casting

Just like primitive types, class instances can also be typecast in Java, particularly between classes that declared an inheritance relationship (extends).

What is Type-Casting?

Type-casting allows an object of a child class to behave like an object of its parent class, and vice-versa.

Example:

public class Animal {}

public class Cat extends Animal {}

Cat cat = new Cat();      // Instance of Cat class
Animal animal = cat;      // Upcasting: cat is cast to Animal

In this example, the cat object, which is an instance of the Cat class, is automatically upcasted to its parent class Animal. This is possible because the Cat class inherits from the Animal class.


Valid Class Conversions

The conversion (casting) of classes is valid when there is an inheritance relationship. This means a child class can be cast into its parent class.

Multiple Levels of Inheritance:

Even if the class isn’t a direct parent, type-casting is valid as long as the class is a superclass in the inheritance hierarchy.

Example:

// A <- B <- C
class A {}
class B extends A {}
class C extends B {}

C c = new C();
A a = c; // Valid because A is a superclass of C

This follows a tree structure, where as long as the classes are in the same branch, casting is allowed.


Downsides of Upcasting

When a child class is upcasted to its parent class:

  • The child object can no longer access methods that are specific to the child class.
  • If a method exists in both the parent and child class but is overridden in the child class, the child class’s method will be used.

Example:

public class Animal {
    public void sound() {
        System.out.println("Animal makes sound");
    }
}

public class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Dog barks");
    }
}

Dog dog = new Dog();
Animal animal = dog;  // Upcasting
animal.sound();       // Output: "Dog barks" (child method is called)

Here, even though animal is of type Animal, it calls the sound() method from the Dog class because of method override.


Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass

Polymorphism in methods

Polymorphism allows a method to work on objects of different classes, as long as they share a common superclass (or interface). The actual method that gets executed is determined by the object type at runtime, not the reference type.

Example:

public class Vehicle {
    public void run() {
        System.out.println("Vehicle is running");
    }
}

public class Bus extends Vehicle {
    @Override
    public void run() {
        System.out.println("Bus go vroom");
    }
}

public class Taxi extends Vehicle {
    @Override
    public void run() {
        System.out.println("Taxi go skrrrt");
    }
}

public class Driver {
    public void drive(Vehicle vehicle) { // Polymorphic parameter
        vehicle.run();  
    }
}

public class DriverExample {
    public static void main(String[] args) {
        Driver driver = new Driver();
        
        Bus bus = new Bus();
        Taxi taxi = new Taxi();

        driver.drive(bus);  // Output: "Bus go vroom"
        driver.drive(taxi); // Output: "Taxi go skrrrt"
    }
}

In this example, the Driver class’s drive() method accepts an object of type Vehicle. Both Bus and Taxi are subclasses of Vehicle, and their overridden run() methods are called based on the actual object passed.


Downcasting

Downcasting is the opposite of upcasting. It converts a parent class back to a child class's reference. This is useful when you know that the object (that was already upcasted to its superclass) is of a specific subclass and want to access the subclass's specific methods or fields.

Example:

Animal animal = new Dog();  // Upcasting
Dog dog = (Dog) animal;     // Downcasting 
dog.sound();                // Output: "Dog barks"

When you downcast, you must explicitly specify the cast, as shown in the example: (Dog) animal. This allows the object to access the child class’s specific methods.


Forced Type-Casting and Risks

Forced type-casting (downcasting) can lead to a ClassCastException if the object being casted is not actually an instance of the class being cast to. Therefore, downcasting should be done with precaution.

That's why we use:

instanceof

We can use the instanceof operator to check whether an object is an instance of a specific class before downcasting.

Example:

Animal animal = new Dog();  // Upcasting

public class Example {

  public static void main(String[] args){
    someMethod();
  }
    
   public static void someMethod(Animal animal) {
   		if (animal instanceof Dog) { // Using instanceof to safely downcast
        	Dog dog = (Dog) animal;  
	        dog.bark();             // Output: "Woof!"   
    	}
   }
}

In this case, the instanceof check ensures that the downcasting is safe.


Polymorphism in Fields

When a field is declared using a parent class data type, but assigned a value from a child class, the field will be automatically promoted to the parent class’s type.

Example:

public class Animal {
    String type = "Some animal";
}

public class Dog extends Animal {
    String type = "Dog";
}

Animal animal = new Dog();  // Upcasting
System.out.println(animal.type);  // Output: "Some animal"

The output demonstrates that the type field in Animal class is referenced instead of the Dog class.

profile
하나씩 차근차근

0개의 댓글