Почему делиться изменяемыми внутренностями неизменяемых объектов - хорошая идея? - PullRequest
0 голосов
/ 10 февраля 2019

Я читаю "Эффективную Яву" Джошуа Блоха и у меня два вопроса.Блох утверждает следующее.

Мало того, что вы можете делиться неизменными объектами, но и они могут делиться своими внутренними объектами.

Затем он приводит пример с одним экземпляром BigInteger, разделяющим его величину.массив с другим BigInteger экземпляром.Мой первый вопрос: не нарушает ли это правило, изложенное Блохом ранее, то есть

Обеспечить эксклюзивный доступ к изменяемым компонентам.

В качестве примера того, как совместное использование изменяемых внутренних элементов может быть проблематичным, мне кажется, что если два экземпляра sample1 и sample2 одного и того же класса могут совместно использовать свои внутренние компоненты, то вы можете получить следующее,


public final class Sample {

    private final int[] field1;
    private final int[] field2;

    public Sample(int[] field1, int[] field2) {
        this.field1 = field2;
        this.field2 = field2;
    }

    public Sample(int[] field1, Sample sampleForField2) {
        this.field1 = field1;
        for (int i = 0; i < sampleForField2.field2.length; i++) {
            sampleForField2.field2[i] += 1;
        }
        this.field2 = sampleForField2.field2;
    }

    public static void main(String[] args) {
        Sample sample1 = new Sample(new int[]{0, 1}, new int[]{10, 11});
        Sample sample2 = new Sample(new int[]{20, 21}, sample1);
        System.out.println(Arrays.toString(sample1.field2));
    }

}

В приведенном выше примере a может поделиться своими внутренними объектами с b через конструктор public Sample(int[] field1, Sample sampleForField2).Это приводит к появлению псевдонимов, в результате чего значение sample1 field2 равно {11, 12}.

Таким образом, мой второй вопрос: не нарушит ли неизменяемость внутренности между экземплярами неизменность?

1 Ответ

0 голосов
/ 10 февраля 2019

Хорошо обмениваться внутренностями неизменяемого объекта при условии, что вы выставляете внутренности объекта неизменным образом.

Например:

public class ImmutableObj {

  private final String[] internals;

  public ImmutableObj(String[] strings) {
    internals = Arrays.copyOf(strings, strings.length);
  }

  public String[] getInternals() {
    // return a copy of the internal state, since arrays
    // do not offer an immutable view
    return Arrays.copyOf(internals, internals.length);
  }
}

Массивы неэффективныпример, но это все еще возможно.Гораздо более производительным было бы сохранение / представление внутреннего состояния как своего рода Collection<String>, так что вы можете установить внутренние компоненты для неизменяемого объекта для начала:

public class ImmutableObj {

  // Simply make this public instead of getter since it is read-only
  public final List<String> internals;

  public ImmutableObj(String[] strings) {
    internals = Collections.unmodifiableList(Arrays.asList(strings));
  }

}
...