- 작성자 : 01 남상협
- 찬조 : 99 류상민
이 문서를 작성하게된 계기 ¶
채팅 UI를 짜려고 여러가지를 하다가 대화명을 입력하였을 경우에 그 대화명을 저장하려고 String 형태의 대화명을 전달인자로 사용하려고 하였는데 되지 않았다. 그래서 MSN을 통해서 상민이 형에게 그에 대해서 물어보았다. 상민이형이 MSN으로 몇십분에 걸쳐서 알려 주었다.(감사~) 이 문서에 나와 있는 내용에 대해서 아시는 분들도 있겠지만, 저와 같이 잘 모르는 분도 또한 있을거 같기에 도움이 되기를 바라면서 상민이 형이 알려준 내용을 간추려 보았다.
구체적인 내용 ¶
~cpp Java 에서는 new 와 delete 가 없지만 그 대안으로 참조형을 이용한다. 참조형은 C++에서 int &a와 같이 by-value가 아닌 by-reference로 값을 이용할 수 있는 형을 말한다. 자바는 기본 자료형과 참조 자료형으로 크게 분류되며 기본 자료형은 byte, short, int, long, double, char, boolean 참조형은 Class, Array, interface (예외 String은 기본 자료형으로 취급한다. String은 기본 자료형만큼 자주 쓰기 때문에 클래스 임에도 불구하고 기본자료형으로 쓰인다.) 기본 자료형은 스칼라(scalar) 형이다. 참조형은 백터(vector) 형. 간단히 비유하면 스칼라는 값, 백터는 화살표. 벡터는 call by-reference로 전달된다. 이런 reference자료형은 Class, 배열(Array) interface이며 call by-reference로 메소드나 전달인자로 넘어 간다. # 참고로 함수라는 말은 자바에서는 맞지 않는다. 함수는 C에서만 존재 하는것이며 자바나 기타 OOP언어에서는 메소드라는 표현이 적절하다. 메소드는 한 객체에 종속된 기능이라는 부가적 의미를 가지고 있기 때문이다. Class A { public int a = 1; public void setA( int A ) { a = A; } } ... A _a; A _A _a.setA(3); 하면 될까? 안된다.(관련 내용은 제본책 3-3에 나와 있음) 안되는 이유는 아까 언급한 바와 같이 클래스는 vector값이기 때문이다. A _a; 에서 _a는 vector 값이다. 이 값은 한국말로 쉽게 표현하자면 방향값,화살표 이다. 그렇다면 현제 방향값인 _a는 무엇을 가리키고 있을까? 대답은 "현재는 아무것도 가리키고 있지 않다." 이다. Java에서는 vector를 초기화 시켜 주기때문에, 객체가 없이 그냥 저렇게만 입력하면 null을 가리킨다. 그래서 위와 같은 경우 _a.setA(3); 을 호출하는 경우에는 NullPointerException이라면서 에러 객체를 발생시킨다. 그래서 A _a = new A(); //vector값 _a에게 가리킬 객체를 부여 이와같은 구문을 넣어서, 객체를 생성하고, _a에게 가리키게 하여야만 한다. 이와 대조적으로 스칼라(scalar) 값의 예를 들면 int a; a = 1; 이건 성립한다. 이유는 int는 기본 자료형으로서 스칼라 값이기 때문이다. 스칼라(scalar) 역시 한국말로 표현하면, 양값(?) 이라고 해야하나, 방향성이 없는 그냥 양을 가리키는 용어이다. 이같은 스칼라 값들은 절대로 메소드에 reference형태의 전달인자로 넘겨줄 수 없다. 이것은 자바의 설계 이념이다. 자바에서는 스칼라 값 즉 기본 자료형은 복사로(call by-value) 전달되고, return 값으로 해당 결과를 객체로 받는다. return 값이 스칼라 값이라면 어쩔 수 없다. 해당 설계이념은 Java Design Pattern 에 잘 나와 있다. 그리고 위에서 살포시 언급했던 String형은 기본자료형과 비슷하게 스칼라형으로 취급하기 때문에 call by-reference로 못넘긴다. 그래서 final로 선언할 수 있다. (final이란 그냥 #define이라고 생각해도 무방하다. Java 컴파일러가 해당 final들을 실제 값으로 1:1 바꾸어 버리는 작업을 해버린다.) 위에서 언급했지만 다시 말하자면 String이 스칼라 취급을 받는 이유는 다음과 같다. Java이전에 태어난 상업용 언어들은 대다수 char까지를 하나의 기본 자료형으로 많이 차용했고 많은 언어에서 string형도 기본자료로 쓸려는 노력을 많이 해두었다. (이유는 많이 쓰이기 때문이다.) 인터넷이 보급되면서 java 설계자들은 String도 기본자료형 취급을 해도 현재의 시스템들이 따라가 줄것이라 예상해서 그렇게 설계했다. # 참고 : 기본 자료형들은 시스템내에서 마구 복사된다. 그리고 만약 200KB 의 스트링 형에게 나중에 2byte 만을 할당하는 다음의 경우에도 String a = 200KB 자료 a = "a";(일단 개념적으로 이렇게 하겠음) 이렇게 되면 기본 자료형으로 취급 받는 String은 통째로 200KB를 갈아 버린다. 문제는 200KB의 사소한 용향이 아닌 그게 2메가 짜리의 문서의 경우는 문제가 된다. 여기서의 의미는, String이 imutable하게 취급 받기 때문에, 해당 객체의 저장소가 완전 초기화 되고 새로 할당 받는다는 의미이다. 물론 초기화는 Garbage collector가 해주기 때문에, 차후 메모리가 부족할때 파괴 되어 진다. 이게 심각한 이유는, 기존 저장소를 그냥 유지한체로, String의 길이만 1로 하고, a[0]에 a문자열을 집어 넣은 이후, 그대로 쓰면 되는데, String 객체는 새로 공간을 할당 받는다는 의미이다. 그래서 mutable한 String처리를 위해서 Java 1.2에서 등장한것이 StringBuffer 이고 이것은 vector값으로 취급 받는다. 흔이 이 문제를 String의 mutable문제 라고 불리며 관련 자료에서 두 단어가 자주 등장한다. string is imutable. Stringbuffer is mutable String은 한번 자료가 들어가면 바뀌지 않아서 주로 바뀌고 확장되는 문자열의자료의 경우 StringBuffer 를 사용하는 걸 권장한다. mutable한 객체의 구현을 위해 StringBuffer의 메소드를 보면, 일정 단위의 char저장 장소를 지정하여 그 내부에서 문자열을 교체할수 있고, 그 저장 장소보다 더 큰 문자열이 입력이 된다면, 해당 문자열 길이의 2배의 공간을 확보해 초기화 한다..