Java 및 .NET에서 문자열을 변경할 수없는 이유는 무엇입니까? 불가능한 이유는 무엇 입니까? 왜

StringJava 및 .NET (및 기타 언어)에서 변경 불가능한 이유는 무엇 입니까? 왜 그것들을 변경하지 않았습니까?



답변

Effective Java의 4 장 73 페이지 2 판 에 따르면 :

“이에 대한 여러 가지 이유가 있습니다. 불변 클래스는 변경 가능한 클래스보다 설계, 구현 및 사용하기가 더 쉽습니다. 오류가 덜 발생하고 더 안전합니다.

[…]

불변 객체는 단순하다. 불변 객체는 생성 된 상태 인 정확히 하나의 상태 일 수있다. 모든 생성자가 클래스 불변을 설정하게한다면, 이러한 불변은 항상 참으로 유지 될 것이다. 노력하지 마십시오.

[…]

불변의 객체는 본질적으로 스레드로부터 안전합니다. 동기화가 필요하지 않습니다. 여러 스레드가 동시에 액세스하여 손상 될 수 없습니다. 이것은 스레드 안전성을 달성하는 가장 쉬운 방법입니다. 실제로 어떤 스레드도 다른 스레드가 불변 개체에 미치는 영향을 관찰 할 수 없습니다. 따라서
불변 개체를 자유롭게 공유 할 수 있습니다

[…]

같은 장의 다른 작은 점들 :

변경 불가능한 객체를 공유 할 수있을뿐만 아니라 내부를 공유 할 수 있습니다.

[…]

불변 객체는 변경 가능하거나 불변의 다른 객체에 대한 훌륭한 빌딩 블록을 만듭니다.

[…]

불변 클래스의 유일한 단점은 각각의 고유 한 값에 대해 별도의 객체가 필요하다는 것입니다.


답변

최소한 두 가지 이유가 있습니다.

첫 번째-보안 http://www.javafaq.nu/java-article1060.html

String이 변경 불가능한 주된 이유는 보안이었습니다. 이 예제를 살펴보십시오. 로그인 확인이 가능한 파일 열기 방법이 있습니다. 호출이 OS로 전달되기 전에 필요한 인증을 처리하기 위해이 메소드에 문자열을 전달합니다. 문자열이 변경 가능하면 OS가 프로그램에서 요청을 받기 전에 인증 확인 후 내용을 수정하는 것이 가능했으며 파일을 요청할 수 있습니다. 따라서 사용자 디렉토리에서 텍스트 파일을 열 수있는 권한이 있지만 파일 이름을 변경하는 경우 즉시 “passwd”파일 또는 다른 파일을 열도록 요청할 수 있습니다. 그런 다음 파일을 수정할 수 있으며 OS에 직접 로그인 할 수 있습니다.

둘째-메모리 효율성 http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

JVM은 내부적으로 “문자열 풀”을 유지 보수합니다. 메모리 효율성을 달성하기 위해 JVM은 풀에서 문자열 오브젝트를 참조합니다. 새 String 객체를 만들지 않습니다. 따라서 새 문자열 리터럴을 작성할 때마다 JVM이 풀이 있는지 여부를 풀에서 체크인합니다. 풀에 이미 존재하는 경우 동일한 오브젝트에 대한 참조를 제공하거나 풀에 새 오브젝트를 작성하십시오. 동일한 String 객체를 가리키는 많은 참조가있을 수 있습니다. 누군가 값을 변경하면 모든 참조에 영향을 미칩니다. 그래서 태양은 그것을 불변으로 만들기로 결정했습니다.


답변

실제로, 문자열이 Java에서 불변 인 이유는 보안과 관련이 없습니다. 두 가지 주요 이유는 다음과 같습니다.

Thead 안전 :

문자열은 매우 널리 사용되는 객체 유형입니다. 따라서 멀티 스레드 환경에서 사용되는 것이 다소 보장됩니다. 문자열은 스레드간에 문자열을 안전하게 공유 할 수 있도록 변경할 수 없습니다. 변경 불가능한 문자열이 있으면 스레드 A에서 다른 스레드 B로 문자열을 전달할 때 스레드 B가 스레드 A의 문자열을 예기치 않게 수정할 수 없습니다.

이렇게하면 이미 복잡한 멀티 스레드 프로그래밍 작업을 단순화 할 수있을뿐만 아니라 멀티 스레드 응용 프로그램의 성능도 향상시킬 수 있습니다. 하나의 스레드가 다른 스레드에 의해 수정되는 동안 하나의 스레드가 개체의 값을 읽으려고 시도하지 않도록 변경 가능한 개체에 대한 액세스는 여러 스레드에서 액세스 할 수있을 때 동기화되어야합니다. 적절한 동기화는 프로그래머에게 올바르게 수행하기 어렵고 런타임에 비용이 많이 듭니다. 변경할 수없는 객체는 수정할 수 없으므로 동기화 할 필요가 없습니다.

공연:

String interning이 언급되었지만 Java 프로그램의 메모리 효율성이 약간만 향상되었습니다. 문자열 리터럴 만 인터 턴됩니다. 즉, 소스 코드 에서 동일한 문자열 만 동일한 문자열 객체를 공유합니다. 프로그램이 동일한 문자열을 동적으로 작성하면 다른 오브젝트로 표시됩니다.

더 중요한 것은 불변 문자열을 사용하여 내부 데이터를 공유 할 수 있다는 것입니다. 많은 문자열 작업의 경우 기본 문자 배열을 복사 할 필요가 없습니다. 예를 들어, String의 첫 다섯 문자를 사용한다고 가정하십시오. Java에서는 myString.substring (0,5)을 호출합니다. 이 경우 substring () 메서드는 myString의 기본 char []를 공유하지만 인덱스 0에서 시작하여 해당 char []의 인덱스 5에서 끝나는 것을 알고있는 새 String 객체를 만드는 것입니다. 이것을 그래픽 형식으로 넣으려면 다음과 같이 끝납니다.

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

이것은 이런 종류의 연산을 매우 저렴하게 만들고, 연산은 원래 문자열의 길이나 추출해야하는 부분 문자열의 길이에 의존하지 않기 때문에 O (1)입니다. 많은 문자열이 기본 char []를 공유 할 수 있기 때문에이 동작에는 메모리 이점도 있습니다.


답변

나사산 안전 및 성능. 문자열을 수정할 수없는 경우 여러 스레드간에 참조를 전달하는 것이 안전하고 빠릅니다. 문자열이 변경 가능한 경우 항상 문자열의 모든 바이트를 새 인스턴스에 복사하거나 동기화를 제공해야합니다. 일반적인 응용 프로그램은 문자열을 수정해야 할 때마다 문자열을 100 번 읽습니다. 불변성 에 대한 위키 백과를 참조하십시오 .


답변

“왜 X가 변해야합니까?” Princess Fluff가 이미 언급 한 이점 때문에 불변성을 기본값으로하는 것이 좋습니다 . 변경 가능한 것은 예외입니다.

불행히도 현재의 대부분의 프로그래밍 언어는 변경 가능성이 있지만, 앞으로는 기본값이 불변성에 가깝습니다 ( 다음 주류 프로그래밍 언어에 대한 희망 목록 참조 ).


답변

와! 나는 잘못된 정보를 믿을 수 없다. String불변의 것은 보안에 아무런 영향을 미치지 않습니다. 누군가가 이미 실행중인 응용 프로그램의 객체에 액세스 할 수 있다면 ( String앱에서 누군가 ‘해킹’을 막으려 고한다고 가정 해야하는 경우 ) 분명히 해킹에 사용할 수있는 다른 많은 기회가 될 것입니다.

불변성이 String스레딩 문제를 해결 한다는 것은 매우 참신한 생각입니다 . 흠 … 두 개의 다른 스레드로 변경되는 객체가 있습니다. 이 문제를 어떻게 해결합니까? 객체에 대한 액세스를 동기화 하시겠습니까? Naawww … 아무도 객체를 변경하지 못하게합시다. 그러면 우리의 지저분한 동시성 문제가 모두 해결 될 것입니다! 실제로 모든 객체를 변경할 수 없게 만든 다음 Java 언어에서 동기화 된 구성을 제거 할 수 있습니다.

(위의 다른 사람들이 지적한) 진짜 이유는 메모리 최적화입니다. 동일한 응용 프로그램에서 동일한 문자열 리터럴을 반복적으로 사용하는 것이 일반적입니다. 실제로 수십 년 전에 많은 컴파일러가 String리터럴 의 단일 인스턴스 만 저장하도록 최적화했습니다 . 이 최적화의 단점은 String리터럴 을 수정하는 런타임 코드가 이를 공유하는 다른 모든 코드의 인스턴스를 수정하기 때문에 문제를 유발한다는 것입니다. 예를 들어, 응용 프로그램 어딘가의 함수가 String리터럴 "dog"을 로 변경하는 것은 좋지 않습니다 "cat". A는 printf("dog")초래 "cat"표준 출력에 기록된다. 따라서 변경을 시도하는 코드로부터 보호하는 방법이 필요했습니다.String리터럴 (즉, 불변으로 만듭니다). OS에서 지원하는 일부 컴파일러는 String리터럴을 특수 읽기 전용 메모리 세그먼트 에 배치 하여 쓰기 시도가있을 경우 메모리 오류를 일으킬 수 있습니다.

자바에서는 이것을 인턴이라고합니다. 여기서 Java 컴파일러는 수십 년 동안 컴파일러가 수행 한 표준 메모리 최적화를 따르고 있습니다. 그리고 String런타임에 수정되는 이러한 리터럴 과 동일한 문제를 해결하기 위해 Java는 단순히 String클래스를 변경할 수 없게 만듭니다 (즉, String내용 을 변경할 수있는 setter를 제공하지 않음 ). 리터럴 String인터 리닝이 String발생하지 않으면 s를 변경할 수 없습니다 .


답변

String 는 기본 유형이 아니지만 일반적으로 값 의미와 함께 값을 사용하려고합니다 (예 : 값).

가치는 당신이 등 뒤에서 변하지 않을 것이라고 믿을 수있는 것입니다. 당신이 쓰는 경우 : String str = someExpr();
당신은 무언가를하지 않는 한 변경을 원하지 않습니다 str.

String과 같이 Object자연스럽게 포인터 의미를 가지고 잘 불변 할 필요가 같은 값의 의미를 얻을 수 있습니다.