자바의 객체지향 프로그래밍(OOP, Object Oriented Programming)에 대해서 논할때 어김없이 등장하는게 바로 이 상속(Inheritance)이란 개념이다. 자바의 상속을 공부하면서부터 많은 프로그래머들이 알던것도 가물가물해지고 모든게 뒤죽박죽되어서 절망(?)의 늪에 빠지는 이들이 상당수다. 특히 이런 상황이 초래되는 이유중에 하나가 발단부터 즉 의미부터가 다르기 때문이다. 상속이라는 말의 의미는 부모가 자식에게 뭔가를 물려주는 것이다. 그럼 물려주고 나면 자식은 가진게 더 많아지지만 부모는 가진게 없어진다. 이게 상속의 본질적 의미겠지만 자바에서는 자식(클래스)이 부모(클래스)한테 상속받았다고 해서 부모가 가진게 없어지는게 아니고 그냥 그대로다. 자식이 단지 가진게 많아질 뿐이다. 자식이 물려는 받으나 부모가 가진게 줄지는 않는다. 상속+공유의 개념으로 이해하는게 더 나을 것이다.
자바의 상속에 대해서 다시 확실하게 정립하겠다. 자바의 상속이란 자식 클래스가 부모 클래스에 있는 생성자를 제외(상속되지는 않지만 자식클래스의 레퍼런스를 만들때 부모클래스의 생성자가 자동으로 먼저 실행되고 자식클래스의 생성자가 실행된다.)한 모든 것을 물려받아 같이 공유하며 이를 더 확장(extends) 발전시키는 것이다. 부모클래스를 Superclass = Parent Class = Base Class라고 하고 자식클래스를 Subclass = Child Class = Derived Class라고도 한다. 또한 부모가 가지고 있는 멤버요소와 똑같은 것을 자식도 가지고 있을 경우(오버라이드 Override 혹은 오버라이딩 Overriding) 자식의 멤버요소를 부모가 가지고 있는 것보다 더 확장 발전시킨걸로 간주하고 자식 클래스에 있는 해당멤버를 사용한다. 그리고 부모와 자식 사이에 파이널(final)이란 넘(?)이 있는데 이 final은 부모자식간에 사이좋게 지내고 공유하는 것을 못하게 막는다. final이란 딱지가 클래스 앞에 붙으면 그 클래스는 물론이고 그 하위에 있는 메소드나 필드(선언된 변수들이 있는 공간)까지 몽땅 final이 되어 상속(공유)받지 못하게 된다.
더불어 여러분이 자바에서 쓰는 모든 클래스는 이것(?)의 자식 클래스다. ?는 바로 Object다. Object(객체)란 클래스가 이미 자바 API(Application Programming Interface,레퍼런스 및 개발자 문서,클래스 라이브러리)에 있는데 자바에서 쓰는 모든 클래스는 자동으로 이 Object 클래스를 상속받는다. toString( ), notify( ), wait( ), equals(??)등 나중에 기회되면 보게 되겠지만 이런 메소드들이 Object 클래스안에 들어있는데 이런 것들을 자동으로 상속받기 때문에 따로 만들지 않아도 이런 메소드들을 어디서나 어떤 클래스에서나 쓸수 있다. Object 클래스는 모든 클래스 중에 최상위 클래스이자 모든 클래스의 부모다. 좀 폼(?)나게 설명하자면 "모든 클래스들의 아버지" 자바에서 "제우스" 같은 존재가 바로 이 "Object 클래스"다. 이런 까닭에 우리는 자바를 Object 즉 객체를 빼놓고선 자바에 대한 언어를 논할수 없다고 하는 것이고 상속을 빼놓고선 객체지향 프로그래밍을 상상조차 할수 없는 것이다.
지금까지 이래저래 주절된 것이 왜 그렇게 많은 사람들이 객체지향이네 상속이 어쩌네 객체가 저쩌네하는 말들 여기저기서 많이 들어봤을터인데 대부분이 이런 연유에서다. 필자가 자바의 상속에 관해 초정밀 압축시켜 넋두리(?) 삼아 말해보았는데 지금까지 쌓여있던 여러분의 궁금증을 어느 정도 해소해 주었길 바라면서 이제 본격적으로 자바의 상속에 대해서 공부해 보겠다. 한마디로 상속은 종합선물세트(?)다. 여러분이 지금까지 배웠던 생성자, 메소드, 변수등이 이리저리 교차하며 어떻게 작동되고 실행되는지 정신없을 것이다. 그러나 두려워하지 말자. 강이가 함께 할것이니까 말이다.ㅎㅎ ^^
자 그렇다면 자바에서 상속이 왜 필요한 것일까? 이것을 알아야 제대로 써먹을수 있을것 아닌가? 여러분이 프로그램을 짤때 뭔가를 구현해야되는 파트가 있는데 만들어야될게 엄청 많다고 치자. 그런데 우연히 어떤 클래스를 보니까 필요한 대부분의 기능들이 그 클래스안에 들어있더란 말이다. 이런 경우 자바에서는 원없이 가져다가 쓰라고 상속이란 강력한 기능을 탑재해 놓은 것이다. 프로그램을 제작할때 엄청난 시간과 비용절감을 가능하게 만들어주는 기능이 상속이라는 점은 누구도 부인할수 없을 것이다.
본격적으로 어떻게 쓰는지 보기로 하자. 이해를 돕기 위해 이름이 부모인 Parent 클래스와 이름이 Child 인 자식 클래스가 있다고 하자. Child 클래스가 Parent 클래스의 상속을 받는 명령은 다음과 같다.
class Parent
{
,,,
,,,,,,
}
class Child extends Parent
{
,,, //부모(Parent)에서 상속받은것(없어도 있다고 생각한다.)
,,,,,, //부모에서 상속받은것
.
..
...
}
위와 같이 extends란 명령을 써서 부모로부터 상속을 받는다. 예제를 보면서 상속에 대해서 보다 자세히 공부해 보기로 하자.(예제에서는 Child 클래스가 Test40이다.)
나는 Parent 생성자
100
Parent는 자동차를 소유
예제 출력의 결과가 위와같이 나오는데 상속의 개념을 잘 모른다면 이해가 되지 않을 것이다. 그럼 차근차근 코드를 살펴보자. 처음에 Test40 클래스의 레퍼런스 t(Test40 클래스를 참조하고 있는 인스턴스)를 만들었다. 객체 생성을 하였으니 Test40안에 생성자가 있는지 살펴본다. 보다시피 Test40안에는 생성자가 없다. 아니 엄밀히 말하면 눈에 보이지는 않지만 빈껍데기의 텅빈 Test40( ) 생성자가 있다. 저번에 생성자에 대해서 공부하였으니 알고 있으리라 간주하겠다. ㅎㅎ 그래서 아무것도 없는 생성자를 실행하고 객체 t를 만든다.
다음을 보니까 t.money에 100을 넣으란다.(변수를 만들고 보니 교통카드랑 이름이 같구나.ㅎㅎ) 그런데 Test40의 어디에도 money라는 변수는 없다. 그런데 어떻게 값을 초기화시키라는건가? 자세히 보니 extends 라는 키워드가 클래스 옆에 보인다. 바로 그거다! 어떤 멤버와 필드를 상속받았던 것이다. 어디로부터? Parent 로부터 말이다. 그럼 Parent 클래스를 찾아본다. 여기서야 클래스가 두개 뿐이니까 헤멜 필요가 없다.^^ 아니나 다를까 money가 있다. 그래서 자식인 Test40클래스에서도 이 변수를 사용할수 있다. 그래서 100을 출력한다. 그리고 결과를 맞춰보니 100을 출력하긴 하는데 그 위에 또 뭔가를 출력했다.?
희한할 것이다. Test40 자신의 생성자도 아니고 난데없이 부모인 Parent 클래스의 생성자를 실행했다. 왜일까? 여기에 상속의 또다른 특징이 있는 것이다. 상속을 받았을 경우 객체 생성시 자식의 생성자를 실행하기 전에 부모의 생성자인 Parent( )를 먼저 호출해서 실행하고 그 다음에 해당 자식의 생성자를 실행하고 객체가 만들어지는거다. 그런 까닭에 예제에서도 객체생성시 "나는 Parent 생성자" 라인이 출력된 것이고 자식의 생성자는 있긴 하지만 보이지는 않는 빈껍데기니까 어떤 실행결과도 볼수 없는 것이다.(사실 상속시 부모 생성자가 호출되는 이유는 자식 생성자 내부에 super( )라는 부모 생성자를 호출하는 키워드가 자동으로 만들어져 숨어있기 때문인데 이 내용에 대해서는 다음에 따로 시간을 할애하여 설명할 것이니 그런게 있다고만 알아두자.)
메인메소드 마지막 줄에 있는 t.car( );도 money와 마찬가지로 원래 자식한테 있는게 아니었지만 부모한테 물려받았으므로 부모 클래스안에 있는 것처럼 자유롭게 이 메소드를 쓸수 있는 것이다. 따라서 car 메소드의 실행값을 출력하고 프로그램이 끝난다.
어떤가? 할만한가? ^^ 상속을 함으로 인해서 여러가지 가능해지는 프로그래밍 기법들(?)을 이제 하나씩 배워나가야 한다. 그 중에 하나가 방금전 얘기한 super 라는 키워드이고 이 밖에 알아야할 것들을 다음부터 만나보는 시간을 갖기로 하겠다. 자바에서 상속은 알짜배기 핵심기능 중의 하나이니 다시 한번 내용을 읽고 궁금증이 생기는 것들은 예제를 응용해 가면서 실험해 보기 바란다. 수고했다. ^^
자바를 처음 시작한다는 가정하에 사소한 것부터 하나하나 짚고 넘어가며 따라하기 쉽도록
예제를 중심으로 모든 설명이 사용자의 관점에서 자세하게 기술되어 있는것이 특징입니다.
"강이"의 자바 강좌는 본 블로그(alecture.blogspot.com)와 제휴를 통해
독점적으로 공급될 예정이며 내용의 수정은 공급자의 제한으로 불가하고
사이트 출처를 밝히는데 한해 어디서나 자유롭게 쓸수있도록 합의하였음을 알립니다.
2011년 5월 4일 수요일
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가 뭔지 아는것도 중요하지만 이것을 씀으로 인해서 파생되는 부분까지도 알게 만들어주는 힘(?)을 강이의 자바강좌에서 느꼈길 바란다.^^
자바에서 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가 뭔지 아는것도 중요하지만 이것을 씀으로 인해서 파생되는 부분까지도 알게 만들어주는 힘(?)을 강이의 자바강좌에서 느꼈길 바란다.^^
피드 구독하기:
글 (Atom)



