[java] 클래스에서 개인 필드가 수정되는 것을 어떻게 방지합니까?

이 수업이 있다고 상상해보십시오.

public class Test
{
  private String[] arr = new String[]{"1","2"};

  public String[] getArr()
  {
    return arr;
  }
}

이제 위의 클래스를 사용하는 다른 클래스가 있습니다.

Test test = new Test();
test.getArr()[0] ="some value!"; //!!!

그래서 이것은 문제입니다 : 나는 외부에서 클래스의 개인 필드에 액세스했습니다! 이 문제를 어떻게 방지 할 수 있습니까? 이 배열을 어떻게 불변으로 만들 수 있습니까? 이것은 모든 getter 메소드에서 개인 필드에 액세스하기 위해 노력할 수 있음을 의미합니까? (구아바와 같은 라이브러리는 원하지 않습니다. 올바른 방법을 알아야합니다.)



답변

배열 의 사본 을 반환해야합니다 .

public String[] getArr() {
  return arr == null ? null : Arrays.copyOf(arr, arr.length);
}


답변

배열 대신 List를 사용할 수있는 경우 Collections는 수정할 수없는 목록을 제공합니다 .

public List<String> getList() {
    return Collections.unmodifiableList(list);
}


답변

수정 private자는 필드 자체 만 다른 클래스에서 액세스하지 못하도록 보호하지만이 필드의 객체 참조는 아닙니다. 참조 된 개체를 보호해야하는 경우에는 제공하지 마십시오. 변화

public String [] getArr ()
{
    return arr;
}

에:

public String [] getArr ()
{
    return arr.clone ();
}

또는

public int getArrLength ()
{
    return arr.length;
}

public String getArrElementAt (int index)
{
    return arr [index];
}


답변

Collections.unmodifiableList이미 언급 된 – Arrays.asList()이상하게 없습니다! 내 해결책은 외부에서 목록을 사용하고 다음과 같이 배열을 래핑하는 것입니다.

String[] arr = new String[]{"1", "2"};
public List<String> getList() {
    return Collections.unmodifiableList(Arrays.asList(arr));
}

배열 복사의 문제점은 코드에 액세스 할 때마다 배열을 수행하고 배열이 큰 경우 가비지 수집기에 대해 많은 작업을 수행한다는 것입니다. 따라서 사본은 간단하지만 실제로 나쁜 접근 방식입니다. “저렴한”이라고 말하지만 메모리가 비쌉니다! 특히 2 개 이상의 요소가있는 경우.

당신의 소스 코드를 보면 Arrays.asListCollections.unmodifiableList이 실제로 많이 만들어지지 않습니다. 첫 번째는 복사하지 않고 배열을 래핑하고 두 번째는 목록을 래핑하여 변경 사항을 사용할 수 없게합니다.


답변

ImmutableList표준보다 나은 것을 사용할 수도 있습니다 unmodifiableList. 이 수업은 Google 에서 만든 구아바 라이브러리의 일부입니다 .

설명은 다음과 같습니다.

여전히 변경할 수있는 별도의 컬렉션에 대한보기 인 Collections.unmodifiableList (java.util.List)와 달리 ImmutableList의 인스턴스에는 자체 개인 데이터가 포함되어 있으며 절대 변경되지 않습니다.

사용 방법에 대한 간단한 예는 다음과 같습니다.

public class Test
{
  private String[] arr = new String[]{"1","2"};

  public ImmutableList<String> getArr()
  {
    return ImmutableList.copyOf(arr);
  }
}


답변

이 관점에서 시스템 배열 사본을 사용해야합니다.

public String[] getArr() {
   if (arr != null) {
      String[] arrcpy = new String[arr.length];
      System.arraycopy(arr, 0, arrcpy, 0, arr.length);
      return arrcpy;
   } else
      return null;
   }
}


답변

데이터 사본을 리턴 할 수 있습니다. 데이터 변경을 선택한 발신자는 사본 만 변경합니다.

public class Test {
    private static String[] arr = new String[] { "1", "2" };

    public String[] getArr() {

        String[] b = new String[arr.length];

        System.arraycopy(arr, 0, b, 0, arr.length);

        return b;
    }
}