[java] 우리는 언제 String 리터럴에서 String의 인턴 메소드를 사용해야합니까?

에 따르면 문자열 # 인턴 () , intern메소드는 문자열이 문자열 풀에서 발견되는 경우, 그렇지 않으면 새로운 문자열 객체는 문자열 풀에 추가되고이 String의 참조가 반환, 문자열 수영장에서 문자열을 반환하기로되어있다.

그래서 나는 이것을 시도했다 :

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

s1 and s3 are sames3이 억지로 인쇄되고 s1 and s2 are same인쇄되지 않을 것으로 예상했습니다 . 그러나 결과는 다음과 같습니다. 두 줄이 모두 인쇄됩니다. 따라서 기본적으로 문자열 상수가 인터 닝됩니다. 그러나 그렇다면 왜 intern방법이 필요 합니까? 다시 말해이 방법을 언제 사용해야합니까?



답변

Java는 자동으로 문자열 리터럴을 인턴합니다. 이것은 많은 경우 == 연산자가 int 또는 다른 기본 값에서와 동일한 방식으로 문자열에서 작동하는 것으로 나타납니다.

interning은 String 리터럴에 대해 자동이기 때문에이 intern()메소드는로 구성된 String에서 사용됩니다.new String()

귀하의 예를 사용하여 :

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

if ( s1 == s4 ){
    System.out.println("s1 and s4 are same" );  // 3.
}

if ( s1 == s5 ){
    System.out.println("s1 and s5 are same" );  // 4.
}

돌아올 것이다 :

s1 and s2 are same
s1 and s3 are same
s1 and s5 are same

s4변수를 제외한 모든 경우에 , new연산자를 사용하여 명시 적으로 작성된 값 과 intern그 결과에 메소드가 사용되지 않은 경우, JVM의 문자열 상수 풀로 리턴되는 변경 불가능한 단일 인스턴스입니다 .

자세한 정보는 JavaTechniques “문자열 동등성 및 인터 닝” 을 참조하십시오.


답변

최근 프로젝트에서 일부 거대한 데이터 구조는 데이터베이스에서 읽은 데이터 (따라서 문자열 상수 / 리터럴이 아님)로 설정되었지만 대량의 복제가 이루어졌습니다. 그것은 은행 응용 프로그램이었고, 적당한 세트 (100 또는 200) 회사의 이름과 같은 것들이 사방에 나타났습니다. 데이터 구조는 이미 커서 모든 회사 이름이 고유 한 개체라면 메모리가 넘 쳤을 것입니다. 대신, 모든 데이터 구조는 동일한 100 또는 200 문자열 오브젝트에 대한 참조를 가지므로 많은 공간을 절약합니다.

인터 링 된 문자열의 또 다른 작은 장점은 ==관련된 모든 문자열이 인터 닝되도록 보장 된 경우 (성공적으로!) 사용하여 문자열을 비교할 수 있다는 것입니다. 더 작은 구문 외에도 성능 향상입니다. 그러나 다른 사람들이 지적 했듯이이 작업을 수행하면 프로그래밍 오류가 발생할 위험이 커지므로 이는 최후의 수단에 대한 절망적 인 수단으로 만 수행해야합니다.

단점은 단순히 문자열을 힙에 던지는 것보다 문자열을 인턴하는 데 더 많은 시간이 걸리며 Java 구현에 따라 인턴 된 문자열의 공간이 제한 될 수 있다는 것입니다. 중복이 많은 알려진 합리적인 수의 문자열을 다룰 때 가장 좋습니다.


답변

==내부 문자열로 사용 하는 데 2 센트를 추가하고 싶습니다 .

가장 먼저하는 일은 String.equals입니다 this==object.

따라서 약간의 성능 향상 (메소드를 호출하지 않음)이 있지만 유지 보수 자의 관점에서 볼 때 ==일부 인턴 문자열은 인턴되지 않는 경향이 있기 때문에 악몽입니다.

따라서 나는 특별한 ==문자열 에 의존하지 말고 항상 equalsGosling이 의도 한대로 사용 하는 것이 좋습니다.

편집 : 인턴 비 인턴되기 :

V1.0
public class MyClass
{
  private String reference_val;

  ...

  private boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

버전 2.0에서 관리자 hasReferenceVal는 인터 레 이닝 된 문자열의 배열을 기대한다는 것을 자세하게 설명하지 않고 공개 하기로 결정했습니다 .

V2.0
public class MyClass
{
  private String reference_val;

  ...

  public boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

대부분의 경우 배열에 리터럴 값이 포함되어 있고 때로는 리터럴이 아닌 문자열이 사용되기 때문에 찾기가 매우 어려울 수있는 버그가 있습니다. 경우 equals대신 사용 된 ==hasReferenceVal아직이 작업을 계속할 것입니다. 다시 한번, 성능 향상은 미미하지만 유지 보수 비용은 높습니다.


답변

문자열 리터럴과 상수는 기본적으로 인턴됩니다. 즉, "foo" == "foo"(문자열 리터럴로 선언)이지만 new String("foo") != new String("foo").


답변

Java String Intern 배우기-한 번만

Java의 문자열은 의도적으로 변경할 수없는 객체입니다. 따라서 동일한 값을 가진 두 개의 문자열 객체는 기본적으로 다른 객체가됩니다. 그러나 메모리를 절약하려면 string intern이라는 개념으로 동일한 메모리를 사용하도록 지시 할 수 있습니다.

아래 규칙은 개념을 명확한 용어로 이해하는 데 도움이됩니다.

  1. 문자열 클래스는 초기에 비어있는 인턴 풀을 유지 관리합니다. 이 풀은 고유 한 값으로 만 문자열 객체를 포함해야합니다.
  2. 동일한 값을 가진 모든 문자열 리터럴은 다른 구별 개념이 없으므로 동일한 메모리 위치 객체로 간주해야합니다. 따라서 같은 값을 가진 모든 리터럴은 인턴 풀에서 단일 항목을 만들고 동일한 메모리 위치를 참조합니다.
  3. 둘 이상의 리터럴을 연결하는 것도 리터럴입니다. (따라서 규칙 # 2가 적용됩니다)
  4. 객체로 생성 된 (즉, 리터럴 이외의 다른 방법으로) 생성 된 각 문자열은 서로 다른 메모리 위치를 가지며 인턴 풀에 항목을 만들지 않습니다
  5. 리터럴이 아닌 리터럴을 연결하면 리터럴이되지 않습니다. 따라서 결과 객체는 새로운 메모리 위치를 가지며 인턴 풀에 항목을 만들지 않습니다.
  6. 문자열 객체에서 인턴 메서드를 호출하면 인턴 풀에 들어가는 새 객체를 만들거나 동일한 값을 가진 풀에서 기존 객체를 반환합니다. 인턴 풀에없는 오브젝트에 대한 호출은 오브젝트를 풀로 이동하지 않습니다. 오히려 수영장으로 들어가는 다른 객체를 만듭니다.

예:

String s1=new String (“abc”);
String s2=new String (“abc”);
If (s1==s2)  //would return false  by rule #4
If (“abc == a”+”bc )  //would return true by rules #2 and #3
If (“abc == s1 )  //would return false  by rules #1,2 and #4
If (“abc == s1.intern() )  //would return true  by rules #1,2,4 and #6
If ( s1 == s2.intern() )      //wound return false by rules #1,4, and #6

참고 : 문자열 인턴에 대한 동기 부여 사례는 여기에서 다루지 않습니다. 그러나 메모리 절약은 분명히 주요 목표 중 하나입니다.


답변

컴파일 시간과 런타임 시간 인 두 가지 기간을 만들어야합니다. 예를 들면 다음과 같습니다.

//example 1 
"test" == "test" // --> true 
"test" == "te" + "st" // --> true

//example 2 
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true

한 손으로, 예제 1에서, 컴파일 시간에 결과가 모두 true를 반환한다는 것을 알았습니다. jvm이 “test”가 존재하면 jvm이 리터럴 문자열의 풀에 “test”를 넣습니다. 예제 1에서 존재하는 것을 사용합니다. “테스트”문자열은 모두 동일한 메모리 주소를 가리 키므로 예제 1은 true를 반환합니다. 반면, 예제 2에서 substring ()의 메소드는 런타임 시간에 실행됩니다. “test”== “! test”.substring (1)의 경우 풀은 두 개의 문자열 객체를 생성합니다. ” test “와”! test “는 서로 다른 참조 객체이므로이 경우”test “==”! test “.substring (1) .intern ()의 경우 intern ( )는 “”! test “.substring (1)”을 리터럴 문자열 풀에 넣습니다.


답변

http://en.wikipedia.org/wiki/String_interning

문자열 인턴은 각각의 고유 한 문자열 값의 사본을 하나만 저장하는 방법으로 변경 불가능합니다. 문자열을 문자열로 만들면 문자열을 만들거나 묶을 때 더 많은 시간이 걸리면서 일부 문자열 처리 작업이 시간이나 공간 효율성이 향상됩니다. 고유 값은 문자열 인턴 풀에 저장됩니다.