Overview

This note covers the concepts of upcasting, downcasting, and serialization in Java. It explains what happens to object fields during these processes and includes a practical example.

Classes Definition

Let’s define two classes, Alpha and Beta, where Beta is a subclass of Alpha.

class Alpha {
    int a1;
    int a2;
    int a3;
}

class Beta extends Alpha {
    int b4;
}

Upcasting

When you upcast an object of a subclass (Beta) to its superclass (Alpha), you are changing the reference type but not the actual object in memory.

Beta beta = new Beta();
Alpha alpha = (Alpha) beta; // Upcasting Beta to Alpha
  • Memory Layout: The memory layout remains unchanged. The object still contains all fields from both the superclass (Alpha) and subclass (Beta).
  • Reference Type: The reference type changes, so the alpha reference can only access the fields and methods defined in Alpha.

Example

public class Test {
    public static void main(String[] args) {
        Beta beta = new Beta();
        Alpha alpha = (Alpha) beta; // Upcasting Beta to Alpha

        // Accessing fields through alpha reference
        alpha.a1 = 10; // This is allowed
        alpha.a2 = 20; // This is allowed
        alpha.a3 = 30; // This is allowed

        // The following line would cause a compile-time error
        // alpha.b4 = 40; // Not allowed, b4 is not defined in Alpha
    }
}

Downcasting

When you downcast a reference from a superclass to a subclass, you can access the subclass-specific fields and methods.

Beta betaAgain = (Beta) alpha; // Downcasting Alpha to Beta
betaAgain.b4 = 40; // This is allowed

Example

public class Test {
    public static void main(String[] args) {
        Beta beta = new Beta();
        Alpha alpha = (Alpha) beta; // Upcasting Beta to Alpha

        // Downcasting alpha back to Beta
        Beta betaAgain = (Beta) alpha; // Downcasting Alpha to Beta

        // Now you can access the b4 field
        betaAgain.b4 = 40; // This is allowed

        // Verifying access to all fields
        System.out.println("a1: " + betaAgain.a1);
        System.out.println("a2: " + betaAgain.a2);
        System.out.println("a3: " + betaAgain.a3);
        System.out.println("b4: " + betaAgain.b4);
    }
}

Serialization

Serialization is the process of converting an object’s state into a byte stream. All fields of the actual object are included in the serialized form, regardless of the reference type.

Example

import java.io.*;

class Alpha implements Serializable {
    int a1;
    int a2;
    int a3;
}

class Beta extends Alpha {
    int b4;
}

public class TestSerialization {
    public static void main(String[] args) {
        try {
            // Create an instance of Beta
            Beta beta = new Beta();
            beta.a1 = 10;
            beta.a2 = 20;
            beta.a3 = 30;
            beta.b4 = 40;

            // Upcast Beta to Alpha
            Alpha alpha = (Alpha) beta;

            // Serialize the upcasted object
            FileOutputStream fileOut = new FileOutputStream("beta.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(alpha);
            out.close();
            fileOut.close();
            System.out.println("Serialized data is saved in beta.ser");

            // Deserialize the object
            FileInputStream fileIn = new FileInputStream("beta.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            Beta deserializedBeta = (Beta) in.readObject();
            in.close();
            fileIn.close();

            // Verify the fields
            System.out.println("Deserialized Beta:");
            System.out.println("a1: " + deserializedBeta.a1);
            System.out.println("a2: " + deserializedBeta.a2);
            System.out.println("a3: " + deserializedBeta.a3);
            System.out.println("b4: " + deserializedBeta.b4);
        } catch (IOException | ClassNotFoundException i) {
            i.printStackTrace();
        }
    }
}

Output

Serialized data is saved in beta.ser
Deserialized Beta:
a1: 10
a2: 20
a3: 30
b4: 40

Key Points

  • Serialization includes all fields: During serialization, all fields of the actual object are included, not just those accessible through the reference type.
  • Upcasting does not affect serialization: Upcasting an object before serialization does not change the serialized form.
  • Deserialization restores the full object: Deserializing the object will restore all fields, even those specific to the subclass.