Java 클래스를 불변으로 만들 수있는 방법은 무엇이며 불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?
답변
불변 객체 란 무엇입니까?
불변 객체는 인스턴스화 된 후에 상태를 변경하지 않는 객체입니다.
개체를 변경 불가능하게 만드는 방법은 무엇입니까?
일반적으로 불변 객체는 노출 된 멤버가없고 setter가없는 클래스를 정의하여 만들 수 있습니다.
다음 클래스는 불변 객체를 만듭니다.
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
위의 예에서 볼 수 있듯이의 값은 ImmutableInt
객체가 인스턴스화 될 때만 설정 될 수 있으며 getter ( getValue
) 만 있으면 인스턴스화 후에 객체의 상태를 변경할 수 없습니다.
그러나 개체가 참조하는 모든 개체도 변경 불가능해야하며 그렇지 않으면 개체의 상태를 변경할 수 있다는 점에주의해야합니다.
예를 들어 배열에 대한 참조를 허용하거나 ArrayList
getter를 통해 가져올 수 있도록하면 배열 또는 컬렉션을 변경하여 내부 상태를 변경할 수 있습니다.
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;
}
}
장점 : 불변 객체는 죽을 때까지 초기화 된 값을 포함합니다.
답변
불변 클래스 는 생성 후 객체를 변경할 수없는 클래스 입니다.
불변 클래스는 다음과 같은 경우에 유용합니다.
- 캐싱 목적
- 동시 환경 (ThreadSafe)
- 상속하기 어렵다
- 어떤 환경에서도 값을 변경할 수 없습니다.
예
문자열 클래스
코드 예
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;
}
}
답변
Java 클래스를 불변으로 만들 수있는 방법은 무엇입니까?
JEP 359 가있는 JDK 14+부터 ” records
“를 사용할 수 있습니다 . Immutable 클래스를 만드는 가장 간단하고 번거로운 방법입니다.
레코드 클래스는 레코드 에 대한 설명을 제공하는 레코드로 알려진 고정 필드 세트에 대한 얕은 불변 의 투명한 캐리어입니다 . 각각 은 제공된 값을 보유 하는 필드와 값 을 검색 하는 방법을 제공 합니다. 필드 이름과 접근 자 이름은 구성 요소의 이름과 일치합니다.components
state
component
final
accessor
불변의 직사각형을 만드는 예를 고려해 보겠습니다.
record Rectangle(double length, double width) {}
생성자를 선언 할 필요가 없으며 equals 및 hashCode 메서드를 구현할 필요가 없습니다. 모든 기록에는 이름과 상태 설명이 필요합니다.
var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1
객체 생성 중에 값의 유효성을 검사하려면 생성자를 명시 적으로 선언해야합니다.
public Rectangle {
if (length <= 0.0) {
throw new IllegalArgumentException();
}
}
레코드의 본문은 정적 메서드, 정적 필드, 정적 이니셜 라이저, 생성자, 인스턴스 메서드 및 중첩 유형을 선언 할 수 있습니다.
인스턴스 방법
record Rectangle(double length, double width) {
public double area() {
return this.length * this.width;
}
}
정적 필드, 메서드
상태는 구성 요소의 일부 여야하므로 레코드에 인스턴스 필드를 추가 할 수 없습니다. 그러나 정적 필드와 메서드를 추가 할 수 있습니다.
record Rectangle(double length, double width) {
static double aStaticField;
static void aStaticMethod() {
System.out.println("Hello Static");
}
}
불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?
이전에 게시 된 답변은 불변성의 필요성을 정당화하기에 충분하며 전문가입니다.