[java] Java에서 문자열을 변경할 수없는 이유는 무엇입니까?

인터뷰에서 String이 불변 인 이유를 물었습니다.

나는 이렇게 대답했다 :

우리가 자바에서 문자열을 만들면 문자열 풀 (hello)String s1="hello"; 에 객체가 생성 되고 s1hello를 가리킬 것입니다 . 이렇게하면 다른 객체가 생성되지 않지만 JVM 이 먼저 확인 하기
때문에 s2 가 가리 킵니다. 동일한 객체가 문자열 풀에 존재하는지 여부. 존재하지 않으면 새로운 객체
만 생성됩니다.String s2="hello";hello

이제 java가 문자열을 변경할 수 있다고 가정하면 s1hello world다음으로 변경하면 s2 값도 hello world변경되므로 java String은 변경할 수 없습니다.

내 대답이 경우 어떤 몸이 말해 주시겠습니까 권리 또는 잘못 ?



답변

String 몇 가지 이유로 변경할 수 없습니다. 요약은 다음과 같습니다.

  • 보안 : 매개 변수는 일반적으로 String네트워크 연결, 데이터베이스 연결 URL, 사용자 이름 / 암호 등 으로 표시됩니다 . 변경 가능한 경우 이러한 매개 변수를 쉽게 변경할 수 있습니다.
  • 동기화 및 동시성 : 문자열을 변경할 수 없게하면 스레드가 안전 해 지므로 동기화 문제가 해결됩니다.
  • 캐싱 : 컴파일러가 String 객체를 최적화 할 때 두 객체의 값이 같으면 (a = “test”및 b = “test”) 단 하나의 문자열 객체 만 필요하다는 것을 알 수 있습니다 (a와 b 모두에 대해이 두 같은 객체를 가리킴).
  • 클래스 로딩 : String클래스 로딩을위한 인수로 사용됩니다. 변경 가능한 경우, 변경 가능한 객체가 상태를 변경하기 때문에 잘못된 클래스가로드 될 수 있습니다.

즉, 불변성은 String퍼블릭 API를 사용하여 변경할 수 없다는 것을 의미합니다. 리플렉션을 사용하여 일반 API를 무시할 수 있습니다. 여기에 대한 답변을 참조 하십시오 .

귀하의 예에서 String변경 가능한 경우 다음 예를 고려하십시오.

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow


답변

Java 개발자는 다음과 같은 측면 디자인, 효율성 및 보안 으로 인해 문자열을 변경할 수 없다고 결정 합니다.

디자인
문자열은 “String Intern pool”이라고하는 Java 힙의 특수 메모리 영역에 작성됩니다. 새 String을 생성하는 동안 (String () 생성자 또는 내부적으로 String () 생성자를 사용하여 새 String 객체를 만드는 다른 String 함수를 사용하는 경우는 아님) String () 생성자는 풀이 아닌 경우 항상 새 문자열 상수를 만듭니다. intern () ) 변수를 호출하여 풀을 검색하여 이미 존재하는지 확인합니다. 존재하는 경우 기존 String 객체의 참조를 반환합니다. 문자열을 변경할 수없는 경우 하나의 참조로 문자열을 변경하면 다른 참조에 대한 값이 잘못됩니다.

DZone 에 대한 기사에 따르면 :

보안
문자열은 많은 Java 클래스 (예 : 네트워크 연결, 파일 열기 등)의 매개 변수로 널리 사용됩니다. 문자열이 변경 불가능한 경우 연결 또는 파일이 변경되어 심각한 보안 위협으로 이어질 수 있습니다. 매개 변수가 문자열이므로 가변 문자열은 Reflection에서도 보안 문제를 일으킬 수 있습니다.

효율성
문자열의 해시 코드는 Java에서 자주 사용됩니다. 예를 들어, HashMap에서. 불변이므로 해시 코드는 항상 동일하므로 변경 사항을 걱정하지 않고 캐시 할 수 있으므로 해시 코드를 사용할 때마다 계산할 필요가 없습니다.


답변

우리는 디자인하는 동안 Java 디자이너가 실제로 무엇을 생각했는지 확신 할 수 없지만 String문자열 불변성에서 얻을 수있는 이점을 기반으로 이러한 이유를 결론 내릴 수 있습니다.

1. 문자열 상수 풀의 존재

문자열이 문자열 상수 풀에 저장 되는 이유 기사 에서 설명한 것처럼 모든 응용 프로그램은 너무 많은 문자열 객체를 생성하고 많은 문자열 객체를 생성 한 다음 가비지 수집을 시작하지 않아도 JVM을 절약 할 수 있습니다. JVM은 모든 문자열 오브젝트를 문자열 상수 풀이라는 별도의 메모리 영역에 저장하고 캐시 된 풀의 오브젝트를 재사용합니다.

문자열 리터럴 JVM을 만들 때마다 해당 리터럴이 상수 풀에 이미 존재하는지 여부를 확인한 후 존재하는 경우 SCP에서 동일한 객체를 가리키는 새로운 참조가 시작됩니다.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

값 위의 예제 문자열 객체에서 Naresh한 번만 SCP에서 만든 얻을 것이다 모든 참조 a, b, c우리가 변화를 만들려고하면 같은 객체하지만 가리 킵니다 a예를 a.replace("a", "").

이상적으로, a값이 있어야 Nresh하지만 b, c때문에 우리가 변화하고 있습니다 최종 사용자로 변경되지 않은 상태로 유지해야 a만. 그리고 우리는 알고 a, b, c우리가 변화 할 경우, 그래서 모두 같은 객체를 가리키고 a, 다른 사람도 변화를 반영해야한다.

그러나 문자열 불변성은이 시나리오에서 우리를 구해 주며 문자열 객체의 불변성으로 인해 문자열 객체 Naresh는 절대 변경되지 않습니다. 따라서 a문자열 객체를 변경하는 대신 변경 Naresh하면 JVM이 새 객체를 생성 한 a다음 해당 객체를 변경합니다.

따라서 문자열 풀은 문자열의 불변성으로 인해 가능하며 문자열을 변경할 수 없으면 문자열 객체를 캐싱하고 재사용하면 변수가 값을 변경하고 다른 변수가 손상되어 가능성이 없습니다.

그렇기 때문에 JVM이 매우 특별하게 처리하고 특수한 메모리 영역이 제공되는 이유입니다.

2. 스레드 안전

객체는 여러 스레드가 작동 중일 때 스레드 안전이라고 불리지 만 어느 상태에서도 손상을 입을 수 없으며 어느 시점에서나 모든 스레드에 대해 동일한 상태를 유지하지 못합니다.

우리가 불변 객체를 만든 후에는 변경할 수 없으므로 모든 불변 객체는 기본적으로 스레드 안전합니다. 동기화 된 메소드 작성과 같은 스레드 안전 조치를 적용 할 필요는 없습니다.

따라서 변경 불가능한 자연 문자열로 인해 여러 스레드에서 공유 할 수 있으며 많은 스레드에서 조작하더라도 값이 변경되지 않습니다.

3. 보안

모든 애플리케이션에서 사용자의 사용자 이름 \ 암호, 연결 URL과 같은 몇 가지 비밀을 전달해야하며 일반적으로이 모든 정보는 문자열 객체로 전달됩니다.

이제 String이 본질적으로 변경 불가능하지 않다면 응용 프로그램에 심각한 보안 위협이 발생한다고 가정하십시오.이 값은 변경 될 수 있기 때문에 허용 된 경우 잘못 작성된 코드 또는 다른 사람으로 인해 변경 될 수 있습니다 변수 참조에 액세스 할 수 있습니다.

4. 클래스 로딩

Example 을 사용 하여 Java에서 Reflection을 통해 객체 만들기 에서 설명했듯이 Class.forName("class_name")method를 사용하여 클래스를 메모리에로드하여 다른 메서드를 다시 호출 할 수 있습니다. 그리고 JVM조차도 이러한 메소드를 사용하여 클래스를로드합니다.

그러나 모든 메소드가 클래스 이름을 문자열 객체로 허용하므로 문자열은 Java 클래스 로딩에 사용되며 불변성은 올바른 클래스가로드되는 보안을 제공합니다 ClassLoader.

String이 불변이 아니고 사이에 java.lang.Object변경되는 것을로드하려고 시도 org.theft.OurObject하고 이제 모든 객체가 누군가가 원하지 않는 것에 사용할 수있는 동작을 가지고 있다고 가정하십시오.

해시 코드 캐싱

객체에서 해싱 관련 작업을 수행 hashCode()하려는 경우 메서드 를 재정의 하고 객체 상태를 사용하여 정확한 해시 코드를 생성해야합니다. 객체의 상태가 변경되면 해시 코드도 변경되어야합니다.

String은 불변이므로 하나의 문자열 객체가 보유하는 값은 변경되지 않으므로 해시 코드도 변경되지 않으므로 String 클래스는 객체 생성 중에 해시 코드를 캐시 할 수 있습니다.

예, String 객체는 객체 생성시 해시 코드를 캐시하므로 해시 코드를 다시 계산할 필요가 없으므로 시간을 절약 할 수 있기 때문에 해시 관련 작업을 수행 할 수 있습니다. 이것이 문자열이 주로 HashMap키로 사용되는 이유 입니다.

Java에서 String이 변경 불가능하고 최종적인 이유 에 대해 자세히 알아보십시오 .


답변

DZone 에 대한 기사에 따르면 가장 중요한 이유는 다음과 같습니다.

문자열 상수 풀
… 문자열이 변경 가능한 경우 하나의 참조로 문자열을 변경하면 다른 참조의 값이 잘못됩니다.

보안

문자열은 네트워크 연결, 파일 열기 등과 같은 많은 Java 클래스에 대한 매개 변수로 널리 사용됩니다. 문자열이 변경 불가능한 경우 연결 또는 파일이 변경되어 심각한 보안 위협으로 이어질 수 있습니다. …

그것이 도움이되기를 바랍니다.


답변

이 게시물 읽기 문자열 자바 불변 또는 Final 이유를 , 그 다음은 가장 중요한 이유가 될 수 있습니다 가정 :

String 객체는 String 풀에 캐시 되므로 Java에서는 String을 변경할 수 없습니다 . 캐시 된 문자열 리터럴은 여러 클라이언트간에 공유 되므로 항상 한 클라이언트의 동작이 다른 모든 클라이언트에 영향을 줄 위험이 있습니다.


답변

네 말이 맞아 String자바에서는 String Pool리터럴의 개념을 사용합니다 . 문자열이 생성되고 문자열이 풀에 이미 존재하는 경우 새 객체를 만들고 참조를 반환하는 대신 기존 문자열의 참조가 반환됩니다. 문자열을 변경할 수없는 경우 하나의 참조로 문자열을 변경하면 다른 참조에 대한 잘못된 값으로 이어집니다.

String불변 이기 때문에 멀티 스레딩에 안전하며 단일 String 인스턴스를 다른 스레드에서 공유 할 수 있기 때문에 한 가지 더 추가 할 것입니다. 이것은 스레드 안전성을위한 동기화 사용을 피합니다 thread safe. 문자열은 암시 적 입니다.


답변

문자열 클래스는 FINAL클래스를 상속하고 기본 구조를 변경하고 Sting을 변경 가능하게 할 클래스를 만들 수 없다는 것을 의미합니다.

제공되는 String 클래스의 또 다른 인스턴스 변수와 메소드는 String일단 생성 된 객체를 변경할 수 없도록하는 것 입니다.

추가 한 이유는 문자열을 불변으로 만들지 않습니다.이 모든 것은 문자열이 힙에 저장되는 방식을 나타냅니다. 또한 문자열 풀은 성능에 큰 차이를 만듭니다