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
alphareference can only access the fields and methods defined inAlpha.
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.