Sunday, 1 April 2012

Casting Reference Variables- Downcasting, Upcasting

Java allows us to cast variables of one type to another as long as the casting happens between compatible data types.The compatible data types means they should follow the following contracts.

1. Both the reference variables types should be in the same inheritance hierarchy.Else compile-time error occurs.

2. When attempting to cast a reference variable to a type that should pass the IS-A test.Else run-time error occurs ,i.e. throws ClassCastException.

Types of reference variable casting

There are two types of reference variable casting: upcasting and downcasting.

 

Upcasting


You can assign a reference variable to a supertype reference variable explicitly or implicitly.For example


class MobilePhone {
    void makeCall() {
        System.out.println("Call using keyboard");
    }
}

class SmartPhone extends MobilePhone {
    void makeCall() {
        System.out.println("Call using touchscreen");
    }

    void accessWIFIData() {
        System.out.println("Access data from WI-FI network");
    }
}

public class Main {

    public static void main(String args[]) {
        SmartPhone smartp = new SmartPhone();
        MobilePhone mobilep = smartp; //upcasting
        mobilep.makeCall();

    }

}

The output is

Call using touchscreen

The object smartp of type SmartPhone is upcasted to mobilep of type MobilePhone.Notice that with a MobilePhone reference pointing to SmartPhone object, one can access the overridden version of makeCall() method in the SmartPhone class (Polymorphism at work here), but even though the object has accessWIFIData() method it cannot be invoked using a reference of type MobilePhone.

 

 Downcasting

 

If you have a reference variable of supertype that refers to a subtype object,you can assign it to a reference variable of the subtype. You must make an explicit cast to do this, and the result is that you can access the subtype's members with this new reference variable.

Suppose there is a method repairPhone() in the ElectronicRepairShop class.The electronic repair shop is providing service for both mobile phone and smart phone.So we have to send a generic parameter of type MobilePhone to the function repairPhone().

If I pass a SmartPhone object to the method and try to access the accessWIFIData() method there would be a compiler error “Cannot Find Symbol”. So one has to cast the object passed into SmartPhone and then access the method. For example


 class MobilePhone {
    void makeCall() {
        System.out.println("Call using keyboard");
    }
}

class SmartPhone extends MobilePhone {
    void makeCall() {
        System.out.println("Call using touchscreen");
    }

    void accessWIFIData() {
        System.out.println("Access data from WI-FI network");
    }
}

class ElectronicRepairShop {

    void repairPhone(MobilePhone phone) {

        SmartPhone smart = (SmartPhone) phone; //downcasting
        smart.makeCall();
        smart.accessWIFIData();

    }
}

public class Main {

    public static void main(String args[]) {
        SmartPhone sp = new SmartPhone();
        ElectronicRepairShop shop = new ElectronicRepairShop();
        shop.repairPhone(sp);
    }

}


The output is

Call using touchscreen
Access data from WI-FI network

Downcasting is done in the above example.The object of type MobilePhone is converted to more specific class type SmartPhone.There is one problem in our repairPhone() method implementation.Can you guess it ?.If I pass an object of type MobilePhone into the repairPhone() method, what will happen?.An exception will occur,ClassCastException.For example

class MobilePhone {
    void makeCall() {
        System.out.println("Call using keyboard");
    }
}

class SmartPhone extends MobilePhone {
    void makeCall() {
        System.out.println("Call using touchscreen");
    }

    void accessWIFIData() {
        System.out.println("Access data from WI-FI network");
    }
}

class ElectronicRepairShop {

    void repairPhone(MobilePhone phone) {

        SmartPhone smart = (SmartPhone) phone;
        smart.makeCall();
        smart.accessWIFIData();

    }
}

public class Main {

    public static void main(String args[]) {
        MobilePhone mp = new MobilePhone();
        ElectronicRepairShop shop = new ElectronicRepairShop();
        shop.repairPhone(mp);
    }

}


The output is

Exception in thread "main" java.lang.ClassCastException: MobilePhone cannot be cast to SmartPhone
    at ElectronicRepairShop.repairPhone(Main.java:21)
    at Main.main(Main.java:33)



How we can handle it.Before performing downcasting we have to check whether the object passed as parameter is of class type SmartPhone.We can use instanceof operator for this purpose.See the implementation below

class MobilePhone {
    void makeCall() {
        System.out.println("Call using keyboard");
    }
}

class SmartPhone extends MobilePhone {
    void makeCall() {
        System.out.println("Call using touchscreen");
    }

    void accessWIFIData() {
        System.out.println("Access data from WI-FI network");
    }
}

class ElectronicRepairShop {

    void repairPhone(MobilePhone phone) {
        if (phone instanceof SmartPhone) {
            SmartPhone smart = (SmartPhone) phone;
            smart.makeCall();
            smart.accessWIFIData();
        } else {
            phone.makeCall();
        }
    }
}

public class Main {

    public static void main(String args[]) {
        MobilePhone mp = new MobilePhone();
        ElectronicRepairShop shop = new ElectronicRepairShop();
        shop.repairPhone(mp);
    }

}


The output is

Call using keyboard


The links you may like


instanceof operator in Java

ClassCastException in Java

No comments:

Post a Comment