자바를 하면서 가장 중요한 개념중에 하나가 다형성이다.
다형성이란 부모클래스의 변수로 여러개의 하위클래스의 객체를 가지는 것을 말한다.
다형성의 장점으로는 확장성과 재사용성이고 하나의 클래스로 여러개의 하위클래스를 관리할수 있어 유동적이고 유지보수가 좋다.
이러한 다형성을 쓰기위해서는 몇가지 규칙이 있다.
1. 부모클래스의 변수에 하위클래스의 객체를 가지면 부모클래스의 메소드만 사용이 가능하다.
이러한 이유는 부모클래스의 메소드 개수에 있다. 자식클래스의 메소드가 부모클레스에 없는 경우 이것을 사용한다고 생각해보
자. 물론 부모클래스에는 없는 메소드이니 당연히 에러가 난다. 이것을 막기위해 자식클래스를 객체로 가지는 부모클래스의
변수는 자식의 메소드를 사용할 수 없게 되어있다.
2. 메소드를 오버라이딩하면 자식의 메소드 우선으로 실행된다.
실제 아래에 있는 예제소스를 보면 알겠지만 자식에 있는 메소드를 사용하려고 하면 에러가 난다.
3. 멤버변수는 변수의 타입에 따라서 값이 달라진다.
이것도 아래 있는 예제를 보면 알겠지만 Top으로 자료형을 둔것과 Sub2로 자료형을 둔 것의 멤버변수 a의 값이 달라지는 것을
볼 수 있다.
4. 메소드의 매개변수로 오는 부모클래스의 변수는 인자로 자식클래스의 객체를 받을 수가 있다.
이것을 보면 감이 잘 안올지도 모르겠지만.... java를 하다보면 굉장이 중요한 개념이기 때문에 소홀히 해서 넘어가서는 안된다.
아래 예제를 보고 천천히 이해를 하기 바란다.
interface InterfacePrint {
public abstract void Print();
}
class Top {
int a = 10;
public void Print() {
System.out.println("------------------------------");
System.out.println("TopClass");
System.out.println("------------------------------");
}
public String toString() {
return "Top";
}
}
class Sub1 extends Top {
public void Print_Sub() {
System.out.println("------------------------------");
System.out.println("Sub1Class, Nothing Override");
System.out.println("------------------------------");
}
public String toString() {
return "Sub1";
}
}
class Sub2 extends Top {
int a = 20;
@Override
public void Print() {
// TODO Auto-generated method stub
System.out.println("------------------------------");
System.out.println("Sub2Class, TopClass Override");
System.out.println("------------------------------");
}
public String toString() {
return "Sub2";
}
}
class Sub3 extends Top implements InterfacePrint {
@Override
public void Print() {
// TODO Auto-generated method stub
System.out.println("------------------------------");
System.out.println("Sub3Class, Interface Override");
System.out.println("------------------------------");
}
public String toString() {
return "Sub3";
}
}
class Sub4 extends Top {
public String toString() {
return "Sub4";
}
}
class ParametaTest { // 조상클래스의 참조변수를 매개변수로 함.
public void print(Top t) {
System.out.println(t + "출력");
}
}
public class PolymorphismTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Top top = new Top();
top.Print();
Top sub1 = new Sub1();
Sub1 sub1_1 = new Sub1();
// Sub1 sub1_2 = new Top();//자식이 부모의 형으로 인스턴스 생성시 Error
System.out.println("<<<<<<<<<<TopClass가 출력>>>>>>>>>>");
sub1.Print();// Top의 메소드만 사용가능
// sub1.Print_Sub();//하위 클래스의 메소드는 불가능
System.out.println("<<<<<<<<<<Sub1Class로 형변환한 TopClass>>>>>>>>>>");// 다운캐스팅
System.out.println("----------런타임에러----------");
// sub1_1 = (Sub1) new Top();// Error-컴파일에러는 안나지만 런타임에러.
System.out.println("<<<<<<<<<<Sub2Class가 출력>>>>>>>>>>");
Top sub2 = new Sub2();
Sub2 sub2_1 = new Sub2();// 멤버변수 확인용(참조형에 따라서 멤버변수의 값이 바뀜)
sub2.Print();// override를 하면 하위 클래스의 메소드가 실행
System.out.println("------------------------------");
System.out.println("맴버변수 호출");// 멤버변수는 참조변수가 부모의 것을 따른다.
System.out.println("top.a = " + top.a);
System.out.println("sub2.a = " + sub2.a);
System.out.println("sub2_1.a = " + sub2_1.a);
System.out.println("------------------------------");
System.out.println("<<<<<<<<<<Sub3Class가 출력>>>>>>>>>>");
Top sub3 = new Sub3();
sub3.Print();
// 인터페이스로도 참조변수 생성 가능
InterfacePrint interfacePrint = new Sub3();
interfacePrint.Print();
System.out.println("<<<<<<<<<<비어있는 Sub4Class>>>>>>>>>>");// 자식클래스가 비어있으면
// 부모의 멤버를
// 따른다.
Top sub4 = new Sub4();
sub4.Print();
System.out.println("Sub4.a = " + sub4.a);
Top topArray[] = new Top[4];// 한개의 참조변수로 여러개의 인스턴스 확보(배열 사용해봤음)
topArray[0] = new Sub1();
topArray[1] = new Sub2();
topArray[2] = new Sub3();
topArray[3] = new Sub4();
topArray[0].Print();// NothingOverride
topArray[1].Print();// Override
topArray[2].Print();// Override
topArray[3].Print();// NullMember
System.out.println("topArray[0] = " + topArray[0].a);
System.out.println("topArray[1] = " + topArray[1].a);
System.out.println("topArray[2] = " + topArray[2].a);
System.out.println("topArray[3] = " + topArray[3].a);
ParametaTest parametaTest = new ParametaTest();// 자식클래스의 참조변수를 인자로 넘기는
// 것이 가능함.
parametaTest.print(top);
parametaTest.print(sub1);
parametaTest.print(sub2);
parametaTest.print(sub3);
parametaTest.print(sub4);
}
}