2011년 5월 3일 화요일

자바에서 클래스인 객체 자신을 지칭하는 명령어(this)

자바에서 쓰이는 명령어 중에 this 라는 키워드가 있다. 처음보는 명령어일수도 있고 자바 같은 프로그래밍을 조금 해봤다면 익숙한 단어일수도 있을 것이다. 자바소스를 보면 심심치 않게 보는게 this인데 이 단어가 자바에서 하는 역활이 무엇인지 명확하게 알지 못하면 뭐가뭔지 헤메일수 밖에 없다. 지금 필자가 담배 얘기를 하는게 아니다.-;


자바에서 this는 객체 자기 자신을 부르는 명령어인데 예를 들어 프로그램의 메소드를 만들고 있는데 지금 만든 그 메소드 안에서 같은 이름의 메소드를 불러서 한번더 실행해야할 일이 있다고 하자. 그럼 어떻게 하겠는가? 혹시 이런 이가 있을지도 모르겠다. 그냥 메소드 이름 안에다가 다시 써서 쓰면 되지 않느냐? 똑똑하다.* 그런데 왜 그렇게 쓰질 않을까라는 질문이 들것이다. 쓸수 없는건 아니다. 하지만 같은 이름의 그것도 같은 메소드 형태가 같은 공간에 있으니 코드를 볼때마다 의미파악이 모호하고 헤깔릴 것이다. 한마디로 구별하기 쉽게 하려고 this를 쓰는 것인데 안타깝게도 원래의 의도와는 다르게 많은 이들이 이것 때문에 고생 아닌 고생(?)을 하고 있다.

일단 this를 어떻게 사용할수 있으며 어떤 방식으로 쓰이는지 알아보자.(this 대신에 클래스 이름이 들어간다고 생각하면 이해가 쉬울 것이다.)

this.변수;                       //자기 자신의 변수를 호출한다.
this( );                            //자기 자신의 생성자를 호출한다.
this(매개변수);              //자기 자신의 생성자(입력값)를 호출한다.
this.메소드( );                //자기 자신의 메소드를 호출한다.
this.메소드(매개변수);  //자기 자신의 메소드(입력값)를 호출한다.

클래스 자기자신의 객체를 부르는 this 라는 명령어 형태를 위의 5가지 형식으로 나눌수 있는데 지켜야할 규칙은 static 메소드나 (항상 static인)메인메소드 내에서는 쓰지 못하고 생성자를 호출시 생성자안에서 가장 첫줄에다가 써야된다. 생성자는 가장 먼저 실행되어야하는 부분이므로 다른 혼선을 방지하기 위해서 this도 그와같은 맥락으로 바로 처리되야한다. 자바에서 static은 객체 생성 이전, 메모리에 관련된 메소드를 메모리에 로딩하므로 자기 자신의 객체를 이용해야만 하는 this를 쓰지 못하는 것은 당연한 이치다. 그냥 예제로 한큐에 this 에 대해서 끝장내 보도록 하자. 백문이 불여일견(?)인지라 그냥 예제를 보다보면 이럴때 쓰는구나하고 저절로 터득이 될 것이다.


5 in Test39
10 in ex
나는 매개변수 a가 있는 ex 메소드
나는 인자가 없는 ex 메소드
나는 매개변수 a가 있는 Test39 생성자
나는 인자가 없는 Test39 기본 생성자
10 in 메인메소드

예제를 실행하면 위의 결과값을 얻을수 있을 것이다. 여러분의 이해를 돕기 위해 프로그램이 어떤 식으로 작동되는지 코드를 보면서 살펴보기로 하자. 당연하지만 자바로 프로그램을 돌리면 메인메소드에서 먼저 시작한다. 클래스 Test39의 객체 생성을 통해서 인스턴스 x를 만들었다. 여기서 저번시간에 배운 생성자가 등장한다. 객체 생성을 시키면 Test39 생성자를 찾는다. 매개변수가 없는 객체 생성을 시켰으니 Test39( ) 형태의 기본 생성자를 찾으러 간다. 이 예제에서는 생성자가 두개다. 하나는 인자가 없는 기본 생성자랑 하나는 int 타입의 인자가 있는 생성자다. 만약 기본 생성자가 없고 Test39(int a)라는 생성자만 있는 상태로 프로그램을 돌렸다면 에러가 난다. 자바에서는 생성자가 하나라도 있으면 기본 생성자를 자동으로 만들고 처리하지 않는다. 따라서 메인메소드에 있는 객체 생성시 ( )안에 int 타입의 인자가 없으니 당근 에러다. 복습하는건데 이해되겠지? ^^ 까먹었으면 저번 시간꺼 복습하기 바란다.ㅎㅎ

다시 프로그램으로 돌아와서 기본 생성자를 찾고 안의 내용을 실행하는데 처음에 this(5);가 나온다. 아까 언급했지만 생성자를 호출하니 맨 첫줄에 써야한다. 자기 자신의 객체에 인자 5를 넣은 형식의 생성자를 찾으라는 것이다.(말하자면 자기 자신이니까 Test39(5)를 실행시킬수 있는 곳을 찾아야한다.) 밑에 보니 Test39(int a) 생성자가 이에 부합하니 그리로 간다. 가니까 this.a=a; 를 하라고 한다. 우리가 받은 입력값이 5 즉 int a=5;나 마찬가지인 매개변수 처리까지는 알텐데 this.a는 무슨 a를 말하는건가? 클래스 객체 자기 자신의 변수 a지 않나? 그럼 Test39.a라고 생각해도 다를바 없다. 클래스 Test39에 있는게 보니까 같은 이름의 int a가 있다. 그 a랑 매개변수 a랑 구별하기 위해서 this.a라고 썼을 뿐이다. 알간? ㅎㅎ

다음줄에 출력하라고 해서 "5 in Test39" 출력하고나면 this.ex( );라는 라인을 만난다. this다음에 점을 찍는거 보니까 메소드로 가라는구나하고 머리회전 빨리빨리(?)하기 바란다.^^ 그럼 인자가 없는 형태의 ex( )메소드를 찾아보니 오라 바로 밑에 있다. 가서 보니 this.ex(10);을 실행하란다. 다시 메소드를 찾으라는데 이번엔 인자 10을 넣을수 있는 ex(10)메소드로 가라는구나. 시키는데로 가보자.ㅎㅎ 웬일이냐? 희한(?)하게도 바로 밑에 관련 메소드가 또 나온다.

this.a=a;가 다시 나오니 아까처럼 10을 클래스 안의 a 즉 전역변수 a에 메소드에서 입력받은 10을 넣어준다. 다음줄을 보니 "10 in ex"을 출력하란다. 험란한 항해(?)끝에 이제서야 두번째 줄을 찍는다. 감개무량하다. ㅎㅎ 그러기가 무섭게 "나는 매개변수 a가 있는 ex 메소드"를 또 찍는다. 다음에 보니 return 0; 이라는게 있다. 메소드앞에 있는 리턴값 타입이 int 이다. 따라서 메소드를 끝낼때 반드시 int 타입의 리턴값을 돌려주어야 한다. 그런데 나중은 모를까 지금은 뭐 특별히 리턴할 값이 없어서 그냥 0을 돌려준거다. 리턴값은 나중에 받아서 써도 되고 안써도 그만이다. 리턴값을 void로 했었다면 return이라는 명령을 안써도 되었을테지만 이런 케이스도 가능하다는걸 보여주기 위해서 일부러 만들었다. 믿거나 말거나...ㅎㅎㅎ

여기서부터가 여러분이 한단계 도약을 해야되는 부분이다. 이곳은 메소드가 끝났는데 다른곳은 계속 실행 도중에 다른 곳으로 이동하는 바람에 생성자나 메소드를 끝내지 못한 곳이 많다. 이럴 경우 지금 여기 int ex(int a) 메소드가 끝났으니 0값을 리턴(리턴해도 받는 인자가 예제에서는 없으니 무시)하면서 이 메소드를 불렀던 바로 그 전 부분 this.ex(10);으로 돌아간다. 그리고 다음줄을 실행한다. "나는 인자가 없는 ex 메소드"을 출력하라는 메세지가 나오니 실행하고 리턴값 0를 돌려주면서 역시 메소드가 끝난다. 그럼 이 int ex( )메소드를 불렀던 전 단계 this.ex( );로 아까처럼 돌아간다.

그리고 다음줄을 보니 "나는 매개변수 a가 있는 Test39 생성자"를 출력하고 Test39(int a) 생성자가 끝이 난다. 리턴값이 없어도 여기서 끝난게 아니다. 이 생성자를 호출한 곳으로 또 다시 돌아간다. 초반에 기본 생성자에서 이 곳으로 오지 않았나? 오래 되었으니 까먹었을수도 있겠다.ㅎㅎ 그래서 호출 지점인 this(5);라인으로 가서 다음줄을 보니 "나는 인자가 없는 Test39 기본 생성자"를 출력하면 처음 시작했던 기본 생성자의 실행명령들도 모두 끝이 난다. 다 끝났다.(?)

이렇게 생각하면 오산이다! 필자가 얘기했던 메인메소드에 관한 호랑이 담배피던 시절의 강좌를 기억하는가? 자바 프로그램은 메인메소드에서 시작해서 메인메소드에서 끝난다. 자 그럼 메인메소드를 다시 보자. 우리는 여태까지 Test39 x=new Test39( );이라는 명령 단 한줄을 처리하기 위해서 이 생고생(?)을 한 것이다. 그렇다고 필자를 원망하지 말아라. 다 피가되고 살이 될것이니 말이다.^^

마지막으로 한줄이 남았다. x.a 즉 전역변수 a의 값을 출력하란다. 그래서 "10 in 메인메소드"를 맨 마지막에 출력하는 것이다. 휴우~ 이제야 프로그램 하나가 끝났다. 이 예제를 통해 자바는 어떻게 명령을 읽어드리고 어떤 순서로 처리하는지 알게 되었을 것이다. 복잡해 보여도 핵심은 하나다. 순서대로 실행하고 다른 곳으로 가느라 처리못한 명령들은 어떤 파트가 끝난 시점에서 바로 직전에 호출한 곳으로 되돌아가면서 못했던 부분을 하나하나 처리해 가는 과정이 자바의 호출코드 처리방법이다. this가 뭔지 아는것도 중요하지만 이것을 씀으로 인해서 파생되는 부분까지도 알게 만들어주는 힘(?)을 강이의 자바강좌에서 느꼈길 바란다.^^

댓글 26개:

  1. 아니 이런 좋은 강의에 댓글이 없다니 ㄷㄷ;;;

    잘보고갑니다!! ㅎㅎ

    답글삭제
  2. C의 리커시브 콜과 비슷하군요 잘 보고 갑니다.

    답글삭제
  3. 덕분에 잘 배우고 갑니다 ! 좋은 정보 감사합니다 ~

    답글삭제
  4. this()에 대한 개념이해를 위해 웹검색을 하다
    우연찬게 강이님의 강좌를 찾았습니다.

    정말 좋은 내용과 적절한 설명, 게다가 유머러스한
    화술까지 정말 잘보고 갑니다~

    북마크 해놓고 앞으로 종종들려서 도강좀할게요^^

    답글삭제
  5. JAVA를 공부하게 되어서 보게 되었지만 JAVA 뿐만 아니라 모든 객체지향 언어를 공부하는데 있어서 아주 큰 도움이될 것 같습니다. 잘 보고 있습니다. 감사합니다^^

    답글삭제
  6. 잘보고 가염 ^^

    -Carter24

    답글삭제
  7. 도움이 많이 되었습니다.!
    감사합니다.~~

    답글삭제
  8. 책을봐도 이해가 안갔는데.. 바로 이해가 가네요
    감사합니다.

    답글삭제
  9. 좋은 정보 감사합니다^ ^
    공부하는데 도움이 많이 됐어요ㅎㅎ

    답글삭제
  10. 감사합니다 ㅎ ㅎ

    답글삭제
  11. this에 대한 이해가 아주잘되네요~ 감사합니다!!

    답글삭제
  12. 와우 감탄하고 갑니다.

    답글삭제
  13. I could not refrain from commenting. Very well written!


    my webpage ... anti cellulite treatment

    답글삭제
  14. 좋은 강의 감사합니다. 링크만 퍼가요 ^^:

    답글삭제
  15. 정말 this 책도보고 자료도 많이 찾아도 여러가지 케이스를 다
    이해하기 어려웠는데 정말 좋은 자료 보고 가요 ^^
    감사합니다.

    답글삭제
  16. 쉽게 이해가 되요...!
    감사합니다...

    답글삭제
  17. 머리에 쏙쏙 들어오는 강의..ㅠㅠ
    그동안 거미줄마냥 엉켜있었던? 개념?들이 한방에 해결 된 느낌이
    네요..좋은 강의 앞으로도 쭈우욱 의어나가시길..

    답글삭제
  18. 잘 듣고 있습니다.

    답글삭제
  19. 전역변수의 a값이 왜 10인가요?

    답글삭제
    답글
    1. * this.a = 전역변수 a (인스턴스변수 a)

      this .ex(10) 문장 으로

      int ex(int a) 메소드출력
      {
      this.a =a ; //
      a가 10 이므로 전역(인스턴스변수) =10 입니다
      ....

      삭제
  20. 감사합니다. 잘 보고 갑니다^^

    답글삭제
  21. 와 너무 이해가 잘 갑니다
    나머지 게시물들도 읽어볼게요

    답글삭제