참조변수 하나로 여러개의 객체를 제어하는 것
-> 상속 관계에 있을 때 부모 참조변수로 자식 객체들을 생성하고 제어함 but 오버라이드 된 메소드만 가능
참조변수.메소드() 글씨는 같은데 결과가 다르게 나온다 하여 다형성 이라고 부름
public class First {
int a;
void showFirst() {
System.out.println("showFirst 입니다");
}
void show() {
System.out.println("First 클래스의 show method");
}
}
public class Second extends First{
int b;
void showSecond(){
System.out.println("show Second");
}
@Override
void show() {
System.out.println("Second 클래스의 show method");
}
}
public class Test extends First {
@Override
void show() {
System.out.println("Test의 show");
System.out.println();
}
}
public class Main {
public static void main(String[] args) {
//업캐스팅이 되어도 자식객체의 기능메소드를 사용할 수 있는 경우가 있음 -> 오버라이드 된 메소드
//부모 참조변수 1개로 자식객체 모두를 제어할 수 있음 => 다형성
//같은 참조변수 하나로 부모것도 자식곳도 참조하는 것
First obj = new First();
obj.show();
obj = new Second();
obj.show();
obj = new Test();
obj.show();
}
}
상속의 관계에 있을 때 부모객체에서 자식객체를 참조할 수 있는 것, 자식 객체를 제어할 수는 있지만 자식객체의 고유의 것은 쓸 수 없다
public class Main {
public static void main(String[] args) {
//제대로 된 캐스팅
First f = new First();
Second s = new Second();
//다른 class의 객체를 참조하면 에러
//f= new Second(); // 에러 : Type mismatch: cannot convert from Second to First
//단, 상속 관계의 클래스 라면 가능해짐
f= new Second(); //부모참조변수로 자식객체를 참조할 수 있음 [UP casting]
//상속후엔 Second 객체에 first 객체를 가지고 있기 때문에
//부모 참조변수로 자식객체를 참조하여 제어가능
f.a = 10;
f.showFirst();
//참조는 할 수 있지만 자식객체의 고유기능은 쓸수 없음
//f.shoSecond(); //에러 : The method shoSecond() is undefined for the type First
}
}
자식 객체에서 부모객체 제어하려는 것 -> 불가
하지만 상속 관계에서 한번이라도 UP casting이 된 상태에선 다운캐스팅 가능
즉, 자식객체를 참조하는 부모의 참조변수를 참조하여 객체를 공유함
사용법 : (데이터 타입)참조변수
-> ((데이터 타입)참조변수).변수
-> ((데이터 타입)참조변수).메서드()
public class Main {
public class Main {
public static void main(String[] args) {
//자식객체의 고유기능을 사용하고싶다면 자식객체를 참조하는 참조변수가 필요
//새로운 자식참조변수를 만들고 Second객체를 참조하면 First 참조변수 f의
//참조값(주소)를 대입해주기 -> 객체 공유
//Second s2 = f; //error : Type mismatch: cannot convert from First to Second
//자식(Second)가 부모(First)를 참조한다고 오해함
//f가 참조하는것이 Second 객체라고 알려주면 대입 가능(형변환)
Second s3 = (Second) f; //다운캐스팅
s3.b = 50;
s3.showSecond();
//업캐스팅 되어 있지 않은 경우 다운캐스팅 시도하면 에러
First f2 = new First();
//Second s4 = (Second)f2; //다운캐스팅 시도 - 형변환은 객체를 바꾸는 것이 아니고 주소값을 바꾸는것
//s4.showFirst(); //이클립스에서 오류표시 안남 but 실행하면 오류 -> class First cannot be cast to class Second
//이런 up, down 캐스팅을 하는 이유
//이걸 하려면 오버라이드 된 메소드일때 살펴봐야함
First ff= new Second(); //업캐스팅
ff.show(); //실제 참조하고 있는 객체의 오버라이드 된 show가 발동됨
System.out.println();
//업캐스팅이 되어도 자식객체의 기능메소드를 사용할 수 있는 경우가 있음 -> 오버라이드 된 메소드
//이 기술을 이용하여 다양하게 활용할 수 있음
//실제 활용현태 실습
//부모 참조변수 1개로 자식객체 모두를 제어할 수 있음 => 다형성
//같은 참조변수 하나로 부모것도 자식곳도 참조하는 것
First obj = new First();
obj.show();
obj = new Second();
obj.show();
obj = new Test();
obj.show();
//조부모 참조변수로 손주객체 참조가능
//First - Second - Third
obj = new Third();
obj.show();
//이렇게 obj.show(); 라는 글씨는 같은데
//결과가 다르게 나온다 하여 다형성 이라고 부름
}
}
다형성 사용이유
보모의 참조변수를 통해 자식객체들을 생성하고 제어할 수 있다
//Dog, Cat, Pig의 부모클래스
public class Animal {
//오버라이드용 메소드
void say() {
}
}
public class Dog extends Animal {
void say() {
System.out.println("멍멍");
}
void gardHouse() {
System.out.println("집지키기");
}
}
public class Cat extends Animal {
void say() {
System.out.println("야옹");
}
void handling() {
System.out.println("왔니");
}
}
public class Pig extends Animal {
void say(){
System.out.println("꿀꿀");
}
void eatAndEat() {
System.out.println("냠냠");
}
}
-> 배열은 같은 타입의 변수들을 묶는 것 인데 다형성을 사용하면 서로 다른 객체를 부모클래스의 참조변수로 하나의 배열로 묶어 관리 할 수 있다
Animal ani = new Dog(); //업캐스팅
ani.say();
System.out.println();
//배열로 자식객체들 묶기
Animal anis[] = new Animal[3];
anis[0] = new Dog(); //UP casting
anis[1] = new Cat();
anis[2] = new Pig();
anis[0].say();
anis[1].say();
anis[2].say();
System.out.println();
//반목문
for (int i = 0; i < anis.length; i++) {
anis[i].say();
}
System.out.println();
//확장
for(Animal t : anis) {
t.say();
}
public class AnimalFctory extends Animal{
//애니멀 객체를 생성하여 리턴해주는 기능메소드
/*
* Animal makeAnimal(int num) {
*
* switch (num) { case 1: Animal d = new Dog(); return d; case 2: Animal c = new
* Cat(); return c; case 3: Animal p = new Pig(); return p; default:
* System.out.println("잘못선택"); return null; } }
*/
Animal makeAnimal(int num) {
Animal ani = null;
switch (num) {
case 1:
ani = new Dog(); //리턴 타입을 공통인 Animal로 묶어 관리
break;
case 2:
ani = new Cat();
break;
case 3:
ani = new Pig();
break;
}
return ani;
}
}
AnimalFctory af = new AnimalFctory();
//makeAnimal은 Animal을 리턴하는데
//다운캐스팅으로 타입을 맞춰줌
Dog d = (Dog)af.makeAnimal(1);
d.say(); //오버라이드 된 기능
d.gardHouse(); //고유기능
System.out.println();
Cat c = (Cat)af.makeAnimal(2);
c.say();
c.handling();
System.out.println();
Pig p = (Pig)af.makeAnimal(3);
p.say();
p.eatAndEat();
System.out.println();
//Animal 참조변수 1개로 여러갟체 제어하기 -> 배열
//편하지만 자식객체만의 고유기능은 사용불가
Animal ani = null;
ani = af.makeAnimal(1);
ani.say();
//자식객체의 고유기능을 사용하려면 다운캐스팅 해야함
Dog dog = (Dog)ani;
dog.gardHouse();
ani = af.makeAnimal(2);
ani.say();
((Cat)ani).handling(); // . 이 연산자 우선순위가 높아서 ()로 묶어준다
ani = af.makeAnimal(3);
ani.say();
((Pig)ani).eatAndEat();
//3. 캐릭터 5마리를 랜덤하게 만들어서 공통기능과 고유기능 시용
//랜덤 값을 만들어 내는 객체생성
Random rnd = new Random();
//동물 참조변수 5개를 가진 배열 생성
Animal[] anis = new Animal[5];
for (int i = 0; i < anis.length; i++) {
int n = rnd.nextInt(3) + 1; // 1,2,3
anis[i] = af.makeAnimal(n);
}
System.out.println();
//각 객체들 기능 호출
for (int i = 0; i < anis.length; i++) {
//동물들의 공통기능
anis[i].say(); // 오버라이드 된 메소드 발동
//고유기능
// anis[i]번째 참보변수가 어떤 클래스인지 알아야 다운캐스팅하고
//고유 기능을 사용할 수 있음
//탐조변수가 어떤 클래스의 객체를 참조하고 있는지 알려주는 연산자 : instanceof
if(anis[i] instanceof Dog) {
Dog ddd = (Dog)anis[i];
ddd.gardHouse();
} else if(anis[i] instanceof Cat) {
((Cat)anis[i]).handling();
} else if(anis[i] instanceof Pig) {
((Pig)anis[i]).eatAndEat();
}
}
instanceof
참조변수가 어떤 클래스의 객체를 참조하고 있는지 알려주는 연산자-> 사용하는 이유 : 다형성으로 인해 여러 타입이 전달될 수 있으므로 각각의 인스턴스 타입에 따라 서로 다른 작업을 하기 위해
if(참조변수 instanceof 클래스이름) {실행문;}
상속과 다형성의 차이 생각해보기
상속은 자식객체에서 부모의 객체를 참조하는 것이고 다형성은 부모객체의 참조변수 하나로 자식 객체들을 모두 제어할 수 있는 것
하지만 상속에서도 다형성에서도 자식객체의 고유기능은 사용할 수 없는 공통점이 있다
자식 객체의 고유 기능을 사용하고 싶으면 다운캐스팅을 사용해 강제로 명시해주면 접근 가능하다~!