List<String> names = List.of("Haiseong", "Jazz", "Kelly", ..... "Mason");
for (int i = 0; i < 100000000; i++) {
if ("Haiseong".equals(name)) {
System.out.println(name);
}
}
오늘 우테코에 출근해서 처음만난 크루(도비)와 이야기 하던중 예전에 블로그에 정리했던 내용을 공유할 일이 있었다.
'위의 코드에서 "Haiseong" 이라는 문자열이 지역변수로 100000000번 생기고 사라지면 비효율 적인 코드 아닌가요?'
위와같은 질문을 받은 나는 이전에 String Pool에 대한 개념을 공부하고 블로그에 정리한 적이 있어서 바로 대답할 수 있었다.
'"Haiseong"이라는 문자열은 String Pool 이라는 공간에 한개만 만들어져서 재활용 됩니다.'
공부한지 1년반 지난 내용이였지만 꽤 잘 대답할 수 있었다. 오늘 이 대화를 통해 블로그 정리의 중요성을 느꼈다. 오늘부터 다시 열심히 배운 내용을 정리해야지.
이전에 포스팅했던 글이 있다. 다시 읽어보니 조금 설명한 부족한 부분과 해깔릴만한 부분이 보여 복습하는 느낌으로 다시 블로그를 써본다.
다시 읽어보니 조금 설명한 부족한 부분과 해깔릴만한 부분이 보여 복습하는 느낌으로 다시 블로그를 써본다.
자바에서 String은 매우 특수하다. 우선 String은 int나 long 같은 원시값이 아닌 객체다. 객체는 new 키워드를 통해 생성하여 사용해야한다. 그러나 String을 쓸때 new를 사용하지 않아도 된다. 그리고 String은 또 다른 중요한 성질이 있다.
자바에서 String은 바꿀 수 없다. (String is immutable)
처음에 이말을 잘 이해하지 못했다. 왜냐하면 아래와 같은 코드가 너무 잘 동작하기 때문이다.
String name = "Haiseong";
System.out.println("name before = " + name);
name = "Loki";
System.out.println("name after = " + name);
// name before = Haiseong
// name after = Loki
바꿀 수 없다며 너무 잘바뀌는데?
이 질문을 가지고 계속 읽어보자.
== 연산자는 비교하고자 하는 두개의 대상의 주소값을 비교하는데 반해 String클래스의 equals 메소드는 비교하고자 하는 두개의 대상의 값 자체를 비교한다.
record Position(int x, int y) {
}
Position position = new Position(1, 2);
Position samePosition = new Position(1, 2);
System.out.println("(position == samePosition) = " + (position == samePosition));
System.out.println("position.equals(samePosition) = " + position.equals(samePosition));
// (position == samePosition) = false
// position.equals(samePosition) = true
record 는 equals를 자동으로 구현해주기 때문에 x, y 값이 같다면 equals의 결과가 true가 나온다. 그러나 position == samePosition은 주소가 다르기 때문에 false가 나온다.
이번엔 String을 비교해보자
String name = "Haiseong";
String sameName = "Haiseong";
System.out.println("(name == sameName) = " + (name == sameName));
System.out.println("name.equals(sameName) = " + name.equals(sameName));
// (name == sameName) = true
// name.equals(sameName) = true
equals의 결과가 true가 나오는것은 당연하다. 우리는 name == sameName가 왜 true가 나왔는지 생각해봐야한다.
== 의 결과가 true가 나왔다는건 name과 sameName의 주소값이 같다는 것이다. 어떻게 이것이 가능한 것인가?
클래스의 생성자를 호출하면 클래스의 인스턴스는 메모리에 동적할당된다. 이 메모리 영역을 힙 영역이라고 한다.
우리는 String을 생성자를 통해 만들지 않는다. 쌍따옴표(""
)를 이용해서 만든다. 이 방식을 String literal 이라고 한다. 이 방식을 통해 만든 String은 String Pool에 저장된다.
String Pool은 힙영역 안에 있는 공간이다. String Constant Pool이라고도 하는데 이 공간은 String literal로 만들어진 문자열들이 저장된다. 이때 문자열의 내용이 같다면 인스턴스를 공유한다.
String str1 = "hello world";
String str2 = "hello world";
이런 코드가 있다면 다음처럼 저장된다.
이 상태에서 다음코드가 실행된다.
String str2 += "!!!";
위에서 말했듯이 자바에서 String은 바꿀 수 없다. 따라서 새로운 String을 만든다.
여기서 중요한 점은 String 클래스는 기존의 "Hello world" 객체를 바꾸는 게 아니다. 새로운 "Hello world!!!" 객체를 만든다는 것이다. String이 한 번 생성되면 생성된 String 인스턴스가 변하지 않고 연산할 때마다 새로운 String 인스턴스로 생성하고 그 인스턴스를 참조한다.
String literal로 String을 생성하는 방법외에 다른 방법이 있다. 생성자를 통해 String을 생성하는것이다.
String str3 = new String("hello world");
생성자로 만들어진 String은 String Pool에 저장되지 않는다. 일반 인스턴스와 같이 힙 영역에 저장된다.
따라서 "Haiseong" == new String("Haiseong")
의 결과는 false다.
String name = "Haiseong";
String nameByConstructor = new String("Haiseong");
System.out.println("(name == nameByConstructor) = " + (name == nameByConstructor));
System.out.println("name.equals(nameByConstructor) = " + name.equals(nameByConstructor));
// false
// true
아 이제 블로그 진짜 열심히 써야지