전에 작성한 포스팅 중, null과 inEmpty의 차이점에 대해 작성했던 적이 있었다.
isEmpty와 ==null - 객체가 비어있는지 확인하는 방법 — 간편 웹프로그래밍 (tistory.com)
이번엔 ==과 equals()에 대해 포스팅해보려고 한다.
일단 null은 메모리영역이 아예 비워있을 때 true이고, isEmpty는 객체가 비어있을 때 true이다.
String a = "" ; 라면 null은 false, isEmpty는 true가 되는 것 이다.
즉 메모리영역이 비어있는지, 아닌 지가 차이점이라는 것이다.
이번에 포스팅 할 ==와 equals 도 같은 맥락이다.
우선 먼저 예제를 살펴보자.
//reference type
String text1 = "sample";
String text2 = text1;
String text3 = new String("sample");
String text4 = new String("sample");
System.out.println(text1 == text2); //true
System.out.println(text1.equals(text2)); //true
System.out.println(text3 == text4); //false
System.out.println(text3.equals(text4)); //true
System.out.println(text3.equals(text1)); //true
먼저, ==연산자는 int,boolean과 같은 primitive type에 대해서는 값을 비교하지만,
reference type에 대해서는 주소값을 비교한다.
하지만 equals() 는 내용을 비교한다.
그 해답은 Java String 클래스의 equlas() 함수에 들어가 보면 알 수 있다.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
먼저 equlas()의 매개변수로 들어온 객체가 자기 자신과 주소값이 값으면 첫번째 if 문에서 true를 리턴한다.
주소값이 다르다면 String 객체의 문자열을 Char타입으로 하나씩 비교해 보면서 boolean을 리턴한다.
그렇기 때문에, 다른 주소값을 가진 text3 와 text4는 ==연산자로 비교했을 땐 false를 리턴하고,
equals()로 비교했을땐 true를 리턴하는 것이다.
그런데 왜 text1 과 text2는 같은 것 일까? 이것도 다른 주소값을 가진 String 객체가 아닌가?
text1은 new 연산자가 아닌 =""로 생성했기 때문에 힙 영역 안에서 String Constant Pool에 (주소, 값)
형태로 저장된다. 그 후로 ""로 생성한 String 객체는 먼저 String Constant Pool 안에 자신이 생성할 문자열과
같은 값이 있는지 찾아본다. 같은 값이 존재한다면 공간을 새로 만드는 것이 아닌,
주소값이 미리 만들어진 String ConstantPool에 있는 값을 연결한다.
결국 같은 값을 가르키기 떄문에 ==연산과 equals() 연산 둘다 true가 리턴되는 것이다.
==은 주소값, equals()는 문자열이다.
String Pool이란 무엇일까?
흔히 new 연산자로 String 객체를 생성하지 않는 것이 좋다라는 말을 볼 수 있다.
인터넷에 기능구현에 관한 예제를 검색해봐도 대부분 String a = "" , literal 형식으로 생성하지,
new 연산자를 사용해서 객체를 생성하지 않는다.
String literal로 생성하면 해당 String 값은 Heap 영역 내 "String Constant Pool"에 저장되어 재사용되지만,
new 연산자로 생성하면 같은 내용이라도 여러 개의 객체가 각각 Heap 영역을 차지하기 때문이다.
위의 사진이 text1 == text2가 true , text3 == text4가 false가 되는 이유이다.
String 객체를 new 연산자로 생성하면 , 같은 값이라도 매번 Heap 영역에 새로운 객체가 생성되고,
String이 갖는 불변성이라는 장점을 누리지 못하게 된다.
메모리를 효율적으로 사용하기 위해서는 항상 String literal 를 사용해서 객체를 생성하는 것이 좋겠다.
그런데, 일단 String은 Object 클래스니까 Heap영역에 저장되는 것은 알겠다.
하지만 Stack과 Heap 영역의 차이와 가비지컬렉터가 작동하는 기준은 무엇일까?
해당 궁금증에 대한 것을 다음 포스팅에 적어보려고 한다.
'JAVA > 자바' 카테고리의 다른 글
[JAVA] Static과 Final (0) | 2022.02.26 |
---|---|
[JAVA] 스택과 힙 , 가비지 컬렉터 (1) | 2022.02.25 |
Java 문자열 나누기 - substring , indexOf , charAt (0) | 2021.12.29 |
Java 배열 정렬하기 (0) | 2021.12.11 |
Java 입력 받은 값을 배열에 저장 (0) | 2021.12.11 |