Java 클래스를 불변으로 만들 수있는 방법은 무엇이며 불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?
@Immutable에서 주석을 jcabi - 측면
Java 클래스를 불변으로 만들 수있는 방법은 무엇이며 불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?
@Immutable에서 주석을 jcabi - 측면
답변:
불변 객체 란 무엇입니까?
불변 객체는 인스턴스화 된 후에 상태를 변경하지 않는 객체입니다.
개체를 변경 불가능하게 만드는 방법은 무엇입니까?
일반적으로 불변 객체는 노출 된 멤버가없고 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);
}
불변성의 장점은 무엇입니까?
불변성의 장점은 동시성과 함께 제공됩니다. 여러 스레드가 동일한 객체의 상태를 변경하려고 시도 할 수 있기 때문에 변경 가능한 객체의 정확성을 유지하는 것은 어렵습니다. 일부 스레드는 해당 객체에 대한 읽기 및 쓰기의 타이밍에 따라 동일한 객체의 다른 상태를 보게됩니다. 목적.
불변 객체를 가짐으로써 불변 객체의 상태가 변경되지 않으므로 객체를보고있는 모든 스레드가 동일한 상태를 보게 될 것입니다.
return Collections.unmodifiableList(list);읽기 전용보기를 반환 할 수도 있습니다 .
final합니다. 그렇지 않으면 setter 메서드 (또는 다른 종류의 변경 방법 및 변경 가능한 필드)로 확장 할 수 있습니다.
final클래스에 private필드 만 있는 경우에는 그럴 필요가 없습니다.
이미 주어진 답변 외에도, 놓치기 쉬운 세부 사항 (예 : 방어 적 사본)이 있으므로 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(객체 생성 후 값을 변경할 수 없도록)불변 클래스는
스레드로부터 안전 하기 때문에 유용 합니다.
-그들은 또한 당신의 디자인에 대해 깊은 것을 표현합니다 : "이것을 바꿀 수 없습니다.", 그것이 적용될 때, 그것은 당신이 필요한 것입니다.
불변성은 주로 두 가지 방법으로 달성 할 수 있습니다.
final재 할당을 피하기 위해 인스턴스 속성 사용불변성의 장점은 이러한 객체에 대해 만들 수있는 가정입니다.
불변 클래스는 인스턴스화 된 후에 값을 재 할당 할 수 없습니다. 생성자는 해당 전용 변수에 값을 할당합니다. 개체가 null이 될 때까지 setter 메서드를 사용할 수 없기 때문에 값을 변경할 수 없습니다.
불변하기 위해서는 다음을 만족해야합니다.
/**
* 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;
}
}
장점 : 불변 객체는 죽을 때까지 초기화 된 값을 포함합니다.
불변 클래스 는 생성 후 객체를 변경할 수없는 클래스 입니다.
불변 클래스는 다음과 같은 경우에 유용합니다.
예
문자열 클래스
코드 예
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 클래스를 만드는 가장 간단하고 번거로운 방법입니다.
레코드 클래스는 레코드 에 대한 설명을 제공하는 레코드로 알려진 고정 필드 세트에 대한 얕은 불변 의 투명한 캐리어입니다 . 각각 은 제공된 값을 보유 하는 필드와 값 을 검색 하는 방법을 제공 합니다. 필드 이름과 접근 자 이름은 구성 요소의 이름과 일치합니다.componentsstatecomponentfinalaccessor
불변의 직사각형을 만드는 예를 고려해 보겠습니다.
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");
}
}
불변성의 필요성은 무엇이며 이것을 사용하면 어떤 이점이 있습니까?
이전에 게시 된 답변은 불변성의 필요성을 정당화하기에 충분하며 전문가입니다.
불변 객체를 만드는 또 다른 방법은 Immutables.org 라이브러리를 사용하는 것입니다.
필요한 종속성이 추가되었다고 가정하고 추상 접근 자 메서드를 사용하여 추상 클래스를 만듭니다. 인터페이스 또는 주석 (@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();
}
이제 생성 된 변경 불가능한 구현을 생성하고 사용할 수 있습니다.
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)
}
}
불변 클래스는 단순히 인스턴스를 수정할 수없는 클래스입니다.
각 인스턴스에 포함 된 모든 정보는 개체의 수명 동안 고정되므로 변경 사항을 관찰 할 수 없습니다.
변경 불가능한 클래스는 변경 가능한 클래스보다 디자인, 구현 및 사용이 더 쉽습니다.
클래스를 변경 불가능하게 만들려면 다음 5 가지 규칙을 따르십시오.
개체의 상태를 수정하는 메서드를 제공하지 마세요.
클래스를 확장 할 수 없는지 확인하십시오.
모든 필드를 최종적으로 만드십시오.
모든 필드를 비공개로 설정합니다.
변경 가능한 구성 요소에 대한 독점적 인 액세스를 보장합니다.
변경 불가능한 객체는 본질적으로 스레드로부터 안전합니다. 동기화가 필요하지 않습니다.
변경 불가능한 객체는 자유롭게 공유 할 수 있습니다.
불변 객체는 다른 객체를위한 훌륭한 빌딩 블록을 만듭니다.
여기에있는 대부분의 답변은 훌륭하고 일부는 규칙을 언급했지만 이러한 규칙을 따라야하는 이유와시기를 말로 적어 두는 것이 좋습니다. 그래서 아래 설명을하고 있습니다
물론 최종 변수에 Setter를 사용하려고하면 컴파일러에서 오류가 발생합니다.
public class ImmutableClassExplored {
public final int a;
public final int b;
/* OR
Generally we declare all properties as private, but declaring them as public
will not cause any issues in our scenario if we make them final
public final int a = 109;
public final int b = 189;
*/
ImmutableClassExplored(){
this. a = 111;
this.b = 222;
}
ImmutableClassExplored(int a, int b){
this.a = a;
this.b= b;
}
}
클래스를 '최종'으로 선언해야합니까?
1. 프리미티브 멤버 만 있는 경우 : 문제가 없습니다. 클래스에 프리미티브 멤버 만 있으면 클래스를 final로 선언 할 필요가 없습니다.
2. 객체를 멤버 변수로 사용 : 객체를 구성원 변수로 사용하는 경우 해당 객체의 구성원도 최종적으로 만들어야합니다. 우리가 트리를 깊숙이 탐색하고 항상 가능하지 않을 수도있는 모든 객체 / 원본을 최종으로 만들어야 함을 의미합니다. 따라서 해결 방법은 상속을 방지하는 최종 클래스를 만드는 것입니다. 따라서 getter 메서드를 재정의하는 하위 클래스에 대한 질문이 없습니다.
Lombok의 @Value 주석을 사용하여 불변 클래스를 생성 할 수 있습니다. 아래 코드처럼 간단합니다.
@Value
public class LombokImmutable {
int id;
String name;
}
Lombok 사이트의 문서에 따라 :
@Value는 @Data의 변경 불가능한 변형입니다. 모든 필드는 기본적으로 비공개 및 최종으로 만들어지며 setter는 생성되지 않습니다. 불변성은 하위 클래스에 강제 할 수있는 것이 아니기 때문에 클래스 자체도 기본적으로 최종화됩니다. @Data와 마찬가지로 유용한 toString (), equals () 및 hashCode () 메서드도 생성되고, 각 필드는 getter 메서드를 가져오고, 모든 인수를 포함하는 생성자 (필드 선언에서 초기화 된 최종 필드 제외)도 생성됩니다. .
record사용합니까?