Fundamentals 8 min read

Understanding Java Reflection, Serialization, Dynamic Proxies, and Object Cloning

This article explains Java reflection, serialization, dynamic proxy mechanisms, and object cloning techniques, including code examples and the differences between deep and shallow copies, providing a comprehensive overview of these core Java concepts.

Java Captain
Java Captain
Java Captain
Understanding Java Reflection, Serialization, Dynamic Proxies, and Object Cloning

Reflection in Java allows a program to inspect and modify its own structure and behavior at runtime, enabling operations such as determining an object's class, constructing objects, accessing fields and methods, and invoking methods dynamically.

Serialization is the process of converting an object's state into a byte stream for storage or transmission, and it is needed when persisting objects to files or databases, sending objects over sockets, or using RMI.

Dynamic proxies provide a way to create proxy classes at runtime that implement specified interfaces, allowing additional processing such as logging, transaction management, or security checks without modifying the original class.

To implement a dynamic proxy, you define an interface, create an InvocationHandler that receives the target object, and use the Proxy utility class to generate a proxy instance via newInstance() , which delegates method calls to the handler.

Object cloning can be achieved either by implementing the Cloneable interface and overriding Object.clone() , or by using serialization and deserialization to perform a deep copy, as demonstrated in the utility code below.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MyUtil {
    private MyUtil() {
        throw new AssertionError();
    }
    @SuppressWarnings("unchecked")
    public static
T clone(T obj) throws Exception {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bout);
        oos.writeObject(obj);
        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bin);
        return (T) ois.readObject();
        // Note: closing the streams is unnecessary for in‑memory streams.
    }
}
import java.io.Serializable;

/**
 * Person class
 */
class Person implements Serializable {
    private static final long serialVersionUID = -9102017020286042305L;
    private String name;    // 姓名
    private int age;        // 年龄
    private Car car;        // 座驾

    public Person(String name, int age, Car car) {
        this.name = name;
        this.age = age;
        this.car = car;
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public Car getCar() { return car; }
    public void setCar(Car car) { this.car = car; }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
}
import java.io.Serializable;

/**
 * Car class
 */
class Car implements Serializable {
    private static final long serialVersionUID = -5713945027627603702L;
    private String brand;       // 品牌
    private int maxSpeed;       // 最高时速

    public Car(String brand, int maxSpeed) {
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }
    public String getBrand() { return brand; }
    public void setBrand(String brand) { this.brand = brand; }
    public int getMaxSpeed() { return maxSpeed; }
    public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; }
    @Override
    public String toString() {
        return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
    }
}
class CloneTest {
    public static void main(String[] args) {
        try {
            Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
            Person p2 = MyUtil.clone(p1);   // 深度克隆
            p2.getCar().setBrand("BYD");
            // 修改克隆的 Person 对象 p2 关联的汽车对象的品牌属性
            // 原来的 Person 对象 p1 关联的汽车不会受到任何影响,因为在克隆时汽车也被克隆了
            System.out.println(p1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Deep copy creates an entirely independent copy of an object and all objects it references, so modifications to the clone do not affect the original, while shallow copy only duplicates reference addresses, causing both copies to share the same nested objects.

reflectionSerializationCloningdeep copyDynamic Proxyshallow copy
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.