티스토리 뷰

https://image.freepik.com/free-vector/man-programmer-working-computer-with-code-screen-illustration_87749-275.jpg

 

"자바를 정말 뭐랄까.. 육군사관학교 나오는 중대장 같은 느낌이다.. 엄청 대단하지만 엄격해서 싫다고 해야할까..

 

분명 보이기엔 같아보이지만 다른게 너무 많다. 스크립트 언어가 관대한것에 비해 자바는 상당히 엄격하다. 엄격한 곳에서 오는 장점은 분명하지만 그만큼 개발자들을 가끔 괴롭힌다."

 

그래서 이번 글에는 저를 엄청나게 괴롭혔던 equals()== 의 차이를 알아보려고 합니다.

 

글에 앞서 이해하는데 큰 도움을 주신 박 본부장님께 감사의 인사를 드립니다!!

 


l String 변수를 생성할 때

 

String은 int, float, double 등과 다르게 자바에서는 클래스로 통합니다. 클래스이기 때문에 다른 데이터형과 다르게 객체로도 생성이 가능합니다.

 

  • 리터럴을 이용하여 String 생성

  • new 연산자를 이용한 String 객체 생성

 

package sec01.seco1;

public class testClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str = "test"; // 리터럴 사용
		String str2 = new String("test"); // new 연산자 사용
		
		System.out.println("str => " + str);
		System.out.println("str2 => " + str2);
	}

}

 

 

리터럴로 생성할 시 String은 String Constant Pool 이라는 곳에 생성되고, new 연산자를 이용하면 Heap 이라는 곳에 저장됩니다. 두 방식다 결국 메모리에 주소 영역을 할당하게 됩니다.

 

그리고 결론부터 얘기하면 equals 경우 문자열 자체를 비교하는 것이고, == 는 String의 주소를 비교합니다.

 

package sec01.seco1;

public class testClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str = "test"; // 리터럴 사용
		String str2 = new String("test"); // new 연산자 사용
		String str3 = "test";
		
		
		if(str == str2) {
			System.out.println("str 와 str2 는 같습니다.");
		}else{
			System.out.println("str 와 str2 는 다릅니다."); // 출력
		}
		
		if(str == str3) {
			System.out.println("str 와 str3 는 같습니다."); // 출력
		}else {
			System.out.println("str 와 str3 는 다릅니다.");
		}
		
		if(str.equals(str3)) {
			System.out.println("equal 함수를 이용한 str 와 str3 는 같습니다."); //출력
		}else {
			System.out.println("equal 함수를 이용한 str 와 str3 는 다릅니다.");
		}
	}

}

 

각각의 조건문에서 과연 어떻게 출력될까요??

 

첫번째 조건문은 "다릅니다"가 출력되고, 두번째 조건문은 "같습니다"가 출력됩니다.

 

리터럴로 생성시켜준 String 의 경우 문자열 비교 할 때  문자열이 같으면 true를 출력하지만, 리터럴로 생성시켜준 String와 new 연산사를 이용해 생성한 String은 분명 문자열은 같지만 메모리에 할당된 주소 영역이 다르기 때문에 다르다고 출력이 됩니다. 즉 ==는 주소를 비교하기 때문에 리터럴과 객체를 비교했을 때는 다르다고 나올수 밖에 없습니다.

 

그리고 세번째 equals는 문자열 자체를 비교한다고 했으므로 주소가 달라도 true를 출력하게 됩니다.

 

문자열을 객체로 받을 경우 그 객체에 대한 비교는 String 주소값이 달라서 비교 할수 없습니다.

 


l new 연산자를 == 로 비교하는 방법은 없을까?

 

package sec01.seco1;

public class testClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str = new String("test");
		
		System.out.println(str == "test"); //false
		System.out.println(str.equals("test")); //true
		
		System.out.println(str.toString() == "test"); //false
		System.out.println((String) str == "test"); //false
		System.out.println(String.valueOf(str) == "test"); //false
	}

}

 

new 연산자로 생성한 String을 그럼 == 비교를 하여서 true로 나오게 해줄순 없을까라는 궁금증이 생겼습니다. 그래서 위와 같이 코드를 짠 후 실행시켜봤는데 두번째 말고는 다 false가 나왔습니다. 

 

첫번째 경우, 앞에서 다루었듯이 당연히 주소 비교를 했을 때 그냥 문자열과 new 연산자로 만들어준 String의 주소는 다르기 때문에 false가 맞습니다.

 

두번째 경우, equasl()를 이용하여 String의 주소가 아닌 문자열 자체를 비교함으로 true가 맞습니다.

 

세번째,네번째, 다섯번째 경우 new 연산자로 생성을 했을시 Object 형태를 String 형태로 바꿔준 후 == 비교를 하면 될줄 알았는데 false가 출력됐습니다.

 

정확한 이유는 아닐수 있지만, 제 추측으로는 new 연산자로 생성했을 당시 str 객체는 이미 메모리에 자신만의 주소 영역을 갖고 있을 것입니다. 하지만 casting, toString, String.valueOf 함수의 경우 문자열의 형을 바꿔주는 것이지 그 객체의 주소를 바꿔주지는 않습니다. 따라서 문자열의 형태는 바뀌었지만 주소 영역은 여전히 그대로 이기 때문에 주소를 비교해주는 == 할 경우 주소가 다르기 때문에 false가 출력되는 것입니다.

 

제 결론은 따라서 str 객체의 주소를 변경시켜주지 않는 한 이미 생성된 객체에 대해 아무리 형태를 바꿔보아도 == 비교는 할수 없습니다.

 

정확한 답은 아니지만, 저는 이렇게 생각합니다. 혹시 답에 대해 아시는 분이 있으시면 알려주십시오.

 


l 요약

 

문자열 비교 할경우 웬만하면 그냥 equals를 사용해라 입니다.

  • equals : 문자열 자체 비교

  • == : 주소 비교

 

 

읽어주셔서 감사합니다.

질문은 언제나 환영합니다.

 

"난 반드시 백엔드 왕이 될거야"

 

댓글
댓글쓰기 폼
공지사항
Total
248,427
Today
802
Yesterday
1,065
링크
«   2022/10   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함