0

Let's say I have a class Book and one of its attribute is an ArrayList of Strings with the names of the protagonists. When I call clone() on the Book, I expect it to do a shallow copy, i.e., the cloned Book object has its own memory location and attributes like Strings and ints as well but an ArrayList attribute will refer to the same existing ArrayList from the prototype Book. However, when I print this information then it appears that the ArrayList has the same address, but the Strings do not. I find this surprising. Can you explain what happens?

import java.util.List;

public class CloneExample {
    public static void main(String[] args) {
        Story philosophersStoneStory = new Story("Lorem ipsum dolor sit amet consectetuer adipiscing");
        List<String> protagonists = List.of("Harry", "Hermoine", "Ron");
        Book harryPotter = new Book("Harry Potter", 25, philosophersStoneStory, protagonists);

        Book harryPotterRipOff = null;
        Object book = null;
        try {
            //WATCH OUT: STUPID DANGEROUS CAST HERE!!!
            harryPotterRipOff = (Book) harryPotter.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        println("The original");
        printBookDetails(harryPotter);

        println("");

        println("The rip-off clone");
        printBookDetails(harryPotterRipOff);

        println("");
        println("The book is new, but the story is actually the same..");
    }

    public static void println(Object obj) {
        System.out.println(obj);
    }

    public static void printBookDetails(Book book) {
        println(book);
        println(book.getAuthor());
        println(System.identityHashCode(book.getProtagonists()));
        println("Harry lives at: " + System.identityHashCode(book.getProtagonists().get(0).hashCode()));
    }
}

Output is:

The original
Book@65ae6ba4
Story@48cf768c
ArrayList is located at: 1509514333
Harry lives at: 184966243

The rip-off clone
Book@768debd
Story@48cf768c
ArrayList is located at: 1509514333
Harry lives at: 1225616405

The ArrayList is at the same address, but the String "Harry" is not.

Saffie
  • 445
  • 3
  • 15
  • You're making a *shallow* copy or clone of the original, and not changing the references in the copy. For better answers, though, post a valid [mre]. – Hovercraft Full Of Eels Nov 29 '21 at 22:11
  • 1
    Also, a String's hashCode is most definitely *not* its address. String overrides equals ***and*** hashCode, and so Strings that satisfy String equality will have the exact same hashCode regardless of where the object resides in memory. Best that you print out the Strings of interest as well as print the hashCode, and yeah, still post your [mre] since something else is going on here. Also, [Object hashCode does not necessarily equate to the object's memory address](https://stackoverflow.com/questions/16418713/does-hashcode-number-represent-the-memory-address). – Hovercraft Full Of Eels Nov 29 '21 at 22:17
  • 1
    Why do you think the array lists have the same address? I can't see where in your code you print that number after "ArrayList is located at:", but I'm not sure how you'd get the address. Are you sure those aren't just the hash codes? Hash codes are NOT addresses, in general. – Dawood ibn Kareem Nov 29 '21 at 22:28
  • Dear both, thank you for your replies. I understand that clone makes a shallow copy and even mention that in the question. If hashcode does not necessarily equate memory access then that closes this question. – Saffie Dec 01 '21 at 13:21
  • The problem here is that for the "Harry lives at:", you are getting the `hashCode()` of `book.getProtagonists().get(0)`, and then you're passing it to `System.identityHashCode()` again. Since `hashCode()` returns an `int`, and `System.identityHashCode()` takes `Object`, the `int` is wrapped into an `Integer`, and this `Integer` object creation can create different objects each time. Otherwise, since `book.getProtagonists()` is the same, `book.getProtagonists().get(0)` must be the same, and calling either `hashCode()` or `System.identityHashCode()` on that must be the same for both cases. – newacct Dec 14 '21 at 06:05

0 Answers0