나는 평일에 프로젝트의 논리적 구현에 바빴다. 나는 토요일에 약간의 시간을 보냈으므로 책장에서 자바에서 두꺼운 영어 버전의 사고를 꺼내어 문자열 물체의 스 플라이 싱을 읽었습니다. 이 책을 번역으로 참조하고, 생각하는 것을 추가하고,이 기사를 작성하여 기록하십시오.
불변의 문자열 객체
Java에서는 문자열 객체가 불변 (불변)입니다. 코드에서 문자열 객체에 대한 여러 별칭을 만들 수 있습니다. 그러나 이러한 별칭의 참조는 동일합니다.
예를 들어, S1과 S2는 "droidyue.com"객체에 대한 별칭이며 별칭은 실제 객체에 대한 참조로 저장됩니다. 그래서 s1 = s2
문자열 s1 = "droidyue.com"; 문자열 s2 = s1; system.out.println ( "s1 및 s2는 동일한 참조 =" + (s1 == s2));
Java에서 유일하게 과부하 된 연산자
Java에서는 오버로드 된 유일한 연산자는 문자열 스 플라이 싱과 관련이 있습니다. +,+=. 그 외에도 Java 디자이너는 다른 연산자에게 과부하를 허용하지 않습니다.
스 플라이 싱 분석
실제로 성능 비용이 있습니까?
위의 두 가지 점을 이해 한 후에는 그러한 생각이있을 수 있습니다. 찌르기 물체는 불변이기 때문에, 다중 (3 개 이상) 문자열의 접합은 필연적으로 불필요한 중간 문자열 물체를 생성합니다.
문자열 username = "Andy"; String age = "24"; String job = "Developer"; String info = username + age + job;
위의 정보를 얻으려면 Andy24의 컨텐츠와 함께 임시 문자열 객체 T1을 생성하기 위해 사용자 이름과 나이가 스 플라이싱 된 다음 T1 및 작업이 결국 필요한 정보 객체를 생성하기 위해 작업을 연결합니다. 그중에서도 중간 T1이 생성되고 T1이 생성 된 후 자동으로 재활용되지 않아 필연적으로 일정량의 공간을 차지합니다. 그것이 많이 스 플라이 싱이라면 (수백 개가 객체에 대한 토스트 링 호출에서 더 일반적이라고 가정하면) 문자열이 더 커지고 성능이 훨씬 낮아집니다.
컴파일러 최적화 처리
위의 성능 비용이 실제로 있습니까? 문자열 스 플라이 싱은 매우 일반적이므로 특별한 처리 최적화가 없습니까? 답은이 최적화가 컴파일러가 .java를 바이트 코드로 컴파일 할 때 수행된다는 것입니다.
Java 프로그램이 실행되기를 원한다면 시간이 걸리고 시간을 컴파일하고 시간이 걸립니다. 컴파일 시간에 Java 컴파일러 (컴파일러)는 Java 파일을 Bytecode로 변환합니다. 런타임에 JVM (Java Virtual Machine)은 바이트 코드를 생성하는 컴파일 타임을 실행합니다. 이 두 기간 동안 Java는 소위 편집을 달성하고 어디서나 실행했습니다.
컴파일 기간 동안 어떤 최적화가 이루어 졌는지 실험하고 성능 비용이 발생할 수있는 코드를 만듭니다.
공개 클래스 연결 {public static void main (String [] args) {String username = "Andy"; 문자열 age = "24"; 문자열 job = "개발자"; 문자열 정보 = username + age + job; System.out.println (정보); }}Concatenation.java를 컴파일하십시오. Concatenation.class를 얻으십시오
Javac Concatenation.java
그런 다음 Javap을 사용하여 컴파일 된 Concatenation.class 파일을 디 컴파일합니다. Javap -C 연결. Javap 명령을 찾을 수없는 경우 Javap이 환경 변수에 위치하거나 Javap의 전체 경로를 사용하는 디렉토리를 추가하는 것이 좋습니다.
17 : 22 : 04 Androidyue ~/workspace_adt/strings/src $ javap -c "concatenation.java"공개 클래스 연결 {public concatenation (); 코드 : 0 : aload_0 1 : invokespecial #1 // 메소드 Java/lang/Object. "<init>":() v 4 : 공개 정적 무효 메인을 반환합니다 (java.lang.string []); 코드 : 0 : LDC #2 // String Andy 2 : String 2 : Stor_1 3 : LDC #3 // String 24 5 : Store_2 6 : LDC #4 // String Developer 8 : Store_3 9 : New #5 // 클래스 Java/Lang/StringBuilder 12 : Dup 13 : intokescial #6 // method java/lang/lang/stringbuilder. InvokeVirtual #7 // 메소드 java/lang/stringbuilder.append : (ljava/lang/string;) ljava/lang/stringbuilder; 20 : aload_2 21 : InvokeVirtual #7 // 메소드 Java/lang/StringBuilder.Append : (ljava/lang/string;) ljava/lang/StringBuilder; 24 : aload_3 25 : InvokeVirtual #7 // 메소드 Java/Lang/StringBuilder.Append : (ljava/lang/string;) ljava/lang/StringBuilder; 28 : InvokeVirtual #8 // 메소드 Java/Lang/StringBuilder.toString :() ljava/lang/string; 31 : 저장 4 33 : getstatic #9 // 필드 Java/Lang/System.out : ljava/io/printstream; 36 : aload 4 38 : invokevirtual #10 // 메소드 java/io/printstream.println : (ljava/lang/string;) v 41 : return}그중에서도 LDC, 상점 등은 조립 지침과 유사한 Java 바이트 코드 지침입니다. 다음 주석은 Java 관련 컨텐츠를 사용하여 설명합니다. 우리는 그것에 많은 StringBuilder가 있다는 것을 알 수 있지만 Java 코드에 표시하지 않고 호출합니다. 이것은 Java 컴파일러의 최적화입니다. Java 컴파일러가 String 스 플라이 싱을 만나면 StringBuilder 객체를 만듭니다. 그 뒤에 스 플라이 싱은 실제로 StringBuilder 객체의 Append 메소드를 호출하고 있습니다. 이런 식으로, 우리가 걱정하는 문제는 없을 것입니다.
컴파일러 최적화 만?
컴파일러가 최적화에 도움이되었으므로 컴파일러의 최적화에만 의존하기에 충분합니까? 물론.
낮은 성능에 최적화되지 않은 코드를 살펴 보겠습니다.
public void implicitusestringBuilder (string [] value) {String result = ""; for (int i = 0; i <value.length; i ++) {result += value [i]; } system.out.println (결과);}Javac과 함께 컴파일하고 Javap으로보기
11 : 새로운 #5 // 클래스 Java/Lang/StringBuilder 14 : DUP 15 : invokespecial #6 // 메소드 Java/Lang/StringBuilder. "<init>":() v 18 : aload_2 19 : invokevirtual #7 // 메소드 31 : Store_2 32 : Iinc 3, 1 35 : Gottatic #9 // Field Java/Lang/System.out : ljava/io/printstream; 41 : aload_2 42 : invokevirtual #10 // 메소드 java/io/printstream.println : (ljava/lang/string;) v 45 : 반환
그중 8 : IF_ICMPGE 38 및 35 : GOTO 5는 루프를 형성합니다. 8 : IF_ICMPGE 38은 JVM 피연산자 스택의 정수 비교가 (i <value.length)의 반대 결과가 참이면 38 행 (System.out)으로 점프한다는 것을 의미합니다. 35 : GOTO 5는 5 행으로 직접 점프하는 것을 의미합니다.
그러나 여기서 StringBuilder 객체 생성이 루프간에 발생한다는 것은 매우 중요한 것이 있습니다. 즉, 루프가 몇 번이나 StringBuilder 객체를 생성 할 것인지를 의미합니다. 알몸의 저수준 코드.
품질을 즉시 향상시키기 위해 약간 최적화하십시오.
public void explicitusestringBuilder (string [] value) {StringBuilder result = new StringBuilder (); for (int i = 0; i <value.length; i ++) {result.append (values [i]); }}해당 편집 된 정보
public void explicitusestringbuider (java.lang.string []); 코드 : 0 : 새로운 #5 // 클래스 java/lang/stringbuilder 3 : dup 4 : invokespecial #6 // 메소드 Java/lang/stringBuilder. "<init>":() v 7 : astore_2 8 : iconst_0 9 : istore_3 10 : iload_3 11 : aload_1 12 : if_icmpge 30 : Aload_1 12 : aload_1 12 : araylength aload_1 18 : iload_3 19 : aaload 20 : invokevirtual #7 // 메소드 java/lang/stringbuilder.append : (ljava/lang/string;) ljava/lang/stringbuilder; 23 : Pop 24 : Iinc 3, 1 27 : Goto 10 30 : 반환
위에서 볼 수 있듯이, 13 : if_icmpge 30 및 27 : goto 10은 루프 루프를 형성하고 0 : 새로운 #5는 루프 외부에 있으므로 StringBuilder는 여러 번 생성되지 않습니다.
일반적으로, 우리는 루프 본체에서 StringBuilders의 암묵적 또는 명백한 생성을 피하려고 노력해야합니다. 따라서 코드가 컴파일되는 방법과 내부적으로 실행되는 방법이 비교적 높은 코드 수준을 갖는 사람들을 이해하는 사람들.
위 기사에 오류가 있으면 비판하고 수정하십시오.
위의 내용은 Java 문자열을 접합하는 것에 대한 정보를 정리하는 것이며 향후 관련 정보를 계속 추가 할 것입니다. 이 웹 사이트를 지원 해주셔서 감사합니다!