자바 String 대상(당신 은 정말 알 고 있 습 니까)

9448 단어 JavaString대상
String 대상 의 실현
String 대상 은 자바 에서 가장 자주 사용 되 는 대상 중 하나 이기 때문에 자바 회사 도 String 대상 의 실현 을 최적화 시 켜 String 대상 의 성능 을 향상 시 키 고 있 습 니 다.아래 그림 을 보고 String 대상 의 최적화 과정 을 알 아 보 겠 습 니 다.

1.자바 6 및 이전 버 전에 서
String 대상 은 char 배열 을 패키지 하여 실현 한 대상 으로 주로 네 개의 구성원 변수 가 있 습 니 다.char 배열,오프셋 오프셋 오프셋,문자 수량 count,해시 값 hash.
String 대상 은 offset 과 count 두 속성 을 통 해 char[]배열 을 찾 아 문자열 을 가 져 옵 니 다.이렇게 하면 배열 대상 을 효율 적 이 고 신속하게 공유 하 는 동시에 메모리 공간 을 절약 할 수 있 지만 이런 방식 은 메모리 누 출 을 초래 할 수 있다.
2.자바 7 버 전부터 자바 8 버 전 까지
자바 7 버 전부터 자바 가 String 류 에 대해 약간의 변 화 를 주 었 다.String 클래스 에는 더 이상 offset 과 count 두 개의 변수 가 없습니다.이러한 장점 은 String 대상 이 차지 하 는 메모리 가 약간 적 고 String.substring 방법 도 char[]를 공유 하지 않 아 이 방법 을 사용 하면 발생 할 수 있 는 메모리 누 출 문 제 를 해결 하 는 것 이다.
3.자바 9 버 전부터
char[]배열 을 by te[]배열 로 바 꾸 는데 왜 이렇게 해 야 합 니까?우 리 는 char 가 두 바이트 라 는 것 을 알 고 있 습 니 다.만약 에 한 바이트 의 문 자 를 저장 하 는 데 낭비 가 있다 면 공간 을 절약 하기 위해 자바 회 사 는 하나의 바이트 의 byte 로 문자열 을 저장 합 니 다.이렇게 한 바이트 의 문 자 를 저장 하면 낭 비 를 피 할 수 있다.
자바 9 에서 새로운 속성 coder 를 유 지 했 습 니 다.인 코딩 형식의 표지 입 니 다.문자열 의 길 이 를 계산 하거나 index Of()함 수 를 호출 할 때 이 필드 에 따라 문자열 의 길 이 를 어떻게 계산 하 는 지 판단 해 야 합 니 다.coder 속성 은 기본적으로 0 과 1 두 개의 값 이 있 고 0 은 Latin-1(단일 바이트 인 코딩)을 대표 하 며 1 은 UTF-16 인 코딩 을 대표 합 니 다.String 이 문자열 에 Latin-1 만 포함 되 어 있다 고 판단 하면 coder 속성 값 은 0 이 고 그렇지 않 으 면 1 입 니 다.
String 대상 생 성 방식
1.문자열 상수 로
String str="pingtouge"형식 으로 문자열 을 만 들 때 JVM 은 문자열 상수 탱크 에서 대상 이 존재 하 는 지 확인 하고 존재 하면 대상 의 참조 주 소 를 되 돌려 줍 니 다.존재 하지 않 으 면 문자열 상수 탱크 에 이 문자열 쌍 을 만 들 고 인용 을 되 돌려 줍 니 다.이런 방식 으로 만 든 장점 은 같은 값 의 문자열 이 중복 되 는 것 을 피하 고 메모 리 를 절약 하 는 것 이다
2.String()구조 함수 의 방식
String str=new String("pingtouge")형식 으로 문자열 대상 을 만 드 는 과정 이 복잡 합 니 다.두 단계 로 나 뉘 어 있 습 니 다.먼저 컴 파일 할 때 문자열 pingtouge 는 상수 구조 에 추가 되 고 클래스 로 딩 할 때 상수 풀 에서 이 문자열 을 만 듭 니 다.그 다음 에 new()를 호출 할 때 JVM 은 String 의 구조 함 수 를 호출 하고 상수 탱크 의 pingtouge 문자열 을 참조 합 니 다.
메모리 에 String 대상 을 만 들 고 더미 에 있 는 참조 주 소 를 되 돌려 줍 니 다.
String 대상 의 두 가지 생 성 방식 을 알 게 되 었 습 니 다.다음 코드 를 분석 하고 이 두 가지 방식 에 대한 이 해 를 강화 하 겠 습 니 다.아래 코드 영화 에서 str 는 str 1 과 같 습 니까?

 String str = "pingtouge";
 String str1 = new String("pingtouge");
 system.out.println(str==str1)
이 몇 줄 의 코드 를 하나씩 분석 해 보 겠 습 니 다.먼저 String str="pingtouge"부터 문자열 상수 방식 으로 문자열 대상 을 만 들 었 습 니 다.pingtouge 문자열 대상 을 만 들 때 JVM 은 상수 탱크 에 가서 이 문자열 이 존재 하 는 지 찾 습 니 다.여기 서 답 안 은 없 을 것 입 니 다.따라서 JVM 은 상수 탱크 에 이 문자열 대상 을 만 들 고 대상 의 주소 참조 로 돌아 갑 니 다.따라서 str 는 pingtouge 문자열 대상 이 상수 탱크 에 있 는 주소 참조 입 니 다.
그 다음 에 String str 1=new String("pingtouge")코드 입 니 다.여 기 는 구조 함수 방식 으로 문자열 대상 을 만 듭 니 다.구조 함수 방식 으로 문자열 대상 을 만 드 는 것 에 대한 이해 에 따라 str 1 은 쌓 여 있 는 pingtouge 문자열 의 참조 주 소 를 얻 을 수 있 습 니 다.str 는 pingtouge 문자열 대상 이 상수 탱크 에 있 는 주 소 를 참조 하 는 것 을 가리 키 기 때문에 str 1 은 더미 에 있 는 pingtouge 문자열 의 참조 주 소 를 가리 키 기 때문에 str 는 str 1 과 같 지 않 을 것 입 니 다.
String 대상 의 불변성
우리 가 String 대상 을 알 게 된 순간 부터 String 대상 은 변 할 수 없다 는 것 을 모두 가 알 고 있 을 것 이 라 고 생각 합 니 다.그럼 얘 가 변 하지 않 는 건 어떻게 하 는 거 예요?자바 가 이렇게 하면 어떤 좋 은 점 을 가 져 올 수 있 습 니까?우리 함께 간단하게 토론 해 보 자.먼저 String 대상 의 소스 코드 를 살 펴 보 자.

public final class String
  implements java.io.Serializable, Comparable<String>, CharSequence {
  /** The value is used for character storage. */
  private final char value[];

  /** Cache the hash code for the string */
  private int hash; // Default to 0

  /** use serialVersionUID from JDK 1.0.2 for interoperability */
  private static final long serialVersionUID = -6849794470754667710L;
  }
이 소스 코드 에서 알 수 있 듯 이 String 류 는 final 수식 자 를 사 용 했 습 니 다.우 리 는 하나의 클래스 가 final 에 의 해 수식 되 었 을 때 이 클래스 가 계승 되 지 못 한 다 는 것 을 알 기 때문에 String 류 는 계승 되 지 못 합 니 다.String 의 변 함 없 는 첫 번 째 포인트 입 니 다.
다시 아래 를 보면 문자열 을 저장 하 는 char value[]배열 은 private 와 final 에 의 해 수식 되 었 습 니 다.final 의 기본 데이터 형식 에 대한 변 수 는 초기 화 된 후에 변경 할 수 없다 는 것 을 알 고 있 습 니 다.이것 은 String 가 변 할 수 없 는 두 번 째 점 이다.
자바 회 사 는 왜 String 을 가 변 적 이지 않 게 설정 합 니까?주로 다음 과 같은 세 가지 측면 에서 고려 합 니 다.
  • 1.String 대상 의 안전성 을 확보한다.String 대상 이 가 변 적 이 라 고 가정 하면 String 대상 은 악의 적 으로 수 정 될 수 있 습 니 다
  • 2.hash 속성 값 이 자주 변경 되 지 않도록 유일 성 을 확보 하여 HashMap 용기 와 유사 해 야 해당 하 는 key-value 캐 시 기능 을 실현 할 수 있 습 니 다
  • 4.567917.3.문자열 상수 탱크 를 실현 할 수 있 습 니 다String 대상 최적화
    문자열 은 우리 가 자주 사용 하 는 자바 형식 중 하나 이기 때문에 문자열 에 대한 조작 도 피 할 수 없습니다.문자열 을 조작 하 는 과정 에서 잘못 사용 하면 성능 이 천차만별 입 니 다.그렇다면 문자열 을 조작 하 는 과정 에서 우리 가 주의해 야 할 부분 은 무엇 입 니까?
    우아 한 맞 춤 문자열
    문자열 의 맞 춤 법 은 문자열 작업 에 가장 자주 사용 되 는 동작 중 하나 입 니 다.String 대상 의 불변성 을 알 고 있 기 때문에 우 리 는 맞 춤 법 을 만 들 때 가능 한 한 적 게+문자열 맞 춤 법 을 사용 하거나 잠재의식 적 으로+문자열 맞 춤 법 을 사용 할 수 없다 고 생각 합 니 다.+문자열 맞 춤 법 을 사용 하면 많은 쓸모없는 대상 이 생 길 수 있다 고 생각 합 니 다.사실 이 정말 그렇습니까?우리 실험 을 하나 하 자.우 리 는 아래 문자열 을 연결 하기 위해+를 사용 합 니 다.
    
    String str8 = "ping" +"tou"+"ge";
    이 코드 가 몇 개의 대상 을 만 들 수 있 는 지 분석 해 볼 까요?우리 가 이해 하 는 뜻 에 따라 분석 하면 먼저 ping 대상 을 만 들 고 pingtou 대상 을 만 들 고 마지막 에 pingtouge 대상 을 만 들 며 모두 세 개의 대상 을 만 들 었 습 니 다.정말 그런 가요?사실은 그렇지 않 습 니 다.자바 회 사 는 우리 프로그래머 가 잘못 할 까 봐 컴 파일 러 를 최적화 시 켰 습 니 다.위의 이 문자열 의 조합 은 우리 의 컴 파일 러 에 의 해 최적화 되 고 String str 8='pingtouge'로 최적화 될 것 입 니 다.대상상수 문자열 의 연결 을 최적화 하 는 것 을 제외 하고+번호 동적 연결 문자열 을 사용 하 는 데 있어 컴 파일 러 도 해당 하 는 최적화 를 하여 String 의 성능 을 향상 시 켰 다.예 를 들 어 다음 코드 와 같다.
    
    String str = "pingtouge";
    
    for(int i=0; i<1000; i++) {
       str = str + i;
    }
    
    
    컴 파 일 러 가 이렇게 최적화 해 줄 거 예요.
    
    String str = "pingtouge";
    
    for(int i=0; i<1000; i++) {
          str = (new StringBuilder(String.valueOf(str))).append(i).toString();
    }
    
    
    이 를 통 해 알 수 있 듯 이 자바 회 사 는 이 부분 에 대해 많은 최적화 를 했 고 프로그래머 가 부주의 로 인해 String 의 성능 이 급 격 히 떨 어 지 는 것 을 방지 했다.비록 자바 회 사 는 컴 파일 러 라 는 부분 에 해당 하 는 최적화 를 했 지만 우 리 는 자바 회사 의 최적화 부족 한 점 을 알 수 있다.동적 으로 문자열 을 연결 할 때 StringBuilder 를 사용 하여 문자열 을 연결 했다.그러나 순환 할 때마다 새로운 StringBuilder 인 스 턴 스 를 생 성하 고 시스템 의 성능 도 떨 어 집 니 다.
    그래서 우 리 는 문자열 연결 을 할 때 코드 차원 에서 최적화 해 야 합 니 다.동적 연결 문자열 을 사용 할 때 스 레 드 안전 과 관련 되 지 않 은 상황 에서 우 리 는 StringBuilder 를 사용 하여 연결 하여 시스템 성능 을 향상 시 켜 야 합 니 다.스 레 드 안전 과 관련 되면 StringBuffer 를 사용 하여 문자열 연결 을 합 니 다.
    intern()방법 교묘 하 게 사용 하기
    
       * <p>
       * When the intern method is invoked, if the pool already contains a
       * string equal to this {@code String} object as determined by
       * the {@link #equals(Object)} method, then the string from the pool is
       * returned. Otherwise, this {@code String} object is added to the
       * pool and a reference to this {@code String} object is returned.
       * <p>
       public native String intern();
    이것 은 intern()함수 의 공식 주석 설명 입 니 다.아마도 intern 함 수 는 상수 탱크 의 한 문자열 을 되 돌려 주 는 데 사 용 될 것 입 니 다.상수 탱크 에 이 문자열 이 존재 한다 면 상수 탱크 에 있 는 대상 의 인용 을 직접 되 돌려 줍 니 다.그렇지 않 으 면 상수 탱크 에 이 대상 을 넣 고 인용 을 되 돌려 줍 니 다.
    한 트 위 터 엔 지 니 어 는 QCon 글로벌 소프트웨어 개발 대회 에서 String 대상 에 대한 최적화 사례 를 공유 했다.그들 은 String.intern()방법 을 이용 하여 이전 20G 메모리 저장 소 를 수백 조 메모리 로 최적화 시 켰 다.이것 은 String.intern()의 위력 을 충분히 나 타 낼 수 있 습 니 다.예 를 들 어 String.intern()의 용법 을 간단하게 알 아 보 겠 습 니 다.
    
      public static void main(String[] args) {
        String str = new String("pingtouge");
        String str1 = new String("pingtouge");
        System.out.println("   intern()  :"+(str==str1));
        System.out.println("   intern()  ,str:"+str);
        System.out.println("   intern()  ,str1:"+str1);
    
        String str2= new String("pingtouge").intern();
        String str3 = new String("pingtouge").intern();
        System.out.println("  intern()  :"+(str2==str3));
        System.out.println("  intern()  ,str2:"+str2);
        System.out.println("  intern()  ,str3:"+str3);
    
      }
    
    

    결과 에서 보 듯 이 String.intern()방법 을 사용 하지 않 았 을 때 같은 값 을 구성 한 문자열 대상 은 서로 다른 대상 의 참조 주 소 를 되 돌려 주 고 String.intern()방법 을 사용 한 후 같은 값 의 문자열 대상 을 구성 할 때 같은 대상 의 참조 주 소 를 되 돌려 줍 니 다.이것 은 우리 가 많은 공간 을 절약 하 는 데 도움 을 줄 수 있다.
    String.intern()방법 은 좋 지만 우 리 는 장면 과 결합 하여 사용 해 야 합 니 다.함부로 사용 해 서 는 안 됩 니 다.상수 탱크 의 실현 은 하나의 Hash Table 과 유사 한 실현 방식 이기 때문에 Hash Table 에 저 장 된 데이터 가 클 수록 옮 겨 다 니 는 시간 복잡 도가 증가 합 니 다.데이터 가 너무 크 면 전체 문자열 상수 탱크 의 부담 이 증가 합 니 다.
    유연 한 문자열 분할
    문자열 의 분할 은 문자열 작업 에 자주 사용 되 는 작업 중 하나 입 니 다.문자열 의 분할 은 대부분 Split()방법 을 사용 합 니 다.Split()방법 은 대부분 정규 표현 식 을 사용 합 니 다.이러한 분할 방식 자체 에 문제 가 없 지만 정규 표현 식 의 성능 은 매우 불안정 합 니 다.부적 절 한 사용 은 역 추적 문 제 를 일 으 킬 수 있 습 니 다.CPU 가 높 아 지지 않 을 가능성 이 높다.다음 두 가지 상황 에서 Split()방법 은 정규 표현 식 을 사용 하지 않 습 니 다.
  • 들 어 오 는 매개 변수의 길 이 는 1 이 며".$|()[{^?*+\"를 포함 하지 않 습 니 다.regex 원 문자 의 경우 정규 표현 식 을 사용 하지 않 습 니 다
  • 들 어 오 는 매개 변수 길 이 는 2 이 고 첫 번 째 문 자 는 역 슬 래 쉬 이 며 두 번 째 문 자 는 ASCII 숫자 나 ASCII 자모 가 아 닌 경우 정규 표현 식 을 사용 하지 않 습 니 다
  • 따라서 문자열 을 분할 할 때 Split()방법 을 신 중 히 사용 해 야 합 니 다.먼저 String.indexOf()방법 으로 문자열 을 분할 하 는 것 을 고려 해 야 합 니 다.String.indexOf()가 분할 요 구 를 만족 시 키 지 못 하면 Split()방법 을 사용 하고 Split()방법 으로 문자열 을 분할 할 때 역 추적 문 제 를 주의해 야 합 니 다.
    문장 에 부족 한 점 이 있 으 면,여러분 들 께 서 많이 지적 해 주시 고,함께 공부 하 며,함께 진보 해 주시 기 바 랍 니 다.
    참고 자료
    자바 성능 개선 실전 유 초
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기