Search code examples
javaarraylistreferencereturn-type

Does the ArrayList return type method return the memory address of the ArrayList variable or a copy of it?


I have a piece of code:

public class Check {
    private ArrayList<Integer> diameters;       // Array of diameters

    public Check(int num) {
        diameters = new ArrayList<>(num);       // Create an ArrayList object.
        for(int i = 0; i < num; i++) {          // Initialize the ArrayList.
            diameters.add(i, i + 1);
        }       
    }

    public ArrayList<Integer> getDiameters() {
        return new ArrayList<Integer>(diameters);
    }
}

Does the getDiameters() method return the memory address of diameters ArrayList (if so, do I need to copy each value individually like I did in the constructor) or does it return a copy of all the integers in the diameters ArrayList?

Does the return value of getDiameters() method and the variable diameters point to the same memory location?

Would the below return statement in the getDiameters() method be a valid statement without any compromise to security instead of writing "return new ArrayList<Integer>(diameters);"?

return diameters;

What are the security issues faced, if any, if I write the above statement?


Solution

  • If you do return diameters; your whole diameters ArrayList would be mutable, as you provide a link to it directly. That means you can affect it size and content from outside.

    When you do new ArrayList<Integer>(diameters) - you're providing a copy of ArrayList with the copied values (which are copied by a reference, so basically are the same objects as in original collection).

    For primitive wrapper like Integer - it's safe, but if you were passing mutable Object within the collection - its change would change the original ArrayList content.

    Simple example:

    
    public class Arrayz {
      public static void main(String[] args) {
        List<Integer> array1 = new ArrayList<>();
        array1.add(new Integer(1));
        array1.add(new Integer(2));
        List<Integer> array2 = new ArrayList<>(array1);
    // you can't mutate Integer - it's immutable
        Integer first = array2.get(0); 
        System.out.println(array1);
        System.out.println(array2);
    
        List<Nom> array3 = new ArrayList<>();
        array3.add(new Nom(1));
        array3.add(new Nom(2));
        List<Nom> array4 = new ArrayList<>(array3);
        Nom third = array4.get(0);
    // Nom is muttable - this will affect initial data as the Object itself mutated
        third.a = 88; 
    // this will not - you replaced the Object in copied array only
        array4.set(1, new Nom(33)); 
        System.out.println(array3);
        System.out.println(array4);
      }
    }
    
    public class Nom {
      public int a;
      Nom(int a) {
        this.a = a;
      }
    
      @Override
      public String toString() {
        return "" +a;
      }
    }
    //////////// output:
    [1, 2] // array1
    [1, 2] // array2
    [88, 2] // array3
    [88, 33] // array4
    

    Generally to protect everything you need to pass an immutable collection with immutable objects. First can be achieved by using com.google.common.collect.ImmutableList.of for example.