자바에서의 String 타입
String name = "홍길동";
String 객체를 생성할 때 문자열 값인 "홍길동"은 String 객체로 생성되고, name 변수는 생성된 String 객체를 참조한다.
String 타입은 클래스 타입으로, 참조 타입이기 때문에 기본 타입과는 달리 힙 영역에 생성되기 때문에 이러한 구조를 가진다.
name 변수 자체는 스택 영역에 저장되고, 문자열 리터럴인 "홍길동"은 힙 영역에 String 객체로 생성된다.
그리고 name 변수에 "홍길동"이 담겨있는 String 객체의 주소 값이 저장된다.
문자열 리터럴
자바에서는 문자열 리터럴이 동일하다면 String 객체를 공유한다.
String name1 = "홍길동";
String name2 = "홍길동";
따라서 위와 같은 경우 name1과 name2는 같은 힙 영역의 String 객체를 가리키고 있다. 그래서 name1과 name2에 저장된 주소 값도 동일하다.
자바에서는 객체 주소를 해시 코드로 쓴다. 따라서 주소 값을 구하기 위하여 System.identityHashCode()를 사용한다.
name1과 name2는 엄연히 다른 변수이지만, 두 변수 모두 "홍길동"이 담긴 String 객체의 주소 값을 참조하고 있으므로 System.identityHashcode() 값(주소 값)이 같다.
new 연산자
일반적으로 변수에 문자열을 저장할 때는 위처럼 문자열 리터럴을 사용하지만 new 연산자를 사용해 String 객체를 생성할 수도 있다. 이때는 문자열 리터럴로 생성했던 때와는 달리, 힙 영역에 무조건 새로운 객체를 생성하게 된다.
name2 변수에 저장한 "홍길동"은 앞전과는 다르게 new 연산자로 생성하였다. 따라서 같은 "홍길동" 값임에도 불구하고 주소 값이 다르게 나오는 것을 볼 수 있다.
각각의 name1, name2 변수가 다른 String 객체의 주소 값을 가리키고 있는 것이다.
equals()
String 타입 변수에 저장된 값만을 비교하려면 equals() 메서드를 사용하여야 한다.
String 객체를 == 연산자로 비교하는 경우 변수 값에 저장된 주소 값을 비교하는 것이므로 값을 비교하기 위해서는 equals() 메서드를 사용해야 한다.
boolean result = name1.equals(name2);
name1에 저장된 문자열 값과 name2에 저장된 문자열 값이 같은 경우 true를 반환하고, 다른 경우 false를 반환한다.
equals() 메서드 사용 시 의도하는 바와 다르게 NullPointerException이 발생하는 경우가 있다.
boolean matchStr(String str1) {
String str2 = "홍길동";
boolean result = str1.equals(str2);
return result;
}
str1 값은 매개변수로 받아오고, str2 값은 메서드 내에 초기화되어 있는 상태이다.
이때 만약 str1 변수에 null 값이 들어오는 경우 NullPointerException이 발생한다.
따라서 위와 같은 경우는 equlas() 메서드를 아래처럼 변경하여 사용하는 것이 좋다.
boolean result = str2.equals(str1);
매개변수로 받는 값을 () 안에 넣어주면 str1에 저장된 값이 null 값이어도 NullPointerException이 발생하지 않는다.
물론 경우에 따라서 equlas() 메서드를 통한 비교 전에 null 처리를 먼저 해주는 것이 좋을 수 있다.