728x90

 

Q > 예를 들어 int[] a = new int[5]가 있으면 이 배열도 객체라는데 무슨말인지 잘 모르겠습니다.

    int라는 이름의 클래스가 있다는 말과 동일하나요? Integer Wrapper 클래스와 연관성은 없는 것 인가요? 알기 쉽게 설명해주세요.

 

 

A >

배열을 객체라고 부른다. 그 이유가 무엇일까? 보통 객체를 생성한다라고하면 클래스의 객체를 많이 떠올린다. 그렇다고 클래스부터 설명을 할 수는 없는 노릇이다. 클래스에 대해서는 안다고 가정하고 클래스와 객체와의 관계에 대해 생각해보자.

 

클래스는 자료형이다. 이 사실을 잊어선 안된다. 왜냐면 자료형은 그 자료가 가진 형태를 나타내는 것이기 때문에 스스로는 사용될 수 없다. 누군가가 그 형태를 가지는 실체를 만들어 내야만 사용할 수 있다. 이런 관점에서 배열과 배열 객체를 바라보자. 배열도 동일한 자료형의 값을 담을 수 있는 공간이다. 그렇기 때문에 int[] a; 라고한다면, a라는 변수는 이제부터 int라는 자료형의 값을 담을 수 있어. 딱 여기까지다. 그 이상도 이하도 아니다. '담을 수 있다'는 것과 '사용할 수 있다'는 다르다. (전달이 잘 되고 있는지 모르겠다.)

 

728x90

 

int[] a; 는 어떤 의미에서 추상적인 표현이다. int라는 자료형의 값을 여러개 담을 수 있는 것. 더 나아가 이것을 실체화 시켜야 사용 가능하다는 것이다. 바로 그 실체화 하는 코드가 new int[5] 인 것이다. (다형성에 대해서 알고 있으면 더 좋을 것 같다.) 이 new int[5]라는 코드 덕분에 a는 배열 객체가 되는 것이다. 그 이전에는 그저 int[] 타입의 변수 a를 정의했는데 아직 객체가 할당되지 않은 상태인 것이다.

 

 

그리고 다른 관점에서 한번 더 생각해보자. 배열은 다른 리터럴 값들과 달리, '배열은 어떠한 값이다.'라고 정의할 수 없다. 즉, new라는 연산자를 통해 heap 메모리 영역에 생성된 공간을 참조하는 주소값을 가지고 있기 때문이다. a는 배열에 할당된 값의 주소를 가리키고 있지 배열의 값을 가리키고 있지 않다는 얘기이다. 그렇기 때문에 이 배열도 객체라고 한다.

 

 

 

int라는 이름의 클래스가 있다는 말과 동일하다는 얘기는 클래스도 결국 자료형임을 알고 있는 것 같다. 자료형의 관점에서 int[] 타입의 클래스 라고도 볼 수 있다고 생각한다. 하지만 그렇게는 잘 얘기하지 않는다. 흔히 primitive 타입이라고 부르는 원시타입에 대해서 자료형이라고 하지 클래스라고는 잘 하지 않기 때문이다.

 

배열 객체의 얘기를 함에 있어서 Integer Wrapper 클래스와는 관련성이 부족한것 같다. Integer는 primitive 타입인 int의 reference타입으로, 흔히 8대 자료형이라 부르는 primitive 타입들의 reference 타입의 클래스를 Wrapper 클래스라고 하기 때문이다. 이런 연관성을 생각한 이유는, 내 생각에, 배열 객체 -> 객체 -> 클래스 -> int -> primitive type -> Wrapper class 이런 흐름이었지 않나 생각한다. Wrapper class는 primitive type을 클래스화 한것이다.

 

 

 

 

728x90
728x90

 

나는 개인적으로 클래스와 객체를 설명할 때 붕어빵 틀을 비유하는걸 싫어한다.

마음에 들지 않는다. 내가 배울 당시 이렇게 배우지 않았을 뿐만 아니라 개인적으로 잘 와닿지도 않았다.

그래서 내가 배운 방법으로 클래스란 무엇이며 이 클래스와 객체와의 관계를 어떻게 이해하면 좋은지 정리해보려 한다.

 

클래스는 우리가 일상 생활속에서 볼 수 있는 모든 것들을 표현할 수 있는 도구라고 생각하는 것도 좋은 발상이다.

클래스를 구성하고 있는 큰 두가지 개념이 있다. 하나는 멤버필드라는 개념이며 다른 하나는 멤버 메서드라는 개념이다.

 

멤버 필드란, 그 클래스가 표현하고자 하는 대상이 가지는 속성들을 의미한다. 높이, 색상, 속도, 속력, 방향, 무게 등 일반적인 사물들이 가질 수 있는 모든 속성들을 말한다.

멤버 메서드란, 그 클래스가 표현하고자 하는 대상이 할 수 있는 어떤 동작, 행위들을 의미한다. 클래스가 사람을 표현하고 싶다면, 앞으로 걷기, 뒤로 걷기, 밥먹기 등이 될 수 있다. 강아지라면 밥먹기, 짖기, 뛰기, 재롱부리기 등이 해당한다.

 

실제로 사람은 훨씬 복잡하지만 클래스로 사람을 표현한 예시이다.

 

class Person {
    private String gender;
    private int tall;
    private double weight;
    private double footSize;

    public void walk() { }
    public void eat() { }
}

 

이 클래스에서 정의하고 있는 사람이라는 것은, 성별, 키, 몸무게, 발 사이즈를 알 수 있으며, 걷거나 먹는 행위를 할 수 있다.

앞서 말했듯 이정도로 사람을 표현하기엔 턱없이 부족하지만 간단한 예시를 들자면 이렇다는 것이다.

하지만 이렇게 정의했다고 해서 바로 사용하고 있는것은 아니다. 이건 마치 설계도면과도 같은 것이다.

스스로는 할 수 있는게 아무것도 없기 때문이다.

김춘수 시인의 꽃이라는 시에서 처럼

내가 클래스의 객체를 만들어 주기 전에는 클래스는 다만 하나의 설계 도면에 지나지 않는다.

 

클래스의 개념에 대해 찾아본다면 기본적인 자바 프로그램을 만들어 보면서 알게 되었을 것이다.

모든 자바 프로그램은 main 메서드에서 시작한다고.

이 main 메서드 안에서 클래스의 객체를 만들어주어야 비로소 나에게 사용할 수 있는 객체로서의 의미를 가지게 된다.

 

 

728x90

 

 

자꾸 객체 객체 하는데, 그래서 객체가 뭔지 답답할지 모르겠다.

다음 예시를 보기 전에 클래스와 객체의 관계에 대해서 알아보자.

 

우리가 많이 사용하는 스마트폰. 이건 클래스다. 하지만 내가 손에 들고 있는 스마트폰은 클래스가 아니다. 객체다.

컴퓨터를 하기 위해서 지금 내가 손으로 쥐고있는 마우스는 객체다. 하지만 마우스는 객체가 아니가. 클래스다.

지금 책상위에 놓여있는 달력은 객체다. 하지만 달력은 객체가 아니다. 클래스다.

'머릿속에 손목 시계를 떠올려보세요' 해서 떠오르는 일반적으로 알고있는 손목시계는 클래스다. 하지만 지금 손목에 차고 있는 이 시계는 객체다.

 

무슨 말장난이냐 싶을지 모르겠지만. 위에서 말한 그대로다.

클래스란 이렇게 우리가 특정 사물에 대해서 일반적으로 떠올릴수 있는 개념적인 것이라면, 객체는 이것이 실제 눈앞에 형태를 갖추고 있는 것 그 자체이다. 즉, 클래스는 '이 사물은 이렇게 생겼고 어떤어떤 기능을 가지고 있어요'라면 객체는 클래스가 설명하고 있는 것을 토대로 만든 것이라고 할 수 있겠다. 그래서 마우스는 클래스지만 지금 내 손 안에 들어와 있는 눈에 보이는 이 마우스는 클래스가 아니고 객체라는 것이다.

 

 

 

위에 작성한 Person 클래스를 사용하는 main 메서드를 작성해 보자.

 

public class ClassTest {
    public static void main(String[] ar) {
        Person p1 = new Person();
        Person p2;
        p2 = new Person();
    }
}

 

ClassTest라는 이름의 클래스는 main 메서드를 담고 있다.

3라인과 4-5라인이 의미하는 바는 똑같다.

하지만 굳이 4라인과 5라인으로 나눈데는 이유가 있다.

3라인의 의미는, p1변수는 Person클래스에서 정의한 형태를 가지는 객체를 담을 변수야. 그리고 난 이 변수에 Person 객체를 담았어. 라는 말이다.

4라인의 의미는, p2변수는 Person클래스에서 정의한 형태를 가지는 객체를 담을 공간이야. 라는 말이다.

5라인의 의미는, Person객체를 하나 만들었고, 나는 이 형태를 가지는 변수 p2에 담았어. 라는 말이다.

 

건축물에 비유하자면 단순히 클래스를 만들기만 해서는, 객체화를 하지 않는다면, 그저 설계도만 만들고 건물은 올리지 않은것이 된다.

하지만 설계도만 가지고 있다면 수십 수백 수천개라도 객체를 만들어낼 수 있다. 너무나 당연하게도. 그렇기 때문에 자바는 재사용성이 뛰어난 언어라는 얘기와도 일맥상통한다.

 

이번에는 클래스와 객체의 관계에 대해서 다루었기 때문에 이정도만 정리해두려 한다.

다음에는 자바의 특징중에 하나인 다형성에 대해 정리하면서 재사용성에 대해서 자세히 정리 해둬야 겠다.

 

 

 

 

728x90
728x90

 

자바에는 문자열을 처리하기 위한 클래스로 String, StringBuilder, StringBuffer 클래스가 있다.

단순히 문자열을 처리하기 위함이라면 (예를 들면 System.out.println("문자열");  이런 경우) 어떤 것을 사용해도 별다른 차이는 없다고 알고 있다. 하지만 문자열을 더하는 (+) 연산을 할 경우에 퍼포먼스상의 차이가 발생한다.

 

백번 듣느니 한 번 보는게 낫다.

실제로 아래와 같은 예제는 많은 곳에서 흔히 볼 수 있는 예제일 것이다.

 

package xxxelppa.tistory.com;

public class StringTest {
    public static void main(String[] ar) {
        long StartTime = 0;
        long EndTime = 0;
        
        String str;
        StringBuilder strBdr;
        StringBuffer strBfr;
        
        for(int k = 0; k < 9; ++k) {
            str = new String("문자열");
            strBdr = new StringBuilder("문자열");
            strBfr = new StringBuffer("문자열");
            
            System.out.println("============== " + (k + 1) + "번째 비교 결과" + " ==============");
            
            StartTime = System.nanoTime();
            for(int i = 0; i < 10000; ++i) {
                str += i;
            }
            EndTime = System.nanoTime();
            System.out.println("String의 실행 시간\t\t: " + (EndTime - StartTime));
            
            StartTime = System.nanoTime();
            for(int i = 0; i < 10000; ++i) {
                strBdr.append(i);
            }
            EndTime = System.nanoTime();
            System.out.println("StringBuilder의 실행 시간\t: " + (EndTime - StartTime));
            
            StartTime = System.nanoTime();
            for(int i = 0; i < 10000; ++i) {
                strBfr.append(i);
            }
            EndTime = System.nanoTime();
            System.out.println("StringBuffer의 실행 시간\t: " + (EndTime - StartTime));
            System.out.println("=============================================");
            System.out.println();
            
        }
        
        
    }
}

 

위 예제는 똑같이 문자열을 더하는 연산을 했을 때 실행 속도를 비교하는 소스이다.

실행 결과는 다음과 같다.

 

============== 1번째 비교 결과 ==============
String의 실행 시간             : 192313252
StringBuilder의 실행 시간    : 417904
StringBuffer의 실행 시간     : 613102
=======================================

============== 2번째 비교 결과 ==============
String의 실행 시간             : 165631465
StringBuilder의 실행 시간    : 427854
StringBuffer의 실행 시간     : 460046
=======================================

============== 3번째 비교 결과 ==============
String의 실행 시간             : 178263707
StringBuilder의 실행 시간    : 276554
StringBuffer의 실행 시간     : 340644
=======================================

============== 4번째 비교 결과 ==============
String의 실행 시간             : 184807363
StringBuilder의 실행 시간    : 371959
StringBuffer의 실행 시간     : 376934
=======================================

============== 5번째 비교 결과 ==============
String의 실행 시간             : 178070851
StringBuilder의 실행 시간    : 436048
StringBuffer의 실행 시간     : 479068
=======================================

============== 6번째 비교 결과 ==============
String의 실행 시간             : 133046927
StringBuilder의 실행 시간    : 268945
StringBuffer의 실행 시간     : 361423
=======================================

============== 7번째 비교 결과 ==============
String의 실행 시간             : 153004492
StringBuilder의 실행 시간    : 210708
StringBuffer의 실행 시간     : 355277
=======================================

============== 8번째 비교 결과 ==============
String의 실행 시간             : 137168318
StringBuilder의 실행 시간    : 289139
StringBuffer의 실행 시간     : 418782
=======================================

============== 9번째 비교 결과 ==============
String의 실행 시간             : 136230374
StringBuilder의 실행 시간    : 309039
StringBuffer의 실행 시간     : 373129
=======================================

 

728x90

 

 

실행 시간 결과는 String > StringBuffer > StringBuilder 순서이다.

그렇다면 왜 이런 결과가 나왔을까?

 

String은 문자열을 더하기 위해 String 공간을 하나 더 만드는 작업을 한다.

이게 무슨 소리일까? String이라는 클래스가 가지는 특성이라고 받아들일 수 밖에 없다.

String 클래스형 자료형으로 선언된 문자열이 메모리상에 할당이 되면, 이 값을 바꿀 수 없는 값이 된다.

만약 이 문자열이 더해지거나 빼는 연산을 하게 될 경우 기존에 할당한 메모리에 저장된 값이 바뀌지 않는다는 소리다.

 

String addr100 = new String("문자열A");
String addr101 = new String("문자열B");

addr100 = addr100 + addr101;

 

이 소스가 실행되면 메모리상에서 어떤 일이 생길까?

 

 

위에 첨부한 이미지를 함께 보자.

만약 메모리상에 위처럼 문자열이 저장 되어있다고 했을 때, 100번지의 "문자열A"와 101번지의 "문자열B"를 더해 새로운 문자열 "문자열A문자열B"를 만든 경우이다.

addr100 변수는 100번지를 바라보고 있다가 새로운 102번지를 바라보게 된다. (바라본다 보다 참조한다는 말이 더 옳다)

그럼 100번지는?

가비지 컬렉터가 나중에 알아서 처리해주니 신경쓰지 말자.

 

String 클래스의 경우 기존 값에 새로운 값을 더하는 것이 아닌, 위와 같이 추가 연산이 필요하기 때문에 StringBuilder나 StringBuffer보다 퍼포먼스가 떨어진다.

그렇기 때문에 문자열 연산에서는 StringBuilder나 StringBuffer 클래스의 사용을 권장한다.

 

(내용이 너무 길어질 것 같아서 추가하지 않으려 했지만, 급하면 이 부분은 넘어가도 좋다.)

지금까지 문자열을 더하는 연산이 빈번하게 발생한 부분은 배치 프로그램에서 쿼리를 작성할 때였다.

다음과 같은 쿼리가 있다고 하자. (다소 과장된 부분이 있다.)

 

SELECT
    AAA
    , BBB
    , CCC
    , DDD
    , EEE
FROM TEST
WHERE
    1=1
    AND AAA > 100
    AND BBB > 200
    AND CCC > 300
    AND DDD > 400

 

이 때 이 쿼리문을 다음과 같이 변수에 담을 수 있다.

 

String query = "";

query += "SELECT           ";
query += "    AAA          ";
query += "    , BBB        ";
query += "    , CCC        ";
query += "    , DDD        ";
query += "    , EEE        ";
query += "FROM TEST        ";
query += "WHERE            ";
query += "    1=1          ";
query += "    AND AAA > 100";
query += "    AND BBB > 200";
query += "    AND CCC > 300";
query += "    AND DDD > 400";

 

단순히 더하는게 아니라고 생각해보면 이게 얼마나 재앙인지 이제는 알게 되었으리라 생각한다.

(위와 같은 경우 반드시 StrinfBuilder 클래스나 StringBuffer 클래스를 사용하기를..)

 

 

 

그럼 마지막으로, String과 StringBuilder, StringBuffer의 차이는 알겠는데 StringBuilder와 StringBuffer의 차이는 무엇일까?

StringBuilder와 StringBuffer 클래스는 사실 하는 일은 똑같다. 다만 하나의 차이가 있는데 동기화 처리의 문제이다.

 

StringBuffer클래스는 동기화 (Synchronized)를 지원하며 멀티 스레드 환경에서도 동기화를 지원한다. 그렇기 때문에 단일 스레드일 경우 StringBuilder 클래스를, 멀티 스레드일 경우 StringBuffer 클래스의 사용이 권장된다. (StringBuffer 클래스의 경우 혼용해도 상관없지만, 동기화 처리 문제로 퍼포먼스상의 이슈가 있다고 한다.)

실제로 맨 위에 예제로 만든 소스의 실행 결과를 보면 단일 스레드 환경에서 StringBuilder 클래스가 StringBuffer클래스보다 퍼포먼스가 좋은 것을 확인할 수 있다.

 

동기화라는 개념은 어려운게 아니다.

마치 한칸짜리 공중 화장실이라고 생각하면 될 것 같다.

누구나 사용할 수 있지만, 동시에 사용할 수 없도록 하는 것이 동기화이다.

 

 

 

흔히 찾아볼 수 있는 예제이지만, 보다 정확하게 확인하고 싶어서 주소값을 직접 출력 해보고 싶었는데 그렇게 하지 못해 아쉬움이 남는다.

 

 

 

 

728x90

+ Recent posts