Возвращает ли метод возвращаемого типа ArrayList адрес памяти переменной ArrayList или ее копию? - PullRequest
3 голосов
/ 21 января 2020

У меня есть фрагмент кода:

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);
    }
}

Возвращает ли метод getDiameters () адрес памяти диаметров ArrayList (если да, нужно ли мне копировать каждое значение отдельно, как я это делал в конструкторе ) или он возвращает копию всех целых чисел в диаметрах ArrayList?

Указывает ли возвращаемое значение метода getDiameters () и переменных переменных на одну и ту же ячейку памяти?

Будет ли приведенный ниже оператор return в методе getDiameters () является допустимым оператором без какого-либо ущерба для безопасности, вместо записи «return new ArrayList (diameters);»?

return diameters;

С какими проблемами безопасности сталкиваются, если таковые имеются, если я напишу приведенное выше утверждение?

Ответы [ 4 ]

2 голосов
/ 21 января 2020
public ArrayList<Integer> getDiameters()
{
    return new ArrayList<Integer>(diameters);
}

Создает новый ArrayList из Integer, давайте процитируем это из документов:

publi c ArrayList (Collection c)

Создает список, содержащий элементы указанной коллекции, в том порядке, в котором они возвращаются итератором коллекции.

Параметры: c - коллекция, элементы которой должны быть помещены в этот список. Throws: NullPointerException - если указанная коллекция является null

https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#ArrayList - java .util.Collection-

Теперь вы передали Collection в конструктор, который на его очередь выдает ArrayList, который похож, но не совпадает с вашим членом данных. Не рекомендуется делать это, если у вас нет очень веских причин для этого, потому что диаметры уже содержат элементы, которые у вас есть.

Что касается безопасности, то единственная проблема безопасности, которую я вижу, это то, что код использование диаметров будет иметь привилегии операции записи для фактического ArrayList. Если вы намерены предотвратить это, не возвращайте фактический ArrayList. Вы можете clone создать его или создать еще один ArrayList (как вы это сделали), или вы можете (и это, на мой взгляд, самое элегантное решение) вызвать unmodifiableList , чтобы вернуть версию только для чтения. Collection.

2 голосов
/ 21 января 2020

Для объектов Java передает ссылку на объект, поэтому метод не будет возвращать глубокую копию списка.

Что касается вопросов безопасности, это означает, что если пользователь манипулирует объектом, возвращаемым return diameters, эти изменения также затронут объект, на который ссылается объект Check, поскольку они являются одним и тем же объектом, который может быть вопрос.

1 голос
/ 21 января 2020

Если вы сделаете return diameters; весь ваш diameters ArrayList будет изменчивым, так как вы предоставите ссылку на него напрямую. Это означает, что вы можете влиять на его размер и содержимое извне.

Когда вы делаете new ArrayList<Integer>(diameters) - вы предоставляете копию ArrayList со скопированными значениями (которые копируются по ссылке, поэтому в основном совпадают объекты, как в исходной коллекции).

Для примитивной оболочки, такой как Integer, - это безопасно, но если вы передаете изменяемый объект в коллекции - его изменение изменит исходное содержимое ArrayList.

Простой пример :


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

Обычно для защиты всего, что вам нужно, необходимо передать неизменную коллекцию с неизменяемыми объектами. Во-первых, можно добиться, используя, например, com.google.common.collect.ImmutableList.of.

1 голос
/ 21 января 2020

getDiameters () вернет адресную память нового созданного ArrayList. Они не указывают на одну и ту же адресную память. он скопирует элементы диаметров в новый ArrayList. Если у вас много потоков, используйте Arraylist, для безопасности вы можете использовать: Collections.synchronizedList(list);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...