0

I am learning Java and have encountered some inconsistency (due to my lack of knowledge) in the the Collections.reverse() function. Take this code for example:

// file: Person.java
public class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Name: " + name + " Age: " + age;
    }
}
// file: Main.java
import java.util.*;

public class Main {

    public static void main(String[] args) {
        
        ArrayList<Person> persons1 = new ArrayList<>();
        persons1.add(new Person("A", 10));
        persons1.add(new Person("B", 12));
        persons1.add(new Person("C", 14));
        persons1.add(new Person("D", 16));
        persons1.add(new Person("E", 18));

        ArrayList<Person> persons2 = persons1;
        ArrayList<Person> persons3 = new ArrayList<>(persons1);

        System.out.println("------------Elements of person1 List [Before]------------");
        for (Person p : persons1) {
            System.out.println(p);
        }

        Collections.reverse(persons1);

        System.out.println("\n------------Elements of person1 List [After]------------");
        for (Person p : persons1) {
            System.out.println(p);
        }

        System.out.println("\n------------Elements of person2 List------------");
        for (Person p : persons2) {
            System.out.println(p);
        }

        System.out.println("\n------------Elements of person3 List------------");
        for (Person p : persons3) {
            System.out.println(p);
        }
    }
}

Output:

------------Elements of person1 List [Before]------------
Name: A Age: 10
Name: B Age: 12
Name: C Age: 14
Name: D Age: 16
Name: E Age: 18

------------Elements of person1 List [After]------------
Name: E Age: 18
Name: D Age: 16
Name: C Age: 14
Name: B Age: 12
Name: A Age: 10

------------Elements of person2 List------------
Name: E Age: 18
Name: D Age: 16
Name: C Age: 14
Name: B Age: 12
Name: A Age: 10

------------Elements of person3 List------------
Name: A Age: 10
Name: B Age: 12
Name: C Age: 14
Name: D Age: 16
Name: E Age: 18

In the code above, when I reverse the persons1 arraylist, persons2 arraylist is also being reverse, except the persons3 arraylist. It would be great if someone explain me what is happening behind the scenes.

N.B.: I have some understanding of C++ and pointers concepts. Also, I understand creating an instance of a class in Java is equivalent to dynamic allocation in C++. So, what is understand an ArrayList in Java is like a C++ vector of pointers allocated in heap dynamically. Therefore, an ArrayList<Person> is like a dynamically allocated vector<Person *>. When I am adding a instance of Person in Java ArrayList, it is equivalent to pushing back a pointer pointing to a Person object in heap to the vector of Person pointers. When I am assigning persons1 to persons2 ArrayList, it is equivalent to assigning the pointer to Vector of Person pointers, stored in person1, to persons2. Therefore, reversing the persons1 will also reverse persons2. However, when I am creating a new instance of ArrayList of Person and passed the persons1 as argument in the constructor, I am copying the elements of persons1, that is pointers to Person objects. So, reversing persons1 ArrayList does not change the pointers of Person in persons3 ArrayList. This is what I am guessing by applying my C++ pointers knowledge.

Please correct me if I am wrong.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    `persons1` and `persons2` are the one & same object. What you do to it through one variable shall reflect when you inspect it through the other variable. – ernest_k Feb 15 '21 at 05:31
  • What ernest above said. For `person3`, the constructor `new ArrayList( person1 )` is defined to make a shallow copy of the list. That means you have a new list which isn't affected by the `Collections.reverse()`. Reading through your **NB** note, I think you have it 100% correct. However I'm not a C++ expert so take that advisedly. – markspace Feb 15 '21 at 05:36
  • Declare `ArrayList persons3 = new ArrayList<>(persons1);` after `Collections.reverse()` – Phenomenal One Feb 15 '21 at 05:41
  • `persons3 = new ArrayList<>(persons1)` creates a copy of the `persons1` list, so changing `persons1` doesn't affect `persons3`. `persons2 = persons1`, on the other hand, is a *reference to the same list object*. It's not a separate list, it's just a second variable pointing at the same list. Therefore, modifying `persons1` modifies `persons2`. – John Kugelman Feb 15 '21 at 05:43
  • In C++ terms, `ArrayList persons1` is analogous to `std::vector *persons1`. Not only does `persons1` contain pointers, it is also itself a pointer. – John Kugelman Feb 15 '21 at 05:46

0 Answers0