1

I'm facing such a bizarre behavior in Java(Android Studio). What I've been doing is populating an ArrayList of Strings with some data. Then instantiate an object using that ArrayList, the new object is then added to another ArrayList of the object type.

Here is the constructor of the class:

    protected ArrayList<String> languages;
    public Person(ArrayList<String> languages)
    {
        this.languages=languages;
    }

Then in the Activity, I use two ArrayLists, one called languages and one called Persons. The languages ArrayList is passed to a new object added in Persons.

ArrayList<String> languages=new ArrayList<String>();
ArrayList<Person> Persons=new ArrayList<Person>();

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        .
        .
        .
        .
        .
        .
                english=(CheckBox)findViewById(R.id.english);
                if(anglais.isChecked())
                    languages.add(english.getText().toString());
                Persons.add(new Person(languages));
                Log.i("test: ",Persons.get(0).getLangues().get(0)); // Will show English
                languages.clear(); // Here I clear the languages ArrayList so I can add new languages for another person
                Log.i("test: ",Persons.get(0).getLangues().get(0)); // Produces an exception.
            }
        });
    }

As you can see, I populate languages first, then populate Persons with a new object using languages. In order to add another person with different languages(for example) I must clear the languages ArrayList so I can re-use it.

To test what actually happens, I found out that the first Log will show the added langauge(notice that I am getting the language from Persons, and not languages). However, the second Log will produce an exception stating that the langauges array IN Person class is empty(cleared). What could be causing the clear function not to just clear the languages array, but also the languages array in Person class?

Amine
  • 1,396
  • 4
  • 15
  • 32
  • You are passing a reference to an ArrayList to an object where you save it as a member variable. The Person.languages Object references the same data that the original ArrayList does. To avoid this, you would need to invoke the copy method to clone the data, while creating a new distinct Object. – Zachary Dec 24 '17 at 00:06
  • @Zachary I literally thought Java was a pass-by-value language. I solved the issue. Can you reply to the question so I can pick as correct? – Amine Dec 24 '17 at 00:14

1 Answers1

2

When you call the constructor of the Person class, you pass a reference to the languages ArrayList Object; A reference to the same piece of memory. Invoking methods or changing variables using one of the references will change the Object itself, meaning all references to that Object will too be changed. To better understand this, you should understand how variables work. In Java, a variable is a reference to a chunk of memory; You may may have multiple references to this piece of memory.

public static void main(String args[]) {
    ArrayList<String> list = new ArrayList<>();
    ArrayList<String> newReference;
    list.add("String1");
    list.add("String2");
    list.add("String3");
    newReference = list;
    newReference.remove(0); // This will remove the item in the first index of the object. This will remove from both list and newReference as they are currently referencing the same object.
    newReference = list.clone();
    newReference.remove(0); // This will remove the item in the first index of the object referenced by newReference. It is not the same as that of list as you have cloned the data to a new segment of memory.
}
Zachary
  • 1,693
  • 1
  • 9
  • 13