IT박스

불변 클래스?

itboxs 2020. 10. 5. 07:46
반응형

불변 클래스?


Java 클래스를 불변으로 만들 수있는 방법은 무엇이며 불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?


불변 객체 란 무엇입니까?

불변 객체는 인스턴스화 된 후에 상태를 변경하지 않는 객체입니다.

객체를 불변으로 만드는 방법?

일반적으로 불변 객체는 노출 된 멤버가없고 setter가없는 클래스를 정의하여 만들 수 있습니다.

다음 클래스는 불변 객체를 만듭니다.

class ImmutableInt {
  private final int value;

  public ImmutableInt(int i) {
    value = i;
  }

  public int getValue() {
    return value;
  }
}

위의 예에서 볼 수 있듯이의 값은 ImmutableInt객체가 인스턴스화 될 때만 설정 될 수 있으며 getter ( getValue) 만 있으면 인스턴스화 후에 객체의 상태를 변경할 수 없습니다.

그러나 개체가 참조하는 모든 개체도 변경 불가능해야하며 그렇지 않으면 개체의 상태를 변경할 수 있다는 점에주의해야합니다.

예를 들어 배열에 대한 참조를 허용하거나 ArrayListgetter를 통해 가져 오도록 허용하면 배열 또는 컬렉션을 변경하여 내부 상태를 변경할 수 있습니다.

class NotQuiteImmutableList<T> {
  private final List<T> list;

  public NotQuiteImmutableList(List<T> list) {
    // creates a new ArrayList and keeps a reference to it.
    this.list = new ArrayList(list); 
  }

  public List<T> getList() {
    return list;
  }
}

위 코드의 문제점 ArrayList은를 통해 획득 getList하고 조작 할 수있어 객체 자체의 상태가 변경되어 불변이 아니라는 것입니다.

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

이 문제를 해결하는 한 가지 방법은 getter에서 호출 될 때 배열 또는 컬렉션의 복사본을 반환하는 것입니다.

public List<T> getList() {
  // return a copy of the list so the internal state cannot be altered
  return new ArrayList(list);
}

불변성의 장점은 무엇입니까?

불변성의 장점은 동시성입니다. 여러 스레드가 동일한 객체의 상태를 변경하려고 할 수 있기 때문에 변경 가능한 객체의 정확성을 유지하는 것은 어렵습니다. 목적.

불변 객체를 가짐으로써 불변 객체의 상태가 변경되지 않기 때문에 객체를보고있는 모든 스레드가 동일한 상태를 보게 될 것입니다.


이미 주어진 답변 외에도, 놓치기 쉬운 세부 사항 (예 : 방어 적 사본)이 있으므로 Effective Java, 2nd Ed.의 불변성에 대해 읽는 것이 좋습니다. 또한, Effective Java 2nd Ed. 모든 Java 개발자가 반드시 읽어야 할 문서입니다.


다음과 같이 클래스를 불변으로 만듭니다.

public final class Immutable
{
    private final String name;

    public Immutable(String name) 
    {
        this.name = name;
    }

    public String getName() { return this.name; } 

    // No setter;
}

다음은 Java 클래스를 변경 불가능하게 만들기위한 요구 사항입니다.

  • 클래스 를 다음과 같이 선언해야합니다 final(하위 클래스를 만들 수 없음).
  • 클래스의 멤버 는 다음과 같이 선언되어야합니다 final(객체 생성 후 값을 변경할 수 없도록)
  • 멤버을 가져 오기 위해 모든 변수에 대해 Getter 메서드작성 합니다.
  • Setters 메서드 없음

불변 클래스는
스레드로부터 안전 하기 때문에 유용 합니다.
-그들은 또한 당신의 디자인에 대해 깊은 것을 표현합니다 : "이것을 바꿀 수 없습니다.", 그것이 적용되면 정확히 당신이 필요로하는 것입니다.


불변성은 주로 두 가지 방법으로 달성 할 수 있습니다.

  • final재 할당을 피하기 위해 인스턴스 속성 사용
  • 클래스 내부의 내용을 수정할 수있는 작업을 허용하지 않는 클래스 인터페이스를 사용합니다 ( 게터 만 사용 하고 세터 없음

불변성의 장점은 다음 객체에 대해 할 수있는 가정입니다.

  • 부작용이없는 규칙 (함수 프로그래밍 언어에서 매우 인기가 있음)을 얻고 동시 환경에서 객체를 더 쉽게 사용할 수 있습니다. 객체가있을 때 원자 적 또는 비원 자적 방식으로 변경할 수 없다는 것을 알고 있기 때문입니다. 많은 스레드에서 사용
  • 언어 구현은 이러한 객체를 다른 방식으로 처리하여 정적 데이터에 사용되는 메모리 영역에 배치하여 이러한 객체를 더 빠르고 안전하게 사용할 수 있도록합니다 (이는 문자열의 JVM 내부에서 발생합니다).

불변 클래스는 인스턴스화 된 후에 값을 재 할당 할 수 없습니다. 생성자는 개인 변수에 값을 할당합니다. 개체가 null이 될 때까지 setter 메서드를 사용할 수 없기 때문에 값을 변경할 수 없습니다.

불변하기 위해서는 다음을 만족해야합니다.

  • Al 변수는 private 이어야합니다 .
  • mutator 메서드 (세터)가 제공 되지 않습니다 .
  • class final (Strong Immutability) 또는 메서드를 final (Week immutability)로 만들어 메서드 재정의를 피하십시오.
  • 기본이 아니거나 변경 가능한 클래스가 포함 된 경우 깊게 복제하십시오.

/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {

// make the variables private
private String Name;

//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}

//provide getters to access values
public String getName() {

return this.Name;
}
}

장점 : 불변 객체는 죽을 때까지 초기화 된 값을 포함합니다.

java-immutable-classes-short-note


불변 클래스 는 생성 후 객체를 변경할 수없는 클래스 입니다.

변경 불가능한 클래스는 다음과 같은 경우에 유용합니다.

  • 캐싱 목적
  • 동시 환경 (ThreadSafe)
  • Hard for inheritance
  • Value cannot be changed in any environment

Example

String Class

Code Example

public final class Student {
    private final String name;
    private final String rollNumber;

    public Student(String name, String rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
    }

    public String getName() {
        return this.name;
    }

    public String getRollNumber() {
        return this.rollNumber;
    }
}

Another way to make immutable object is using Immutables.org library:

Assuming that required dependencies were added, create an abstract class with abstract accessor methods. You can do the same by annotating with interfaces or even annotations (@interface):

package info.sample;

import java.util.List;
import java.util.Set;
import org.immutables.value.Value;

@Value.Immutable
public abstract class FoobarValue {
  public abstract int foo();
  public abstract String bar();
  public abstract List<Integer> buz();
  public abstract Set<Long> crux();
}

It is now possible to generate and then use the generated immutable implementation:

package info.sample;

import java.util.List;

public class FoobarValueMain {
  public static void main(String... args) {
    FoobarValue value = ImmutableFoobarValue.builder()
        .foo(2)
        .bar("Bar")
        .addBuz(1, 3, 4)
        .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}

    int foo = value.foo(); // 2

    List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
  }
}

As a non-native English speaker, I dislike the common interpretation of "immutable class" being "constructed class objects are immutable"; rather, I myself lean to interpret that as "the class object itself is immutable".

That said, "immutable class" is a kind of immutable object. The difference is when answering what the benefit is. To my knowledge/interpretation, immutable class prevents its objects from runtime behavior modifications.

참고URL : https://stackoverflow.com/questions/3162665/immutable-class

반응형