불변의 의미는 무엇인가?
이것은 지금까지 물어본 것 중 가장 멍청한 질문일 수도 있지만 나는 자바 신인으로서는 꽤 혼란스러운 질문이라고 생각한다.
- 누군가가 불변의 의미를 명확히 할 수 있을까?
- 왜 a인가
String
불변의? - 불변의 물건의 장단점은 무엇인가?
- 왜 다음과 같은 돌연변이가 가능한 물체가 있어야 하는가?
StringBuilder
스트링과 반대편보다 선호되는가?
(자바어로) 좋은 예가 정말 고마워할 것이다.
불변성은 객체의 생성자가 실행을 완료한 후에는 해당 인스턴스를 변경할 수 없음을 의미한다.
이것은 다른 사람이 그 내용을 바꿀 것이라는 걱정 없이 그 사물에 대한 참조를 전달할 수 있다는 것을 의미하기 때문에 유용하다.특히 동시성을 다룰 때는 절대 변하지 않는 물체에 잠금 문제가 없다.
예)
class Foo
{
private final String myvar;
public Foo(final String initialValue)
{
this.myvar = initialValue;
}
public String getValue()
{
return this.myvar;
}
}
Foo
전화를 건 사람은 걱정할 필요가 없다.getValue()
문자열의 텍스트를 변경할 수 있음.
만약 당신이 비슷한 수업을 상상한다면Foo
, 그러나 .StringBuilder
String
회원으로서, 당신은 전화를 건 사람을 볼 수 있다.getValue()
이 모든 것을 바꿀 수 있을 것이다.StringBuilder
의 .Foo
인스턴스
또한 여러분이 발견할 수 있는 다른 종류의 불변성을 조심하라: 에릭 리퍼트는 이것에 대해 블로그 기사를 썼다.기본적으로 인터페이스가 불변하는 객체를 가질 수 있지만, 무대 뒤에서 실제 돌연변이가 개인 상태를 방해(따라서 스레드 간에 안전하게 공유할 수 없음)
불변의 객체는 내부 필드(또는 적어도 외부 행동에 영향을 미치는 모든 내부 필드)를 변경할 수 없는 객체를 말한다.
불변의 문자열에는 많은 이점이 있다.
성능:다음 작업을 수행하십시오.
String substring = fullstring.substring(x,y);
하위 문자열() 방법에 대한 기본 C는 다음과 같은 것일 수 있다.
// Assume string is stored like this:
struct String { char* characters; unsigned int length; };
// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
struct String* out = malloc(sizeof(struct String));
out->characters = in->characters + begin;
out->length = end - begin;
return out;
}
어떤 문자도 복사할 수 없다는 점에 유의하십시오!문자열 객체가 변경될 수 있는 경우(문자는 나중에 변경될 수 있음) 모든 문자를 복사해야 하며, 그렇지 않으면 하위 문자열의 문자에 대한 변경 내용이 나중에 다른 문자열에 반영된다.
동시성: 불변의 객체의 내부 구조가 유효하다면, 언제나 유효할 것이다.다른 스레드가 그 개체 내에 유효하지 않은 상태를 만들 가능성은 없다.따라서 불변의 물체는 스레드 세이프(Trad Safe)이다.
가비지 수집:쓰레기 수집가가 불변의 물건에 대해 논리적인 결정을 내리는 것은 훨씬 쉽다.
그러나 불변성의 단점도 있다.
성능:잠깐, 난 네가 퍼포먼스는 불변성의 거꾸로라고 말한 줄 알았어!글쎄, 가끔은 그렇지만 항상은 아니야.다음 코드를 입력하십시오.
foo = foo.substring(0,4) + "a" + foo.substring(5); // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder
두 줄 모두 네 번째 문자를 "a"로 대체한다.두 번째 코드는 더 읽기 쉬울 뿐만 아니라 더 빠르다.foo에 대한 기본 코드를 어떻게 해야 하는지 봐.하위 문자열은 쉽지만, 5번 스페이스에 이미 문자가 있고 다른 것이 foo를 참조하고 있을 수 있기 때문에, 그것을 그냥 변경할 수는 없다; 전체 문자열을 복사해야 한다(물론 이 기능 중 일부는 실제 기초 C의 기능으로 추상화되지만, 여기서 요점은 한 번에 모두 실행되는 코드를 보여주는 것이다.…을 배치하다
struct String* concatenate(struct String* first, struct String* second)
{
struct String* new = malloc(sizeof(struct String));
new->length = first->length + second->length;
new->characters = malloc(new->length);
int i;
for(i = 0; i < first->length; i++)
new->characters[i] = first->characters[i];
for(; i - first->length < second->length; i++)
new->characters[i] = second->characters[i - first->length];
return new;
}
// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));
연결은 전체 문자열을 루핑해야 한다는 의미로 두 번 호출된다는 점에 유의하십시오!이 값을 의 C 코드와 비교해 보십시오.bar
작업:
bar->characters[4] = 'a';
변이 가능한 끈 조작은 분명히 훨씬 더 빠르다.
결론:대부분의 경우, 당신은 불변의 문자열을 원한다.그러나 끈에 많은 덧셈과 삽입을 해야 한다면 속도에 대한 변이성이 필요하다.동시성 안전 및 가비지 수집 혜택을 얻으려면 변이 가능한 개체를 메소드에 로컬로 유지하는 것이 핵심이다.
// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
StringBuilder mutable;
boolean first = true;
for(int i = 0; i < strings.length; i++)
{
if(!first) first = false;
else mutable.append(separator);
mutable.append(strings[i]);
}
return mutable.toString();
}
그 이후mutable
개체는 로컬 참조이므로 동시성 안전성에 대해 걱정할 필요가 없음(단 한 개의 스레드만 닿음).그리고 다른 곳에서는 참조되지 않기 때문에 스택에만 할당되므로 함수 호출이 끝나는 대로 할당을 해제한다(쓰레기 수집에 대해 걱정할 필요가 없다).그리고 돌연변이와 불변이의 모든 성능상의 이점을 누릴 수 있다.
위에서 제시된 위키백과 정의를 사용한다면 실제로 문자열은 불변의 것이 아니다.
String의 상태는 사후 시공에 변화를 준다.해시코드() 방법을 살펴본다.문자열은 로컬 필드의 해시코드 값을 캐시하지만 해시코드()의 첫 번째 호출이 있을 때까지 계산하지 않는다.이러한 해시코드의 게으른 평가는 String을 상태가 변화하는 불변의 개체로서 흥미로운 위치에 놓지만, 반사를 사용하지 않고서는 변화했다고 볼 수 없다.
그래서 아마도 불변의 정의는 변했다고 관찰할 수 없는 사물이어야 할 것이다.
만일 국가가 창조된 후 불변의 개체에서 변화하지만 아무도 그것을 볼 수 없다면(반영 없이) 그 개체는 여전히 불변의 개체인가?
불변의 객체는 프로그램적으로 변경할 수 없는 객체다.특히 다중 스레드 환경이나 둘 이상의 프로세스가 객체에서 값을 변경(교체)할 수 있는 기타 환경에 좋다.
그러나 명확히 하자면 스트링빌더(StringBuilder)는 사실 변이 가능한 물체이지 불변의 물체가 아니다.일반 Java String은 불변(한 번 생성된 후에는 객체를 변경하지 않고 기본 문자열을 변경할 수 없다는 의미)이다.
예를 들어, 내가 String 값과 String 색상을 가진 ColoredString이라는 클래스가 있다고 하자.
public class ColoredString {
private String color;
private String string;
public ColoredString(String color, String string) {
this.color = color;
this.string = string;
}
public String getColor() { return this.color; }
public String getString() { return this.string; }
public void setColor(String newColor) {
this.color = newColor;
}
}
이 예에서 ColoredString은 새로운 ColoredString 클래스를 만들지 않고도 핵심 속성 중 하나를 변경(교체)할 수 있기 때문에 변이 가능하다고 한다.이것이 좋지 않은 이유는 예를 들어, 여러 개의 스레드가 있는 GUI 응용 프로그램이 있고 ColoredStrings를 사용하여 데이터를 창에 인쇄하고 있다고 합시다.다음으로 작성된 ColoredString 인스턴스가 있는 경우
new ColoredString("Blue", "This is a blue string!");
그러면 당신은 그 끈이 항상 "파란색"이 될 것이라고 예상할 것이다.그러나 다른 스레드가 이 인스턴스를 입수하여 호출한 경우
blueString.setColor("Red");
"파란색"을 원했을 때 갑자기, 그리고 아마도 예상치 못하게 "빨간색" 줄이 생겼을 겁니다.이 때문에 불변의 객체는 사물의 인스턴스를 전달할 때 거의 항상 선호된다.변이 가능한 물체가 정말로 필요한 경우, 일반적으로 특정 제어 영역에서 복사본만 전달하여 Objet를 보호하십시오.
Java, Java.lang에서 다시 캡슐화하려면문자열은 불변의 개체(한 번 생성되면 변경할 수 없음)와 java.lang이다.StringBuilder는 새 인스턴스를 만들지 않고도 변경할 수 있기 때문에 변경 가능한 개체다.
- 대규모 애플리케이션에서는 문자열 리터럴이 큰 메모리 비트를 차지하는 것이 일반적이다.그래서 메모리를 효율적으로 처리하기 위해 JVM은 "String constant pool"이라고 불리는 영역을 할당한다.(기억에서는 참조되지 않은 문자열도 문자[]를, 문자열의 길이를 나타내는 int를, 그리고 해시코드를 나타내는 문자[]를 가지고 있다는 점에 유의하십시오. 숫자의 경우, 반대로, 최대 8개의 즉시 바이트가 필요하다.)
- 컴파이터가 String 리터럴에 도달하면 풀에서 동일한 리터럴이 이미 있는지 확인하십시오.그리고 하나가 발견되면, 새로운 리터럴에 대한 참조는 기존 스트링으로 향하며, 새로운 '스트링 리터럴 객체'는 생성되지 않는다(기존 스트링에는 단순히 추가 참조가 주어진다).
- 그러므로 : 문자열 변이성은 메모리를 절약한다...
- 그러나 변수들 중 어떤 것이든 값을 변경할 때, 실제로 - 그것은 그들의 참조일 뿐, 메모리의 값에는 영향을 미치지 않는다(그렇다고 해서 그것을 참조하는 다른 변수들에는 영향을 미치지 않는다).
문자열 s1 = "이전 문자열";
//s1 variable, refers to string in memory
reference | MEMORY |
variables | |
[s1] --------------->| "Old String" |
문자열 s2 = s1;
//s2 refers to same string as s1
| |
[s1] --------------->| "Old String" |
[s2] ------------------------^
s1 = "새 문자열";
//s1 deletes reference to old string and points to the newly created one
[s1] -----|--------->| "New String" |
| | |
|~~~~~~~~~X| "Old String" |
[s2] ------------------------^
원래 문자열 'in memory'는 변경되지 않았지만, 참조 변수는 새로운 문자열을 가리키도록 변경되었다.그리고 만약 s2가 없다면, "Old String"은 여전히 기억 속에 있을 것이지만, 우리는 그것에 접근할 수 없을 것이다...
"불가능"은 값을 바꿀 수 없다는 것을 의미한다.문자열 클래스의 인스턴스가 있는 경우 값을 수정하는 것처럼 호출하는 모든 메서드는 실제로 다른 문자열을 생성한다.
String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"
변화를 보존하기 위해서는 이런 foo = foo와 같은 것을 해야 한다.유지 (3);
컬렉션을 작업할 때 불변 대 변이성은 우스울 수 있다.변이 가능한 객체를 지도 키로 사용한 다음 값을 변경하면 어떻게 되는지 생각해 보십시오(팁: 생각해 보십시오).equals
, 그리고hashCode
).
자바.시간
조금 늦을 수도 있지만, 불변의 객체가 무엇인지 이해하기 위해서는 새로운 Java 8 Date and Time API(java.time)의 다음 예를 들어보자.Java 8의 모든 날짜 객체는 불변성이므로 다음 예에서 확인하십시오.
LocalDate date = LocalDate.of(2014, 3, 18);
date.plusYears(2);
System.out.println(date);
출력:
2014-03-18
이것은 초기 날짜와 같은 연도를 인쇄한다.plusYears(2)
새 개체를 반환하여 이전 날짜가 변경되지 않도록 하십시오. 이전가가가지 일단 되면 더 할 수 일단 작성된 날짜는 더 이상 수정할 수 없으며 날짜 변수는 여전히 해당 날짜를 가리킨다.
따라서 이 코드 예는 해당 호출에 의해 인스턴스화되고 반환된 새로운 개체를 캡처하여 사용해야 한다.plusYears
.
LocalDate date = LocalDate.of(2014, 3, 18);
LocalDate dateAfterTwoYears = date.plusYears(2);
date.toString()… 2014-03-18
dateAfter2Years.toString()… 2016-03-18
나는 SCJP Sun Certified Programmer for Java 5 Study Guide의 설명이 정말 마음에 들어.
Java의 메모리를 더욱 효율적으로 만들기 위해 JVM은 "String constant pool"이라고 불리는 특별한 메모리 영역을 따로 설정한다.컴파일러가 String 리터럴을 발견하면 동일한 String이 이미 존재하는지 확인하기 위해 풀을 검사한다.일치 항목이 발견되면 새 리터럴에 대한 참조가 기존 스트링으로 연결되고 새 스트링 리터럴 개체가 생성되지 않는다.
불변의 개체들은 만들어진 후에 상태를 바꿀 수 없다.
언제든지 불변의 객체를 사용할 수 있는 세 가지 주요 이유가 있으며, 이 모든 것이 코드에 도입되는 버그 수를 줄이는 데 도움이 될 것이다.
- 다른 방법으로 개체 상태를 변경할 수 없다는 것을 알고 있을 때 프로그램이 어떻게 작동하는지 추론하는 것이 훨씬 쉽다.
- 불변의 객체는 자동으로 안전하게 스레드되므로(안전하게 게시된 것으로 가정) 고정하기 어려운 다중 스레딩 버그의 원인이 결코 되지 않을 것이다.
- 불변의 객체는 항상 동일한 해시 코드를 가지므로 해시맵(또는 이와 유사함)에서 키로 사용할 수 있다.만약 해시 테이블에서 요소의 해시 코드가 변경된다면, 테이블에서 그것을 찾으려는 시도는 결국 엉뚱한 곳을 찾게 되기 때문에, 테이블 항목이 사실상 손실될 것이다.이것이 String 객체가 불변하는 주된 이유다 - 그것들은 HashMap 키로 자주 사용된다.
또한 개체의 상태가 불변하다는 것을 알 때 코드에서 할 수 있는 몇 가지 다른 최적화(예: 계산된 해시 캐싱)도 있지만, 이러한 최적화들은 최적화여서 거의 흥미롭지 않다.
한 가지 의미는 값이 컴퓨터에 저장되는 방법과 관련이 있다.예를 들어, Net 문자열은 메모리에 있는 문자열을 변경할 수 없다는 것을 의미한다. 이 문자열을 변경하고 있다고 생각할 때, 실제로 메모리에 새 문자열을 만들고 기존 변수(다른 곳에 있는 실제 문자 집합에 대한 포인터일 뿐)를 새 문자열을 가리키고 있다.
String s1="Hi";
String s2=s1;
s1="Bye";
System.out.println(s2); //Hi (if String was mutable output would be: Bye)
System.out.println(s1); //Bye
s1="Hi"
: 객체s1
에 "Hi가 들어 있는 Hi" 값을 사용하여 생성되었다.
s2=s1
: 객체s2
s1 객체를 참조하여 생성된다.
s1="Bye"
: 전s1
때문에 사물의 가치는 변하지 않는다.s1
String String type 은 String type을 가지고 있다.s1
그것에 언급되어 있다.여기 인쇄할 때s2
값, 결과는 "안녕"이 아니라 "안녕"이 될 것이다.s2
전을 s1
Hi" 값을 가진 객체.
불변이란 일단 객체가 생성되면 그 구성원이 아닌 사람이 바뀐다는 것을 의미한다.String
당신은 그것의 내용을 바꿀 수 없기 때문에 불변의 것이다.예를 들면 다음과 같다.
String s1 = " abc ";
String s2 = s1.trim();
위의 코드에서 문자열 s1은 변경되지 않았으며, 다른 개체(s2
)은(는) 다음을 사용하여 생성됨s1
.
불변이란 단순히 변경할 수 없거나 수정할 수 없는 것을 의미한다.문자열 개체가 생성되면 해당 데이터 또는 상태를 변경할 수 없음
예를 들어보자.
class Testimmutablestring{
public static void main(String args[]){
String s="Future";
s.concat(" World");//concat() method appends the string at the end
System.out.println(s);//will print Future because strings are immutable objects
}
}
아래 도표를 보고 아이디어를 내자.
이 도표에서, 당신은 "미래 세계"로 만들어진 새로운 물체를 볼 수 있다.그러나 "미래"를 바꾸지 않는다.Because String is immutable
.s
, 여전히 "미래"를 가리킨다."미래 세계"라고 불러야 한다면
String s="Future";
s=s.concat(" World");
System.out.println(s);//print Future World
문자열 개체가 Java에서 불변하는 이유는?
왜냐하면 자바는 문자열 리터럴의 개념을 사용하기 때문이다.기준 변수가 5개 있다고 가정하고, 모두 하나의 객체 "미래"를 가리킨다.하나의 기준 변수가 개체의 값을 변경하면 모든 기준 변수에 영향을 미친다.그래서 문자열 오브젝트는 자바에서 불변한다.
한번 선동하면 바꿀 수 없다.의 인스턴스가 해시 테이블 등의 키로 사용될 수 있는 클래스를 고려하십시오.Java 모범 사례를 확인하십시오.
합격된 답은 모든 질문에 답하지 않기 때문이다.11년 6개월이 지나서야 대답을 할 수밖에 없다.
누군가가 불변의 의미를 명확히 할 수 있을까?
당신이 불변의 대상을 의미했기를 바란다. (불변의 참조에 대해 생각할 수 있기 때문이다.
객체는 불변하다: 한번 생성되면 항상 같은 값을 나타낸다(값을 변경하는 방법은 없다).
왜 a인가
String
불변의?
Sting.java 소스 코드를 조사하여 확인할 수 있는 위의 정의를 존중하십시오.
불변의 물건의 장단점은 무엇인가?불변의 종류:
벌레로부터 안전한
이해하기 쉬운
변화를 위한 더 많은 준비가 되어 있다.
StringBuilder와 같은 돌연변이가 가능한 객체가 String 및 반대 방향보다 선호되어야 하는 이유는 무엇인가?
질문의 범위를 좁히는 중. 프로그래밍에 돌연변이 가능한 StringBuilder가 필요한 이유는?이를 위한 일반적인 용도는 다음과 같이 많은 수의 문자열을 함께 연결시키는 것이다.
String s = "";
for (int i = 0; i < n; ++i) {
s = s + n;
}
불변의 문자열을 사용하여 많은 임시 복사본을 만들 수 있는데, 이 문자열의 첫 번째 숫자("0")는 실제로 최종 문자열을 구성하는 과정에서 n번 복사되고, 두 번째 숫자는 n-1번 복사된다.비록 우리가 n개의 요소만 연결했음에도 불구하고, 실제로 그 모든 복사를 하는 데만 O(2) 시간이 든다.
StringBuilder는 이 복사를 최소화하도록 설계되었다.toString() 호출로 최종 String()을 요청하는 경우, 간단하지만 영리한 내부 데이터 구조를 사용하여 맨 끝까지 복사를 전혀 하지 않는다.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
sb.append(String.valueOf(n));
}
String s = sb.toString();
우리가 변이 가능한 물체를 사용하는 이유 중 하나는 좋은 성능을 얻는 것이다.다른 하나는 편리한 공유다. 프로그램의 두 부분이 공통의 돌연변이가 가능한 데이터 구조를 공유함으로써 보다 편리하게 의사소통을 할 수 있다.
여기서 더 많은 것을 찾을 수 있다: https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#message_imfable_properties.
불변의 개체
어떤 물체는 그것이 만들어진 후에 그것의 상태가 변할 수 없다면 불변으로 간주된다.불변의 객체에 대한 최대의 의존은 단순하고 신뢰할 수 있는 코드를 만들기 위한 건전한 전략으로 널리 받아들여지고 있다.
불변의 객체는 특히 동시적 애플리케이션에서 유용하다.상태를 변경할 수 없기 때문에 나사산 간섭에 의해 손상되거나 일관되지 않은 상태에서 관찰될 수 없다.
프로그래머들은 종종 불변의 물체를 사용하는 것을 꺼린다. 왜냐하면 그들은 새로운 물체를 만드는 비용을 걱정하기 때문이다. 왜냐하면 그들은 제자리에 있는 물체를 업데이트하는 것과는 반대로 새로운 물체를 만드는 것에 대한 비용을 걱정하기 때문이다.개체 생성의 영향은 종종 과대평가되며, 불변의 개체와 관련된 효율성 중 일부에 의해 상쇄될 수 있다.여기에는 가비지 수집으로 인한 오버헤드 감소, 변이 가능한 개체를 손상으로부터 보호하는 데 필요한 코드 제거 등이 포함된다.
다음 하위섹션은 인스턴스(instance)가 변이 가능한 클래스를 취하며, 그것으로부터 인스턴스(instance)가 불변하는 클래스를 파생한다.그렇게 함으로써, 그들은 이런 종류의 변환에 대한 일반적인 규칙을 주고 불변의 객체의 장점들을 보여준다.
불변의 객체는 당신이 그것을 만든 후에 수정할 수 없는 객체를 말한다.대표적인 예가 문자열 리터럴이다.
점점 인기가 높아지는 D 프로그래밍 언어는 '불변' 키워드를 통해 '불변성'이라는 개념을 갖고 있다.이 박사님을 확인해 보십시오.Dobb의 그것에 대한 기사 - http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29. 그것은 문제를 완벽하게 설명해준다.
참조URL: https://stackoverflow.com/questions/279507/what-is-meant-by-immutable
'programing' 카테고리의 다른 글
데이터 테이블(v-data-table) Vuetify Data Table - 특정 열의 값을 조건부로 스타일 지정하는 방법 (0) | 2022.04.28 |
---|---|
Vuex 저장소의 페이지 지정 (0) | 2022.04.28 |
Vuex에서 동일한 구성 요소에 대해 양방향 데이터 바인딩을 구현하는 다양한 방법 (0) | 2022.04.28 |
콘솔에서 실행되지 않는 Windows에서 Java 프로세스의 스레드 및 힙 덤프를 가져오는 방법 (0) | 2022.04.28 |
vuex에서 데이터의 초기 값을 설정하는 방법 (0) | 2022.04.28 |