Java(심화) - 스트링 타입과 객체
안녕하세요
Shiny Ocean 입니다 : )
이번 포스팅에서 다룰 내용은 자바의 스트링 타입과 객체에 대한것 입니다.
개요
우리는 앞서 지금까지 참조타입으로 정의할수 있는 "객체"에 대하여 계속 다루고있었습니다. 이번엔 문자열 클래스만 따로 집중적으로 다루어 보겠습니다.
알고리즘 문제를 해결하다보면 탐색트리나 그래프의 노드를 객체로 표현하고 해당 필드의 값을 문자열로 표현하는등의 방법을 많이 사용하는데, 이때 탐색과정에서 분명 같은 문자열인데 다르다고 나오거나 다른 문자열인데 같다고 나오는경우들이 있었습니다.
이러한 것은 문자열의 데이터에만 집중하다보니 해당 타입이 참조타입이라는것을 망각하고 발생시킨 오류입니다. 이번포스팅을 통해 문자열 클래스에 대하여 배우게 된다면 이러한 오류도 왜 생기게 되었는지 알수 있을것이라 생각합니다.
String 타입
기본적으로 스트링 타입은 문자열을 저장하는 클래스 타입입니다. C언어에서는 char 배열을 이용하여 문자열을 다루었다면 자바에서는 따로 이를 객체로 정의한 클래스가 존재하고있기 때문에 이를 이용해서 주로 문자열을 처리하게 됩니다.
일반적인 참조타입과 동일하게 스택영역에 변수명과 함계 문자열 객체의 번지수가 저장되게 되고 해당 번지수를 통해 힙영역내에 실제 존재하는 객체 데이터를 이용할수 있습니다.
그런데 스트링타입의 재밌는점은 문자열 리터럴이 동일하다면 String객체를 공유하는것에 있습니다. 예시를 들겠습니다.
class Human{
int age;
String name;
public Human(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return this.age + ", " +this.name;
}
}
public class Exam {
public static void main(String[] args) {
Human man1 = new Human(21, "kim");
Human man2 = new Human(21, "kim");
System.out.println(man1 == man2);
}
}
위의 코드에서 Human 이란 클래스는 생성자를 통해 필드값을 입력받을수 있도록 하였습니다. 그렇게 구성된 클래스 객체를 같은 나이와 이름으로 초기화하여 선언하여도 이 두객체는 다르다는것을 우리는 지난 포스팅을 통해 알고있습니다.
물론 기본적으로 힙영역에 새로운 객체를 생성하는 new 연산자를 사용한다면 스트링 클래스도 동일한 결과인 false가 나올것입니다. 아래와 같이 말이죠
public class Exam {
public static void main(String[] args) {
String man1 = new String("kim");
String man2 = new String("kim");
System.out.println(man1 == man2);
}
}
하지만, 아주흥미로운점은 여기서 스트링 변수에 직접 값을 초기화 해줄때 발생합니다. 만약 두개의 man이라는 스트링 변수에 동일한 문자열을 초기화 해준다면 둘은 같은 객체를 가리키는 참조타입 변수가 됩니다. 따라서 아래 코드의 결과는 true입니다.
public class Exam {
public static void main(String[] args) {
String man1 = "kim";
String man2 = "kim";
System.out.println(man1 == man2);
}
}
이러한 구조는 아주 흥미롭습니다.
레퍼런스 타입이지만 객체의 데이터필드값을 건드릴 때는 참조가 바뀐다고 해석이 되기 때문입니다.
이에대해 조금더 살펴보겠습니다. 만약 다른 변수명으로 선언된 동일한 객체 타입의 데이터 필드값을 바꿀경우입니다. 아래처럼 man2는 man1을 참조하도록 즉 동일한 객체를 참조하도록 선언하였습니다. 이때 man2의 필드값을 임의로 바꿔주면 동일한 객체를 참조하는 man1의 필드값도 바뀌는 결과를 확인할수 있습니다. 그리고 필드값을 바꾼다고해서 두 객체가 동일하다는 == 의 결과는 true에서 변함이 없습니다.
public class Exam {
public static void main(String[] args) {
Human man1 = new Human(21, "kim");
Human man2 = man1;
man2.age =22;
man2.name ="lee";
System.out.println(man1 == man2);
System.out.println(man1);
System.out.println(man2);
}
}
<결과>
그런데 String 객체의 경우 좀 다릅니다. 아래와 같이 작성된 코드의 첫번째 출력문은 당연히 true입니다, 이후 man2의 문자열데이터를 바꾸어주고 두번째출력문은 false가 됩니다. 즉 문자열을 바꿔 초기화 해주는 것은 새로운 객체를 생성해 참조해주는 것과 같은 효과를 볼수 있습니다. 따라서 위의 예제처럼 man2의 값이 변한다고 man1의 값이 동일하게 바뀌지는 않습니다.
public class Exam {
public static void main(String[] args) {
String man1 = "kim";
String man2 = man1;
System.out.println(man1 == man2);
man2 = "lee";
System.out.println(man1 == man2);
System.out.println(man1);
System.out.println(man2);
}
}
<결과>
여러가지 복잡한 문제로인해 문자열을 편하게 사용하겠다고 시작한 String 자료형이 조금 이상해 진거 같습니다. 하지만 단순히 문자열이 같은지에 대한 참,거짓값만이 필요하다면 스트링 클래스의 equals 메소드를 사용하면 됩니다. 이는 스트링 변수가 서로 참조하는 객체가 다르더라도 문자열 데이터만 같다면 참값을 리턴해주는 메소드입니다. 아래의 예제 코드와 결과를 참고하면 개념을 확실히 하기에 좋을것 같습니다.
public class Exam {
public static void main(String[] args) {
String man1 = "kim";
String man2 = "kim";
String man3 = new String("kim");
System.out.println(man1 == man2);
System.out.println(man1 == man3);
System.out.println(man1.equals(man2));
System.out.println(man1.equals(man3));
}
}
<결과>
+@
지금까지 코드에서 String 타입이 어떻게 동작하는지 알아보고 객체로서 어떤식으로 활용되는지 알아봤습니다. 하지만 스트링 클래스는 조금더 알아야 할 내용이 더 많이 있습니다 이후에 스트링 클래스만 따로 게시글을 통해 다루어 보겠습니다.