package String;
public class CheckCompare {
public static void main(String[] args){
CheckCompare checkCompare = new CheckCompare();
checkCompare.checkCompare();
}
public void checkCompare(){
String text = "Check value";
String text2 = "Check value";
if(text==text2){
System.out.println("text==text2 result is same.");
}else{
System.out.println("text==text2 result is different.");
}
if(text.equals("Check value")){
System.out.println("text.equals(text2) result is same.");
}
}
}
실행 결과
일반적으로 생각하기에는 두 번째 if문만 통과해서 결과가 출력될 것 같은데 첫번째 if문과 두 번째 if문을 모두 통과했다.
String 클래스도 기본적으로 ==가 아닌 equals() 메소드를 사용해서 비교를 해야만 한다. 하지만 이렇게 결과가 나오는 이유는 자바에 Constant Pool
이라는 것이 존재하기 때문이다. 이 풀에 대해서 간단하게 이야기하면, 자바에서는 객체들을 재사용하기 위해서 Constant Pool이 만들어져 있고, String의 경우 동일한 값을 갖는 객체가 있으면, 이미 만든 객체들을 재사용한다. 따라서, text와 text2는 실제로는 같은 객체이다.
이 첫 번째 연산 결과가 우리가 원하는 대로 나오도록 하려면, text2의 객체의 생성을 다음과 같이 다른 방식으로 하면 된다. text2 생성 부분을 아래와 같이 변경하자.
//String text2 = "Check value";
String text2 = new String("Check value");
이렇게 String 객체를 생성하면 값이 같은 String 객체를 생성한다고 하더라도 Constant Pool의 값을 재활용하지 않고 별도의 객체를 생성한다. 따라서 이와 같이 변경한 후에 이 메소드를 변경해보면 다음과 같이 값이 출력된 것을 확인할 수 있다.
String은 immutable한 객체다. immutable이라는 말은 사전적인 의미로 "불변의"라는 의미이다. 다시 말해서 한 번 만들어지면 그 값을 바꿀 수 없다. 만약 String 문자열을 더하면 새로운 String 객체가 생성되고, 기존 객체는 버려진다. 그러므로, 계속 하나의 String을 만들어 계속 더하는 작업을 한다면 계속 쓰레기를 만들게된다.
String text="Hello";
text=text+" world";
이 경우, "Hello"라는 단어를 갖고 있는 객체는 더 이상 사용할 수 없다. 즉, 쓰레기가 되며 나중에 GC(Garbage Collector)의 대상이 된다.
이러한 String 클래스의 단점을 보완하기 위해서 나온 클래스가 StringBuffer
와 StringBuilder
다. 두 클래스에서 제공하는 메소드는 동일하다. 하지만, StringBuffer는 Thread safe하다고 하며, StringBuilder는 Thread safe 하지 않다고 한다.
StringBuffer와 StringBuilder 클래스는 문자열을 더하더라도 새로운 객체를 생성하지 않는다. 그렇다고 더하기(+) 기호를 사용하여 더할 수 있다는 말이 아니다. 이 두 개의 클래스에서 가장 많이 사용하는 메소드는 append()
라는 메소드다. append() 메소드는 매개 변수로 모든 기본 자료형과 참조 자료형을 모두 포함한다. 따라서, 어떤 값이더라도 이 메소드의 매개 변수로 들어갈 수 있다.
보통 다음과 같이 사용한다.
StringBuilder sb=new StringBuilder();
sb.append("Hello");
sb.append(" world");
StringBuilder sb=new StringBuilder();
sb.append("Hello").append(" world");
세미콜론이 나오기 전에 계속 append() 메소드를 붙여도 상관 없다. 왜나하면, append() 메소드를 수행한 후에는 해당 StringBuilder 객체가 리턴되므로, 그 객체에 계속 붙이는 작업을 해도 무방한 것이다.
추가로, JDK 5 이상에서는 여러분이 String의 더하기 연산을 할 경우, 컴파일 할 때 자동으로 해당 연산을 StringBuilder로 변환해 준다. 따라서, 일일이 더하는 작업을 변환해 줄 필요는 없으나, for 루프와 같이 반복 연산을 할 때에는 자동으로 변환을 해주지 않으므로, 꼭 필요하다.
마지막으로 String과 StringBuilder, StringBuffer 클래스의 공통점에 대해서 알아보자. 공통점이라면, 모두 문자열을 다룬다는 점이다. 그런데, 또 다른 공통점은 CharSequence 인터페이스를 구현했다는 점이다. 따라서, 여러분들이 이 세 가지 중 하나의 클래스를 사용하여 매개 변수로 받는 작업을 할 때 String이나 StringBuilder 타입으로 받는 것보다는 CharSequence 타입으로 받는 것이 좋다.
그러면 언제 StringBuilder를 사용하고, 언제 StringBuffer 클래스를 사용해야 할까? 일반적으로 하나의 메소드 내에서 문자열을 생성하여 더할 경우에 StringBuilder를 사용해도 전혀 상관 없다. 그런데, 어떤 클래스에서 문자열을 생성해서 더하기 위한 문자열을 처리하기 위한 인스턴스 변수가 선언되었고, 여러 쓰레드에서 이 변수를 동시에 접근하는 일이 있을 경우에는 반드시 StringBuffer를 사용해야 한다.
참고