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
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 이 상수 탱크 에서 회수 되 지 않 고 다른 스 레 드 에 의 해 상수 탱크 에서 직접 읽 히 지 않 는 한 매우 드 문 일 것 입 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
2022년 3월 21일 TIL1. JVM & JDK JVM JRE 자바 실행 환경의 약자로 자바 프로그램을 실행하기 위한 도구들이 들어있으며 JVM이 이 안에 포함된다 JDK JRE + 개발툴 javac는 컴파일 명령어 HelloWorld.cl...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.