sitelink1 | |
---|---|
sitelink2 | |
sitelink3 | |
sitelink4 | |
sitelink5 | |
sitelink6 |
프로그래머 집안이 있습니다.
아버지는 C전문가 입니다.
아들은 아버지로부터 어릴때부터 C를 배워서 C도 마스터하였고 시대에 맞추어 JAVA도 익혔습니다.
그렇다면 아버지 클래스는 Father 아들은 Child 그리고 다룰 줄 아는 언어는 함수로 표현할 수 있겠습니다.
정리하면 다음과 같습니다.
class Father
{
public void c(){
... ... ...
}
}
class Child extends Father
{
public void java(){
... ... ...
}
}
그런데 어머니가 있습니다. 바로 JVM(자바가상머쉰)입니다. 두 부자는 둘다 프리랜서인데 고지식한 전산쟁이라서 회사에서
일을 맡아올때 중간에 도와줄 사람이 필요했습니다. 바로 어머니가 경영학 출신이었죠...^^
그래서 두 부자를 철저히 관리해주고 일을 맡아옵니다.
그리고 일을 내어주는 회사는 바로 우리입니다.
우리는 필요한 일이 있으면 두 부자를 이용해서 일을 시키는데 어머니라는 중간자와 계약을 맺어서 이용가능합니다.
대충 여기까지 이해가 가겠죠?
일단 우리는 어머니만 만나봤습니다. 두 부자를 만난적이 없습니다.(클래스의 "Encapsulation"입니다. API를 보면 클래스의 이름과 메소드에 대한 설명만 나옵니다. 메소드의 구현원리는 설명되어 있지 않습니다. 알 필요도 없죠.)
그래서 어머니에게 C를 잘하는 사람을 소개해 달라고 부탁만합니다. 그러면 어머니는 아버지의 명함을 건네줍니다.
그리고 우리에게 아버지의 능력이 필요할때마다 그 명함으로 호출하면 일을 처리해준다고 말합니다.
명함에 적혀있는것은 달랑 "Father" 와 "C의 마스터"라고 적혀있겠죠? 더 많은 정보는 필요없으니까요.
이것을 객체생성으로 표현할 수 있습니다.
Father f = new Father(); 여기서 f가 명함이 되겠군요. 그리고 아버지의 능력을 이용합니다.
f.c();
그런데 어느날 아버지가 해외출장을 갔습니다. 그런데 공교롭게도 우리는 C개발자가 필요합니다.
그래서 어머니께 다시 부탁을 합니다. C개발자가 필요해요~
그러자 어머니는 아버지와 같은 기술을 보유한 사람을 안다고 합니다. 그러니 그냥 아버지의 명함 그대로 호출하면 된다고 일러줍니다.
이것을 객체생성으로 표현하면 Father f = new Child(); 가 되겠죠? 아들도 상속을 받아 C의 마스터니까요.
이것 역시 f.c();하면 자동으로 아버지가 아닌 아들의 능력을 이용합니다.
하지만 우리는 우연찮게 Child객체가 java도 잘 한다는 것을 알았습니다. 그래서 아들객체에게 java프로그램도 해달라는 요청서를
작성해서 어머니께 건네줬습니다. f.java();가 되겠죠.
그러자 어머니는 그걸보고 우리에게 따집니다. 왜 계약에도 없는 일을 시키냐는 거지요.(compile error)... 분명 처음에 우리가 아들의 객체를 아버지의 명함으로 생성할때는 C개발자가 필요해서였습니다. 게다가 아버지의 명함에는 "Father"와 "C의 마스터"라는 표식이 분명하게 나와있으니까 만일 아들만이 할 수 있는 자바개발을 시킨다면 계약위반이라는 거지요.
그것이 바로 type safety(형안정)입니다.
이제 레퍼런싱의 문제로 넘어가 봅니다.
레퍼런싱은 바로 명함입니다.
Child는 Father의 상속을 받아 C의 마스터입니다. 때문에 Child역시 아버지와 같은 일을 할 수 있다고 모든이에게 알리고 다닐수 있습니다.
바로 Father f = new Child();입니다. 아버지의 이름으로 일을 하는거지요. 그것은 어머니도 인정했습니다.
하지만 반대로 아버지가 아들의 이름으로 일을 할 경우는 뻔한 결과를 야기합니다.
바로 어머니의 태클입니다. java의 ja짜도 모르는 사람이 어떻게 아들의 이름으로 일을 할 수 있느냐는 거지요. (괜히 아버지를 자바개발자로 소개했다가는 나중에 회사이미지 버립니다. 신용도가 없으면 그 클래스는 끝장이죠.)
그래서 그런행위는 어머니에 의해 저지당합니다. 바로 이런경우죠... Child c = new Father(); (compile error)
하지만 아버지는 그래도 아들의 명함을 이용하고 싶었습니다. c = (Child)f; (캐스팅연산으로 어머니를 속였습니다)
그래서 어머니의 저지는 피했습니다. 하지만 막상 일을 하려니 java때문에 포기해야 했습니다. (runtime error)
지금까지 기나긴 예를 들어서 설명했습니다. 되도록 이해하기 쉽게 하려 했는데 도움이 될지 모르겠습니다.
여기서 우리가 필요하고도 중요하게 생각해야 할 것은 "아버지의 명함으로 아들이 일을 할 수 있다"는 것입니다. 나머지는 개념적인 내용으로 그냥 상식수준으로 알아두시면 됩니다.
아버지의 명함으로 아들이 일을 하면 편한점이 있습니다. 바로 아들들이 많을 경우죠.
같은 C프로그래밍이라도 아들들 각각의 능력이 다르게 발전될 수 있습니다. (오버라이딩)
그리고 우리는 그 자식들 각각의 약간씩 다른 C프로그래밍 능력을 모두 이용하고 싶어집니다.
그럴경우 만일 아버지의 명함으로 일을 시킬 수 없다면 아들들 각각이 자신들만의 명함을 가져야합니다.
그렇게 되면 각각의 명함을 만들기 위해 디자인이 매번 바뀌어야 하는 수고를 해야겠죠.
하지만 아버지의 명함으로 일을 시킬 수 있다면 아버지의 명함 디자인 하나만 만들어서 각각의 아들들에게 복사해서 하나씩 나눠주고 일을 시키면 편할겁니다.
그에 대한 예제 소스입니다. (Override.java)
class Father
{
public void c(){}
}
class ChildA extends Father
{
public void c(){
int a=4;
int b=5;
int c=a-b;
System.out.println("ChildA는 a,b정수를 뺀다. a=4,b=5,c=a-b="+c);
}
public void java(){}
}
class ChildB extends Father
{
public void c(){
int a=4;
int b=5;
int c=a+b;
System.out.println("ChildB는 a,b정수를 더한다. a=4,b=5,c=a+b="+c);
}
public void cPlus(){}
}
class ChildC extends Father
{
public void c(){
int a=4;
int b=5;
int c=a*b;
System.out.println("ChildC는 a,b정수를 곱해준다. a=4,b=5,c=a*b="+c);
}
public void html(){}
}
class Override
{
public static void main(String args[]){
Father f[] = new Father[3]; //이렇게 배열을 생성하는 부분이 복사하는 부분이죠.
f[0] = new ChildA();
f[1] = new ChildB();
f[2] = new ChildC();
for(int i=0;i<3;i++)
{
f[i].c(); //아주 편합니다. 한줄로 모든 아들들에게 각자의 일을 시킵니다.
}
}
}
위의 예제에서 각각의 child들은 c()메소드를 Overriding해서 조금씩 다른 일을 수행합니다."