JDK 소스 코드 에서 실 용적 인'팁'요약

머리말
그 동안 비교적 한가 해서 jdk 소스 코드 를 보기 시작 했다.일반적인 고급 개발 엔지니어 가 소스 코드 를 읽 을 수 있 는 것 은 자신의 향상 에 매우 크다.본 고 는 JDK 소스 코드 중의'작은 기교'를 정리 하여 여러분 들 이 참고 하여 공부 할 수 있 도록 공유 하 였 습 니 다.다음은 더 이상 말 하지 않 겠 습 니 다.상세 한 소 개 를 해 보 겠 습 니 다.
1 i++ vs i--
String 소스 의 985 줄,equals 방법 중

 while (n--!= 0) {
  if (v1[i] != v2[i])
   return false;
  i++;   
 }
이 코드 는 문자열 이 같은 지 아 닌 지 를 판단 하 는 데 사용 되 지만 이상 한 점 은 i--!=0 으로 판단 합 니 다.우 리 는 보통 i++를 사용 하지 않 습 니까?왜 i 를 써 요.-네?그리고 순환 횟수 가 같다.컴 파일 후 명령 이 하나 더 있 기 때 문 입 니 다:
i-작업 자 체 는 CPSR(현재 프로그램 상태 레지스터)에 영향 을 줄 수 있 습 니 다.CPSR 에서 흔히 볼 수 있 는 플래그 는 N(결과 마이너스),Z(결과 0),C(진 위 있 음),O(넘 침 있 음)입 니 다.i>0,Z 표 지 를 통 해 직접 판단 할 수 있 습 니 다.
i++작업 도 CPSR(현재 프로그램 상태 레지스터)에 영향 을 미 치지 만 O(넘 침)로고 에 만 영향 을 줍 니 다.이것 은 i쉽게 말 하면 0 과 비교 하면 명령 이 하나 줄 어 들 것 이다.그래서 순환 사용 i-,고급 대기 등급.
2 구성원 변수 vs 부분 변수
JDK 소스 코드 는 모든 방법 에서 구성원 변 수 를 부분 변수 로 받 아들 입 니 다.예 를 들 어

public int compareTo(String anotherString) {
  int len1 = value.length;
  int len2 = anotherString.value.length;
부분 변수 가 초기 화 된 후에 이 방법 스 레 드 스 택 에 있 고 구성원 변수 가 초기 화 된 것 은 메모리 에 있 기 때문에 전자 가 더 빠 릅 니 다.그래서 우 리 는 방법 에서 구성원 변 수 를 직접 사용 하 는 것 을 피하 고 부분 변 수 를 사용 합 니 다.
3.레지스터 에 불 러 오기&&시간 소모 동작 을 잠 금 외부 에 두 기
Concurrent HashMap 에서 segment 를 잠 그 는 작업 은 매우 재 미 있 습 니 다.직접 잠 그 는 것 이 아니 라 자 물 쇠 를 가 져 오 는 것 과 같 습 니 다.자 물 쇠 를 가 져 오 는 과정 에서 링크 를 옮 겨 다 니 며 데 이 터 를 레지스터 에 캐 시 에 먼저 불 러 와 잠 그 는 과정 에서 편리 함 을 피 하 는 동시에 새로운 대상 을 만 드 는 작업 도 자물쇠 의 외부 에 두 어 합 니 다.자물쇠 에서 의 시간 소모 조작 을 피하 다.

  final V put(K key, int hash, V value, boolean onlyIfAbsent) {
    /**     segment    ,       segment     
          lock(),       */
    HashEntry<K,V> node = tryLock() ? null :
      scanAndLockForPut(key, hash, value);
scanAndrockForPut()원본 코드

private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
  HashEntry<K,V> first = entryForHash(this, hash);
  HashEntry<K,V> e = first;
  HashEntry<K,V> node = null;
  int retries = -1; // negative while locating node

  //      
  while (!tryLock()) {
    HashEntry<K,V> f; // to recheck first below
    if (retries < 0) {
      if (e == null) {
        if (node == null) // speculatively create node
          // hash   ,    ,     put()        
          node = new HashEntry<K,V>(hash, key, value, null);
        retries = 0;
      }
      // hash  key   ,      
      else if (key.equals(e.key))
        retries = 0;
      else
        //     ,cpu          
        e = e.next;
    }
    // retries>0       。  ,           MAX_SCAN_RETRIES(  1  64),     ,          
    //  lock()      ,        ,    
    else if (++retries > MAX_SCAN_RETRIES) {
      lock();
      break;
    }
    else if ((retries & 1) == 0 &&
         //           ,             ,       
         //           ,           scanAndLockForPut   
         (f = entryForHash(this, hash)) != first) {
      e = first = f; // re-traverse if entry changed
      retries = -1;
    }
  }
  return node;
}
4.판단 대상 이 같 으 면 먼저 사용 할 수 있다==
대상 이 같은 지 아 닌 지 를 판단 할 때 는 먼저===주 소 를 직접 비교 하 는 것 이 매우 빠 르 기 때문에 equals 는 가장 대상 값 의 비교 가 상대 적 으로 느 리 기 때문에 가능 하 다 면 a=b||a.equals(b)로 대상 이 같은 지 비교 할 수 있다.
5 transient 에 대하 여
transient 는 직렬 화 를 막 는 데 사용 되 지만 HashMap 소스 코드 에서 내부 배열 은 transient 로 정의 합 니 다.

 /**
   * The table, resized as necessary. Length MUST Always be a power of two.
   */
  transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
그 안에 있 는 키 값 이 정렬 되 지 않 습 니까?네트워크 에서 hashmap 로 전송 하 는 것 은 전송 할 수 없 는 것 이 아니 겠 습 니까?사실은 그렇지 않 습 니 다.
Effective Java 2nd,Item 75,Joshua 대신 언급:
For example, consider the case of a hash table. The physical
representation is a sequence of hash buckets containing key-value
entries. The bucket that an entry resides in is a function of the hash
code of its key, which is not, in general, guaranteed to be the same
from JVM implementation to JVM implementation. In fact, it isn't even
guaranteed to be the same from run to run. Therefore, accepting the
default serialized form for a hash table would constitute a serious
bug. Serializing and deserializing the hash table could yield an
object whose invariants were seriously corrupt.
어떻게 이해 해요?HashMap.get()/put()를 보 세 요.읽 기와 쓰 기 는 Object.hashcode()에 따라 어느 bucket 에서 읽 고 쓰 는 지 확인 합 니 다.Object.hashcode()는 native 방법 으로 JVM 에 따라 다 를 수 있 습 니 다.
예 를 들 어 HashMap 에 entry 를 저장 하고 key 는 문자열'STRING'이 며 첫 번 째 자바 프로그램 에서'STRING'의 hashcode()는 1 이 고 첫 번 째 bucket 에 저장 합 니 다.두 번 째 자바 프로그램 에 서 는"STRING"의 hashcode()가 2 일 수 있 습 니 다.두 번 째 bucket 에 저장 합 니 다.기본 직렬 화(Entry[]table 은 transient 를 사용 하지 않 습 니 다)를 사용 하면 이 HashMap 은 첫 번 째 자바 프로그램 에서 직렬 화 를 통 해 두 번 째 자바 프로그램 을 가 져 온 후 메모리 분포 가 같 습 니 다.이 건 아 닙 니 다.
예 를 들 어 HashMap 에 키 값 대 entry,key='방 로 사'를 저장 합 니 다.첫 번 째 자바 프로그램 에서'방 로 사'의 hashcode()는 1 이 고 table[1]에 저장 합 니 다.자,이제 다른 JVM 프로그램 에 전 달 됩 니 다.'방 로 사'의 hashcode()는 2 일 수 있 습 니 다.그래서 table[2]에 가서 찾 으 면 결과 값 이 존재 하지 않 습 니 다.
HashMap 의 현재 readObject 와 writeObject 는 내용 을 출력/입력 하여 HashMap 을 다시 생 성 합 니 다.
6.char 쓰 지 마 세 요.
char 는 자바 에서 utf-16 인 코딩 으로 2 개의 바이트 이 고 2 개의 바 이 트 는 모든 문 자 를 표시 할 수 없습니다.2 개의 바이트 가 표시 하 는 것 을 BMP 라 고 하 며,다른 하 이 surrogate 와 low surrogate 의 연결 로 4 바이트 로 표 시 된 문자 입 니 다.예 를 들 어 String 소스 코드 의 index of:

 //   int     char,      
 public int indexOf(int ch, int fromIndex) {
    final int max = value.length;
    if (fromIndex < 0) {
      fromIndex = 0;
    } else if (fromIndex >= max) {
      // Note: fromIndex might be near -1>>>1.
      return -1;
    }
    // Bmp  
    if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
      // handle most cases here (ch is a BMP code point or a
      // negative value (invalid code point))
      final char[] value = this.value;
      for (int i = fromIndex; i < max; i++) {
        if (value[i] == ch) {
          return i;
        }
      }
      return -1;
    } else {
      //             
      return indexOfSupplementary(ch, fromIndex);
    }
  }
그래서 자바 의 char 는 utf 만 표시 할 수 있 습 니 다.­16 의 bmp 부분 문자 입 니 다.CJK(한 중 일 통일 표 의 문자)부분 확장 문자 집합 에 대해 서 는 표시 할 수 없습니다.
예 를 들 어 아래 그림 에서 Ext-A 부분 을 제외 하고 char 는 표시 할 수 없다.

또한,char 를 사용 해 야 한 다 는 설 도 있 습 니 다.비밀 번 호 는 String 을 사용 하지 마 십시오.String 은 상수(즉,생 성 후 변경 할 수 없습니다)입 니 다.상수 풀 에 저 장 됩 니 다.다른 프로 세 스 가 이 프로 세 스 의 메모 리 를 덤 프 할 수 있다 면 비밀 번 호 는 상수 풀 이 덤 프 에 의 해 유출 되 고,char[]는 다른 정 보 를 기록 하여 변경 할 수 있 습 니 다.덤 프 에 걸 려 도 비밀 번 호 를 누설 할 위험 이 줄어든다.
개인 적 으로 덤 프 메모리 가 다 된다 고 생각 합 니 다.String 이 상수 탱크 에서 회수 되 지 않 고 다른 스 레 드 에 의 해 상수 탱크 에서 직접 읽 히 지 않 는 한 매우 드 문 일 것 입 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기