728x90

이 강의는 자바의 프로젝트를 어떻게 만드는지, 또한 빌드를 어떻게 하는지에 대한 강의를 진행하지 않는다.

그러나 자바의 기본적인, 그리고 자바에 필수적인 기능들도 분명 존재하고 이 블로그엔 그 작업에 필요한 포스팅도 함께 제공하고 있다.

그 정보를 확인하고 싶다면 여기를 참조하라. 양이 조금 되고 현재진행형으로 늘어나고 있으므로 페이지내의 찾기(ctrl+f 나 cmd+f)로 찾아보도록하자.


java.lang패키지의 중요한 부분인 Object와  Wrapper클래스의 설명을 마쳤다.

아직도 중요한 부분들이 있지만 나머지는 다음 기회에 설명하도록하자.

마지막으로 설명드릴것은 CharSequence이다.

사실 CharSequence는 interface로서 그 자체로는 아무 의미가 없다.

단 문자의 나열인 CharSequence는 말그대로 문자의 나열이므로 결국에는 String을 다루게된다.

사실 이 부분을 설명할까 말까 조금 망설였다.

그 이유는 실제로는 몰라도 큰 문제가 없기 때문이다.

필자는 혼동을 줄바에야 모르는게 낫지 않냐고 생각이 들기 때문이다.

그러나 설명을 하기로 결심하게된 계기는 최적화를 위해서이다.

그러니까 엄청 자세한걸 안다는 마음으로 접근하기 보다는 그냥 이런것도 있구나 하고 접근하길 바란다.


현존하는 CharSequence를 상속받은 클래스들은 총 5가지로 그것은 아래와 같다.


CharBuffer, Segment, String, StringBuffer, StringBuilder


CharSequence는 말그대로 문자의 나열이라고 했다.

즉 위의 5클래스는 문자의 나열을 지원하고 관리하는 클래스들이다.

사용의도는 저마다의 차이가 있다.

CharBuffer는 사실 문자열을 다루려는 의도보다는 문자를 저장하기 위해서 사용한다. 말그대로 Buffer인 셈이다.

Segment는 Swing에서 다루는 문자를 쓸때 사용한다고 알고 있다. 이 역시 문자단위로 사용한다.

따라서 여기서는 CharBuffer와 Segment를 다루지 않겠다.

사실 크게 다룰 필요도 없다. 둘다 사용하는 일이 드물 것이다.


그럼 이제 String과 StringBuffer,StringBuilder 3가지가 존재한다.

다실 StringBuffer와 StringBuilder의 기능은 똑같다.

StringBuffer는 기능은 조금 떨어지지만 쓰레드에서 안전하고

StringBuilder는 기능은 조금 낫지만 쓰레드에서 불안정하다.

따라서 둘은 같은 솔루션이라고 생각하고 접근해도 무방하다는 것이다.

그러므로 여기서는 String과 StringBuffer에 대해서만 논하도록 하겠다.


여러분은 이 때까지 String을 문자열을 처리하기 위해서 써왔다.

그리고 String은 이미 그 마저로도 충분히 매력적인 클래스이다.

단 경우에 따라서는 StringBuffer가 더 매력적일 수 있다.

그러한 예제를 아래의 상황에서 보도록 하자.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
String str = "동해물과 백두산이";
String str2 = str;
System.out.println(str==str2);
str += " 마르고 닳도록";
System.out.println(str==str2);
}
}

이 코드를 실행해보자.

어떠한 결과가 나올까?

일단 str2는 str과 같은 값을 가르키기에 첫번째 str==str2은 true가 나올것이다.

그럼 두번째는? str과 str2는 과연 같은 객체를 가르키고 있을까?


결과는 false가 된다. 아니 객체를 언제 가르키는것이 바뀐것일까?

타이밍은 단한번 +를 했을때 밖에 없다.

여러분은 말이 안된다고 생각할 수 있다.

왜냐하면 새로운 객체를 생성한 것이 아니라고 생각할테니까.

그러나 여러의 생각은 틀렸다.

위의 코드는 정확하게 아래처럼 돌아간다.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
String str = "동해물과 백두산이";
String str2 = str;
System.out.println(str == str2);
str = new String(str + " 마르고 닳도록");
System.out.println(str == str2);
}

사실 위코드와 아래코드의 동작원리는 동일하다.

그 이유는 String은 사실 값을 변경할 수 없는 불변 값이기 때문이다.

아니 그럼 이때까지 +하거나 문자열을 변경하거나 그런것들은 어떻게 했던 것일까?

사실 그때마다 객체를 새로생성해서 만들었었다.

즉 +연산을 사용하건 replace를 사용하건 모두 그때그때 String을 새로 할당해서 사용했던 것이다.


뭔가 비효율 적인것 같다... 그러나 뭐 문제없으니까 장땡 아닌가? 라고 생각할 수 있을 거 같다.

뭐 맞는말일수도 있다. 효율이 그리 중시되지 않는다면말이다.

그러나 만약 입출력이 빈번하게 일어난다면 이러한 방식은 프로그램에 심각한 부하를 줄 수있다.

그러면 불변 문자열을 다루는게 아니라 가변 문자열을 다룰 수 있는 방법은 없을까?

그래서 존재하는것이 StringBuffer이다.

위의 예제를 아래와 같이 바꿔보자.


package com.jiharu.main;

public class Main {

public static void main(String[] args) {
StringBuffer str = new StringBuffer("동해물과 백두산이");
StringBuffer str2 = str;
System.out.println(str == str2);
str.append(" 마르고 닳도록");
System.out.println(str == str2);
}
}

StringBuffer는 String클래스에게만 주어지는 특권인 +연산으로 문자열을 붙히는것을 못한다.

따라서 append클래스를 사용해야한다.

이 경우 StringBuffer의 결과는 당연히 동해물과 백두산이 마르고 닳도록이 될것이다.

이번에는 str과 str2가 동등할까?

실행결과를 확인하여 보자.



이번에는 둘이 동등한것을 확인할 수 있다.

String은 태생적 한계상 반복작업이 심하게 문자열을 바꿀경우에는 비효율 적일 수 밖에 없다.

따라서 문자열의 값이 계속해서 가변해야한다면 String의 선택은 옳지 못하다.

따라서 StringBuffer를(혹은 StringBuilder) 선택해야한다.


+ Recent posts