CloneNotSupportedException in Java

What is CloneNotSupportedException in Java?

CloneNotSupportedException is a checked exception in Java that is thrown when the Object.clone() method is called on an object that does not implement the Cloneable interface.

Cloning in Java refers to creating an exact copy of an object using the clone() method. However, not all objects are cloneable by default. If you call clone() on an object that doesn’t implement the Cloneable marker interface, Java throws a CloneNotSupportedException.

Class Declaration

package java.lang;

public class CloneNotSupportedException extends Exception {
    public CloneNotSupportedException() {
        super();
    }

    public CloneNotSupportedException(String message) {
        super(message);
    }
}

This is a checked exception, meaning it must be handled using a try-catch block or declared with a throws clause.

What is the Cloneable Interface?

The Cloneable interface is a marker interface (an interface with no methods). It signals to the JVM that the class allows field-for-field copying using Object.clone(). If a class doesn’t implement Cloneable, calling clone() on its object throws a CloneNotSupportedException.

When Does CloneNotSupportedException Occur?

  • When super.clone() is called in a class that does not implement Cloneable
  • When a subclass inherits clone() but its parent hasn’t implemented Cloneable
  • When a custom clone() method tries to clone a non-cloneable object

Example 1: Triggering CloneNotSupportedException

This example shows what happens when you try to clone an object that does not implement Cloneable.

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    public Person clonePerson() throws CloneNotSupportedException {
        return (Person) super.clone(); // Will throw CloneNotSupportedException
    }
}

public class CloneFailDemo {
    public static void main(String[] args) {
        Person person1 = new Person("Alice");

        try {
            Person person2 = person1.clonePerson();
            System.out.println("Cloned: " + person2.name);
        } catch (CloneNotSupportedException e) {
            System.out.println("CloneNotSupportedException caught: " + e.getMessage());
        }
    }
}

Expected Output

CloneNotSupportedException caught: null

Explanation

  • The class Person does not implement Cloneable.
  • Calling super.clone() results in CloneNotSupportedException.
  • We catch the exception and print an error message.

Example 2: Fixing the Exception by Implementing Cloneable

Let’s correct the above example by implementing Cloneable and overriding clone() properly.

class Person implements Cloneable {
    String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class CloneSuccessDemo {
    public static void main(String[] args) {
        Person person1 = new Person("Bob");

        try {
            Person person2 = (Person) person1.clone();
            System.out.println("Cloned: " + person2.name);
        } catch (CloneNotSupportedException e) {
            System.out.println("Cloning failed: " + e.getMessage());
        }
    }
}

Expected Output

Cloned: Bob

Explanation

  • We implement the Cloneable interface.
  • Override clone() and call super.clone() inside it.
  • The cloning works, and the cloned object is created successfully.

Deep vs Shallow Copy

Java's default clone() performs a shallow copy — it copies field values directly, including references. For a deep copy (duplicating nested objects), you must override clone() and handle it manually.

Example: Shallow Copy

class Address {
    String city;

    Address(String city) {
        this.city = city;
    }
}

class Employee implements Cloneable {
    String name;
    Address address;

    Employee(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // shallow copy
    }
}

public class ShallowCloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("New York");
        Employee emp1 = new Employee("Tom", addr);
        Employee emp2 = (Employee) emp1.clone();

        emp2.address.city = "Los Angeles";

        System.out.println("Original Employee City: " + emp1.address.city);
        System.out.println("Cloned Employee City: " + emp2.address.city);
    }
}

Expected Output

Original Employee City: Los Angeles
Cloned Employee City: Los Angeles

Explanation: Both objects share the same Address reference because it’s a shallow copy.

How to Handle CloneNotSupportedException

Option 1: Catch it

try {
    Object copy = obj.clone();
} catch (CloneNotSupportedException e) {
    System.err.println("Object cannot be cloned.");
}

Option 2: Declare it

public Object cloneObject() throws CloneNotSupportedException {
    return super.clone();
}

Best Practices

  • Always implement Cloneable if your class overrides clone().
  • Use super.clone() inside your overridden method.
  • Override clone() with protected or public visibility.
  • Document whether your class supports cloning to avoid confusion.

Common Mistakes

  • Not implementing Cloneable but calling super.clone()
  • Relying on shallow copy when deep copy is needed
  • Forgetting to handle CloneNotSupportedException in method calls

Summary

  • CloneNotSupportedException is thrown when an object not implementing Cloneable is cloned.
  • It is a checked exception and must be handled.
  • Implement Cloneable and override clone() to enable object cloning.
  • Be mindful of shallow vs deep copying, especially with reference fields.

Final Thoughts

Understanding CloneNotSupportedException is essential when working with object copying in Java. While cloning is not always the preferred way to duplicate objects (compared to copy constructors or serialization), knowing how it works helps in legacy projects, libraries, or performance-sensitive applications. Handle the exception correctly and choose the right copying method based on your application’s needs.