[JAVA] Duplicate an object using a generic type

Introduction

One way to duplicate non-identical objects is to implement the Cloneable interface and override ʻObject # clone`.

However, when I wanted to duplicate an object using a generic type like the following code, I was frustrated because I could not access ʻObject # clone` directly, so I can duplicate an object even if I use a generic type. I decided to devise various things like [^ best].

python


class GenericsSample {
    @SuppressWarnings("unchecked")
	static <T> T cloneSample(T obj) {
        return (T) obj.clone(); //Compile error (invisible clone method)
    }
}

Introducing the interface

python


public interface CloneablePublicly<T> {
    T clone();
}

ʻI made an interface to call a method to clone from the outside instead of Object # clone`. Let's implement this for the class of the object that uses the generic type.

Implementation example


class Sample implements Cloneable, CloneablePublicly<Sample> {
    int value;
    public Sample(int value) {
        this.value = value;
    }
    @Override public Sample clone() {
        try {
            return (Sample) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }
}

Of course, the Cloneable interface is also implemented at the same time. If this is not implemented, it will throw a CloneNotSupportedException.

Duplicate object

After that, if you modify the method as follows, you can duplicate the object using the generic type.

python


class GenericsSample {
    @SuppressWarnings("unchecked")
    static <T> T cloneSample(T obj) {
        if (obj instanceof Cloneable && obj instanceof CloneablePublicly) {
            return ((CloneablePublicly<T>) obj).clone();
        }
		return null;
    }
}

Example of use


Sample samp1 = new Sample(1);
Sample samp2 = GenericsSample.cloneSample(samp1);
System.out.println(samp1.value);    // 1
System.out.println(samp2.value);    // 1
System.out.println(samp1 == samp2); //false (duplicate non-identical object)

bonus

If you don't want to return null, return the optional [^ cost] as follows: This also allows you to do nothing if you cannot duplicate the object.

python


class GenericsSample {
    @SuppressWarnings("unchecked")
    static <T> Optional<T> cloneSample(T obj) {
        return Optional.ofNullable(obj)
            .filter(Cloneable.class::isInstance)
            .filter(CloneablePublicly.class::isInstance)
            .map(o -> ((CloneablePublicly<T>) obj).clone());
    }
}

Example of use


Sample samp1 = new Sample(1);
GenericsSample.cloneSample(samp1).ifPresent(samp2 -> {
    System.out.println(samp1.value);    // 1
    System.out.println(samp2.value);    // 1
    System.out.println(samp1 == samp2); //false (duplicate non-identical object)
});

// Sample samp1 = null;At that time, do nothing.

Postscript

From @ saka1029's comment, we introduced interface inheritance and implementation using boundary type parameters. Thank you!

Inheritance of Cloneable interface


interface CloneablePublicly<T> extends Cloneable {
    T clone();
}

This way you don't have to implement the Cloneable interface for the class of objects that use generic types. ~~ I completely forgot the inheritance function of the interface. ~~

Implementation example


class Sample implements CloneablePublicly<Sample> {
    ... //the same
}

python


class GenericsSample {
    static <T extends CloneablePublicly<T>> T cloneSample(T obj) {
        return Objects.isNull(obj) ? null : obj.clone();
    }
}

Type safety is ensured using borderline parameters, eliminating the need for hand-cast cast inspection. The optional line has been completed.

python


class GenericsSample {
    static <T extends CloneablePublicly<T>> Optional<T> cloneSample(T obj) {
        return Optional.ofNullable(obj).map(CloneablePublicly::clone);
    }
}

[^ best]: I searched a lot, but I couldn't find any material that looked good, so I made it myself. If you have any suggestions or suggestions on best practices, we apologize for the inconvenience, but we would appreciate it if you could teach us. [^ Cost]: According to "Effective Java 3rd Edition", it is costly to use Optional frequently, so it may be better to refrain from it if you are concerned about performance.

Recommended Posts

Duplicate an object using a generic type
Write a null case using the Optional type without using an if statement
A story about saving an image with carrierwave in a nested form using a form object.
java: How to write a generic type list [Note]
A memorandum for creating an extended logger using org.slf4j.Logger
I want to create a generic annotation for a type
Draw a line on an existing PDF document using PDFBox
Procedure for publishing an application using AWS (4) Creating a database