한성이가 StringBuffer와 StringBuilder의 차이에 대해서 물어봐서 ThreadSafe 한지 안한지 차이라고 확인해주었다.
그런데 인터넷에 "String, StringBuffer, StringBuilder의 차이점과 장단점은 뭔가요?"를 글을 보다가 미물님이 테스트한 글을 보게 되었다.
테스트의 요지는 StringBuffer랑 문자열을 +로 붙이는 것의 비교였다.
왠지 컴파일 될 때 최적화가 되어 문자열이 하나로 합쳐지는 것이 아닌가 의심이 되었다.
테스트 JDK는 1.7.0_45이다.
그래서 아래와 같은 간단한 클래스를 만들어보았다.
class Test
{
public static void main(String[] args)
{
String str1 = "Hello";
String str2 = "World!";
String str = str1 + " " + str2;
System.out.println(str);
}
}
str이 "Hello World!" 와 같은 형태로 저장이 된다면 최적화를 할 수 있다고 볼 수도 있는 것이다.
아래와 같은 일련의 단계를 걸쳐 바이트코드를 얻을 수 있었다.
Test.java --- javac.exe -> Test.class --- javap Test.class -> 바이트코드
> javac Test.java
> java Test
Hello World!
> javap -v -p Test.class > bytecode.txt
결과: bytecode.txt
생각과는 달리 코드에서 문자열은 합쳐져서 존재하지 않았고 각각의 문자열 풀에 존재하였다.
또한 + 연산은 StringBuilder에 의해 append 되고 있었다.
0 ldc #2 <Hello>
2 astore_1
3 ldc #3 <World!>
5 astore_2
6 new #4 <java/lang/StringBuilder>
9 dup
10 invokespecial #5 <java/lang/StringBuilder.<init>>
13 aload_1
14 invokevirtual #6 <java/lang/StringBuilder.append>
17 ldc #7 < >
19 invokevirtual #6 <java/lang/StringBuilder.append>
22 aload_2
23 invokevirtual #6 <java/lang/StringBuilder.append>
26 invokevirtual #8 <java/lang/StringBuilder.toString>
29 astore_3
30 getstatic #9 <java/lang/System.out>
33 aload_3
34 invokevirtual #10 <java/io/PrintStream.println>
37 return
그렇다면 메서드를 호출하는 경우에는 동일할까?
class Test
{
private static String operation()
{
String str = "Hello" + " " + "World!";
return str;
}
private static String stringBuilder()
{
StringBuilder sb = new StringBuilder("Hello");
sb.append(" ");
sb.append("World!");
String str = sb.toString();
return str;
}
public static void main(String[] args)
{
System.out.println(operation());
System.out.println(stringBuilder());
}
}
바이트 코드를 보면
operation메서드에서 문자열을 붙이지 않고 아예 상수로 가지고 있음을 알 수 있다.
0 ldc #2 <Hello World!>
2 astore_0
3 aload_0
4 areturn
마지막으로 미물님이 테스트한 코드의 바이트 코드를 살펴보았다.
private static Repeatable stringConcatenationTest = new Repeatable()
{
public void iteration(long loopId) {
String query =
"SELECT " +
"a.userName, " +
"a.registerDate, " +
"sum(a.duration), " +
"a.id " +
"FROM " +
StringTest.class.getName() +
" as a " + "ORDER BY " +
"a.registerDate desc";
String result = query;
}
};
stringConcatenationTest 필드의 경우 아래와 같이 바이트코드로 된다.
0 new #2 <java/lang/StringBuilder>
3 dup
4 invokespecial #3 <java/lang/StringBuilder.<init>>
7 ldc #4 <SELECT a.userName, a.registerDate, sum(a.duration), a.id FROM >
9 invokevirtual #5 <java/lang/StringBuilder.append>
12 ldc_w #6 <Test>
15 invokevirtual #7 <java/lang/Class.getName>
18 invokevirtual #5 <java/lang/StringBuilder.append>
21 ldc #8 < as a >
23 invokevirtual #5 <java/lang/StringBuilder.append>
26 ldc #9 <ORDER BY >
28 invokevirtual #5 <java/lang/StringBuilder.append>
31 ldc #10 <a.registerDate desc>
33 invokevirtual #5 <java/lang/StringBuilder.append>
36 invokevirtual #11 <java/lang/StringBuilder.toString>
39 astore_3
40 aload_3
41 astore 4
43 return
추과 관련 링크: http://www.slipp.net/questions/271
'Programing > JVM(Java, Kotlin)' 카테고리의 다른 글
[Java] 배열 최대 할당 가능 크기? (0) | 2015.01.07 |
---|---|
[MVC] 파일 업로드 (0) | 2015.01.05 |
STS 이클립스에 설치하기 (0) | 2014.10.27 |
Eclipse: Maven을 사용해서 Dynamic Web Project 생성하기 (0) | 2014.08.11 |
[이럴수가] 바이트 배열을 숫자로 바꾸다 발견한 점 (0) | 2014.03.04 |