Java에서 String이 불변인 이유는 무엇입니까?
인터뷰에서 왜 String은 불변의 존재냐고 물었어요.
나는 이렇게 대답했다.
자바에서 다음과 같은 문자열을 만들 때
String s1="hello";
오브젝트가 string pool(hello)에 생성되고 s1이 hello를 가리키게 됩니다.다시 한 번 한다면String s2="hello";
다른 오브젝트는 생성되지 않지만 s2는 다음을 가리킵니다.hello
왜냐하면 JVM은 먼저 문자열 풀에 동일한 개체가 있는지 여부를 확인하기 때문입니다.존재하지 않는 경우, 새로운 것만이 작성됩니다.그렇지 않은 경우는 작성되지 않습니다.
이제 java에서 문자열 변환이 가능한 경우 s1을 로 변경합니다.hello world
s2 값도 마찬가지입니다.hello world
Java String은 불변입니다.
제 답이 맞는지 틀린지 말씀해 주실 분 없나요?
String
는 몇 가지 이유로 불변합니다.요약사항은 다음과 같습니다.
- 보안: 파라미터는 일반적으로 다음과 같이 표시됩니다.
String
네트워크 접속, 데이터베이스 접속 URL, 사용자 이름/사용자 이름 등변형이 가능한 경우 이들 파라미터는 쉽게 변경할 수 있습니다. - 동기화 및 동시성: 문자열을 자동으로 불변으로 하면 스레드가 안전해져 동기화 문제가 해결됩니다.
- 캐싱: 컴파일러가 String 개체를 최적화할 때 두 개체의 값이 같으면(a="test" 및 b="test") 하나의 문자열 개체만 있으면 됩니다(a와 b 모두에 대해 이 두 개체가 동일한 개체를 가리킵니다).
- 클래스 로드:
String
는 클래스 로딩의 인수로 사용됩니다.변경 가능한 경우 잘못된 클래스가 로드될 수 있습니다(변환 가능한 객체의 상태가 바뀌기 때문에).
말하자면, 불변은String
Public 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 Developers는 다음과 같은 설계, 효율성 및 보안 측면 때문에 문자열이 불변이라고 판단합니다.
설계 문자열은 "String Internal pool"로 알려진 자바 힙의 특수 메모리 영역에 생성됩니다.String() 컨스트럭터를 내부적으로 사용하여 새로운 String 오브젝트를 작성하는 String() 컨스트럭터 또는 기타 String 함수를 사용하는 경우는 제외됩니다.String() 컨스트럭터는 메서드 intern() 변수를 호출하지 않는 한 풀 내에서 항상 새로운 스트링 상수를 만듭니다.y가 존재합니다.존재하는 경우 기존 String 객체의 참조를 반환합니다.String이 불변하지 않는 경우 한 참조에서 String을 변경하면 다른 참조에 잘못된 값이 지정됩니다.
DZone에 대한 이 기사에 따르면:
보안 문자열은 네트워크 연결, 파일 열기 등과 같은 많은 Java 클래스의 매개 변수로 널리 사용됩니다.String이 불변하지 않으면 연결 또는 파일이 변경되어 심각한 보안 위협이 발생합니다.매개 변수가 문자열이므로 문자열이 변경되면 Reflection에서도 보안 문제가 발생할 수 있습니다.
효율성 문자열의 해시 코드는 Java에서 자주 사용됩니다.예를 들어 HashMap에 있습니다.불변의 경우 해시코드는 항상 동일하게 유지되므로 변경에 신경 쓰지 않고 캐시할 수 있습니다.즉, 해시 코드를 사용할 때마다 계산할 필요가 없습니다.
자바 디자이너가 디자인하면서 실제로 어떤 생각을 했는지 알 수 없다.String
그러나 이러한 이유는 문자열 불변성으로부터 얻을 수 있는 이점에 근거해 결론을 내릴 수 있습니다.그 중 일부는 다음과 같습니다.
1. 문자열 상수 풀의 존재
"String is Stored in String Constant Pool" 문서에서 설명한 바와 같이 모든 응용 프로그램에서 너무 많은 문자열 개체를 생성하고 JVM을 먼저 많은 문자열 개체를 생성한 후 가비지 수집으로부터 보호하기 위해 작성됩니다.JVM은 모든 문자열 개체를 문자열 상수 풀이라는 별도의 메모리 영역에 저장하고 캐시된 풀의 개체를 재사용합니다.
문자열 리터럴 JVM을 처음 작성할 때마다 해당 리터럴이 상수 풀에 이미 존재하는지 여부와 존재하는 경우 새로운 참조가 SCP의 동일한 개체를 가리키기 시작합니다.
String a = "Naresh";
String b = "Naresh";
String c = "Naresh";
위의 예에서는 값을 가진 문자열 개체Naresh
SCP에 작성되는 것은 1회뿐이며 모든 참조가 됩니다.a
,b
,c
같은 오브젝트를 가리키지만, 만약 우리가 이 오브젝트를 바꾸려고 한다면a
예.a.replace("a", "")
.
이상적으로.a
가치가 있어야 한다Nresh
그렇지만b
,c
최종 사용자로서 변경을 가하고 있기 때문에 변경은 없습니다.a
유일한 것. 그리고 우리는a
,b
,c
모든 것이 같은 대상을 가리키고 있기 때문에 만약 우리가 변화를 준다면a
, 그 외의 것도 변경을 반영할 필요가 있습니다.
그러나 문자열의 불변성은 문자열 객체의 불변성 때문에 이 시나리오에서 우리를 구합니다.Naresh
절대 변하지 않을 거야그래서 우리가 어떤 변화를 주었을 때a
문자열 개체를 변경하는 대신Naresh
JVM이 새 개체를 만듭니다.a
그리고 그 대상을 변화시킵니다.
따라서 String 풀은 String의 불변성 때문에만 가능하며 String이 불변성이 아닌 경우 값이 변경되어 다른 변수가 손상되기 때문에 String 개체를 캐시하고 재사용할 수 없습니다.
그렇기 때문에 JVM에 의해 특별히 처리되어 메모리 영역이 지정되었습니다.
2. 나사산의 안전성
오브젝트는 여러 스레드가 동작하고 있는 경우 스레드 세이프라고 불립니다만, 그 어느 스레드도 상태를 손상시킬 수 없습니다.또한 오브젝트는 어느 시점에서나 모든 스레드에 대해 동일한 상태를 유지합니다.
불변의 객체는 그 생성 후 누구도 수정할 수 없기 때문에 모든 불변의 객체는 기본적으로 스레드 세이프가 됩니다.동기화된 메서드 작성 등 스레드 안전 대책을 적용할 필요가 없습니다.
따라서 문자열 객체는 불변의 성질 때문에 여러 스레드로 공유할 수 있으며 여러 스레드에 의해 조작되어도 값은 변경되지 않습니다.
3. 보안
모든 어플리케이션에서 사용자의 user-name\passwords, connection URL 등 몇 가지 비밀정보를 전달해야 합니다.일반적으로 이 모든 정보는 문자열 오브젝트로 전달됩니다.
여기서 String이 본질적으로 불변하지 않는 경우 이러한 값은 변경이 허용되며, 변경이 허용될 경우 잘못 기술된 코드 또는 변수 참조에 액세스할 수 있는 다른 사용자로 인해 변경될 수 있기 때문에 애플리케이션에 심각한 보안 위협이 발생한다고 가정합니다.
4. 클래스 로딩
예를 들어 Java에서 Reflection을 통한 객체 생성에서 설명한 바와 같이 우리는 다음을 사용할 수 있습니다.Class.forName("class_name")
다른 메서드를 호출하는 메모리에 클래스를 로드하는 메서드.JVM도 이러한 방법을 사용하여 클래스를 로드합니다.
단, 이러한 메서드는 모두 클래스 이름을 문자열 오브젝트로 받아들이기 때문에 문자열은 Java 클래스 로딩에 사용되며 불변성은 올바른 클래스가 로딩되는 보안을 제공합니다.ClassLoader
.
예를 들어 String이 불변하지 않고 로드하려고 합니다.java.lang.Object
로 바뀌다org.theft.OurObject
그 사이 그리고 지금 우리의 모든 사물들은 누군가 원하지 않는 것에 사용할 수 있는 행동을 가지고 있다.
5. 해시 코드 캐시
오브젝트에 대해 해시 관련 작업을 수행하려면 이 작업을 덮어쓸 필요가 있습니다.hashCode()
method 및 오브젝트 상태를 사용하여 정확한 해시 코드를 생성해 보십시오.오브젝트 상태가 변경되면 해시 코드도 변경됩니다.
String은 불변하기 때문에 1개의 문자열 객체가 보유하고 있는 값은 변경되지 않으므로 해시 코드도 변경되지 않으므로 String 클래스는 객체 작성 중에 해시 코드를 캐시할 수 있습니다.
예, String 객체는 객체 생성 시 해시 코드를 캐시하므로 해시 관련 작업에 매우 적합합니다. 해시 코드를 다시 계산할 필요가 없기 때문에 시간을 절약할 수 있습니다.이것이 String이 주로 사용되는 이유입니다.HashMap
열쇠들.
Java에서 문자열이 불변하고 최종적인 이유에 대한 자세한 내용은 여기를 참조하십시오.
DZone에 관한 이 기사에 따르면 가장 중요한 이유는 다음과 같습니다.
문자열 상수 풀...문자열이 변경 가능한 경우 한 참조로 문자열을 변경하면 다른 참조에 잘못된 값이 지정됩니다.
보안.
문자열은 네트워크 연결, 파일 열기 등과 같은 많은 Java 클래스의 매개 변수로 널리 사용됩니다.String이 불변하지 않으면 연결 또는 파일이 변경되어 심각한 보안 위협이 발생합니다.
도움이 되길 바랍니다.
IMHO, 가장 중요한 이유는 다음과 같습니다.
Java에서는 String 객체가 String 풀에 캐시되므로 String은 불변입니다.캐시된 String 리터럴은 여러 클라이언트 간에 공유되므로 한 클라이언트의 작업이 다른 모든 클라이언트에 영향을 미칠 위험이 항상 있습니다.
맞아요. String
java에서는 개념을 사용합니다.String Pool
문자 그대로의문자열이 생성되고 해당 문자열이 풀에 이미 있는 경우 새 개체를 만들고 해당 참조를 반환하는 대신 기존 문자열의 참조가 반환됩니다.문자열이 불변하지 않는 경우 한 참조로 문자열을 변경하면 다른 참조에 잘못된 값이 지정됩니다.
한 가지 더 덧붙이고 싶은 게 있는데String
는 불변이며 멀티 스레드에 대해 안전하며 단일 String 인스턴스를 서로 다른 스레드로 공유할 수 있습니다.이렇게 하면 스레드 안전을 위해 동기화가 사용되지 않습니다. 문자열은 암묵적으로thread safe
.
문자열은 맵 컬렉션에서 키로 저장할 수 있기 때문에 Sun 마이크로 시스템에서 불변으로 지정됩니다.String Buffer는 가변입니다.그렇기 때문에 맵 객체의 키로 사용할 수 없습니다.
Java에서 String이 불변하게 되는 가장 중요한 이유는 보안에 대한 고려입니다.다음은 캐싱입니다.
나는 String in이 불변하게 만든 사실에서 효율성, 동시성, 디자인 및 문자열 풀과 같은 다른 이유들이 나온다고 믿는다.예를 들면.String Pool은 String이 불변하기 때문에 생성될 수 있습니다.
고슬링 인터뷰 성적표는 이쪽에서 확인하세요.
전략적 관점에서 볼 때, 그들은 종종 문제가 없는 경향이 있습니다.그리고 보통 결과를 캐시하는 것과 같이 가변적인 것으로는 할 수 없는 불변의 것으로는 할 수 있는 일이 있습니다.파일 오픈 메서드에 문자열을 전달하거나 사용자 인터페이스의 라벨 생성자에게 문자열을 전달하면 일부 API(많은 Windows API 등)에서 문자 배열이 전달됩니다.해당 개체의 저장 수명에 대해 아무것도 모르기 때문에 해당 개체의 수신자는 해당 개체를 복사해야 합니다.그리고 그들은 그 물체에 무슨 일이 일어나고 있는지, 그것이 그들의 발밑에서 변화하고 있는지 알지 못한다.
소유할 수 있을지 모르기 때문에 거의 강제로 개체를 복제하게 됩니다.불변의 물체에 대한 좋은 점 중 하나는 "네, 물론이죠"라는 대답입니다.바꿀 권리가 있는 소유권 문제는 존재하지 않기 때문입니다.
Strings를 불변하게 만든 것 중 하나는 보안이었다.파일 열기 메서드가 있습니다.스트링을 전달합니다.그리고 OS 호출을 시작하기 전에 모든 종류의 인증 체크를 수행합니다.String을 효과적으로 변환하는 작업을 보안 검사 후 및 OS 호출 전에 수행할 수 있다면 Boom에 가입할 수 있습니다.하지만 끈은 불변하기 때문에 그런 공격은 통하지 않는다.그 정확한 예가 스트링스가 불변할 것을 요구한 것이다.
문자열 클래스는FINAL
즉, 어떤 클래스도 만들 수 없고 기본 구조도 바꿀 수 없고 스팅도 바꿀 수 없습니다.
제공되는 String 클래스의 다른 인스턴스 변수 및 메서드는 변경할 수 없습니다.String
오브젝트 생성 후.
추가한 이유가 String을 불변하게 하는 것은 아닙니다.이 모든 것은 String이 힙에 저장되는 방법을 나타냅니다.또, 스트링 풀은 퍼포먼스에 큰 차이를 가져옵니다.
좋은 답변에 덧붙여 몇 가지 포인트를 더하고 싶었습니다.Strings와 마찬가지로 어레이는 어레이의 선두에 대한 참조를 보유하기 때문에 2개의 어레이를 작성하면arr1
그리고.arr2
이런 걸 했어요.arr2 = arr1
이것은 을 참조할 것이다.arr2
와 같은arr1
따라서 이들 중 하나의 값이 변경되면 예를 들어 다른 값이 변경된다.
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4};
int[] b = a;
a[0] = 8;
b[1] = 7;
System.out.println("A: " + a[0] + ", B: " + b[0]);
System.out.println("A: " + a[1] + ", B: " + b[1]);
//outputs
//A: 8, B: 8
//A: 7, B: 7
}
}
코드의 버그를 일으킬 뿐만 아니라 악의적인 사용자에 의해 악용될 수도 있습니다.admin 비밀번호를 변경하는 시스템이 있다고 가정합니다.사용자는 먼저 를 입력해야 합니다.newPassword
그 다음에oldPassword
만약oldPassword
와 동일하다adminPass
프로그램이 패스워드를 변경하다adminPass = newPassword
새로운 패스워드가 admin 패스워드와 같은 참조를 가지기 때문에, 불량한 프로그래머가 이 패스워드를 작성할 가능성이 있다고 합니다.temp
variable: 사용자가 데이터를 입력하기 전에 admin 비밀번호를 유지합니다.oldPassword
와 동등하다temp
그렇지 않으면 패스워드가 변경됩니다.adminPass = temp
새로운 패스워드를 쉽게 입력할 수 있고 이전 패스워드와 abracadabra를 입력하지 않을 수 있다는 것을 알고 있는 사람.관리자 권한을 가지고 있습니다.Strings에 대해 배울 때 이해하지 못했던 또 다른 점은 JVM이 모든 오브젝트에 대해 새로운 스트링을 만들고 이를 위한 고유한 위치를 메모리에 배치하지 않는 이유는 무엇입니까?new String("str");
항상 사용하고 싶지 않은 이유new
대부분의 경우 메모리 효율이 떨어지고 읽기 속도가 느리기 때문입니다.
한다면HELLO
String 이면 변경할 수 없습니다.HELLO
로.HILLO
이 속성을 불변성 속성이라고 합니다.
여러 포인터 String 변수를 사용하여 HELLO String을 지정할 수 있습니다.
단, HELLO가 char Array일 경우 HELLO를 HAILLO로 변경할 수 있습니다.예:
char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this
답변:
프로그래밍 언어에는 불변의 데이터 변수가 있으므로 키, 값 쌍의 키로 사용할 수 있습니다.문자열 변수는 키/인디케이터로 사용되므로 변경할 수 없습니다.
에서Security
견해의 점 우리가:실용적인 예를 사용할 수 있다.
DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {
// if strings were mutable IP,PORT,USER,PASS can be changed by validate function
Boolean validated = validate(IP,PORT,USER,PASS);
// here we are not sure if IP, PORT, USER, PASS changed or not ??
if (validated) {
DBConnection conn = doConnection(IP,PORT,USER,PASS);
}
// rest of the code goes here ....
}
언급URL:https://stackoverflow.com/questions/22397861/why-is-string-immutable-in-java
'programing' 카테고리의 다른 글
TypeScript를 사용할 때 단일 파일 구성 요소에서 Vue를 가져오는 방법 (0) | 2022.08.21 |
---|---|
Vuex 모듈 게터 및 돌연변이에 액세스하는 방법 (0) | 2022.08.18 |
BigDecimal setScale 및 라운드 (0) | 2022.08.18 |
감시 경로나 내비게이션 가드 중 어느 쪽도 발포하지 않습니다. (0) | 2022.08.18 |
VueJ에서 가로채기 확인란 변경 이벤트s (0) | 2022.08.18 |