다형성(polymorphism)
조상타입참조변수로 자손타입객체를 다루는것
다형성을 구현하는 기술
- 상속 또는 인터페이스의 자동타입변환
- 오버라이딩
다형성의 효과
- 다양한 실행결과를 얻을 수 있다.
- 객체를 부품화 시킬 수 있어 유지보수가 용이하다.
인터페이스를 이용한 다형성 개념
interface I {
void method1();
void method2();
}
I i = new A();
I i = new B();
//I라는 인터페이스에 A라는 구현객체를 대입을 했다.
//이때, A라는 객체가 문제가 있어서 B라는 객체로 바꿀 수있다.
i.method1();
i.method2();
//처음에는 A라는 구현객체의 메소드지만,
//B로 변경했을때, B의 구현객체의 메소드로 사용할 수 있다는 것
예를 들어
useRemoteControl (new Televison());
useRemoteControl (new Audio());
를 만들어서 대입을 할 수 있다.
자동타입변환(Promotion)
UML에서 점선은 인터페이스 / 실선은 상속 관계
같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
다형성을 위해 자바는 부모타입에 모든 자식객체가 대입될 수 있다.
이것을 이용하면 객체는 부품화가 가능하다.
타입변환이란?
데이터 타입을 다른 데이터 타입으로 변환하는 행위
자동타입변환(Promotion)
프로그램 실행 도중에 자동적으로 타입변환이 일어나는 것
자동타입변환 조건↓
부모클래스변수 = 자식클래스타입;
↖자동타입변환 ↙
자동타입 변환의 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다는 것.
import package0008_promotionExample.parent;
import package0008_promotionExample.child;
public class main {
public static void main(String[] arg) {
startPromotion();
}
private static void startPromotion() {
//child클래스로부터 child객체를 생성
child child = new child();
//parent 변수에 대입하면 자동타입 변환
parent parent = child;
parent.method1();
parent.method2(); //child에는 method2,method3가 있다.method2는 나옴.
// parent.method3(); 호출불가능
}
}
package package0008_promotionExample;
public class parent {
public void method1() {
System.out.println("Parent-method1()");
}
public void method2() {
System.out.println("Parent-method2()");
}
}
package package0008_promotionExample;
public class child extends parent {
@Override
public void method2() {
System.out.println("Child-method2()");
}
public void method3() {
System.out.println("Child-method3()");
}
}
자동 타입 변환 예제 [슬라임]
main
import package0004_gameSlimeLand.slime.NormalSlime;
import package0004_gameSlimeLand.slime.actionSlimeBludslime;
import package0004_gameSlimeLand.slime.actionSlimeRedslime;
public class main {
public static void main(String[] arg) {
CreateSlime();
}
public static void CreateSlime() {
//슬라임을 매개변수로 넣어서 출력하기
NormalSlime normalSlime = new NormalSlime();
//actionSlime의 자식
actionSlimeBludslime blueActionSlime = new actionSlimeBludslime();
actionSlimeRedslime redActionSlime = new actionSlimeRedslime();
//normalSlime getAction 메소드 부분
// public void getAction(actionSlime action) {
// action.playAction();
// }
normalSlime.getAction(blueActionSlime);
normalSlime.getAction(redActionSlime);
}
}
(blueActionSlime) 매개로 객체
actionSlime
package package0004_gameSlimeLand.slime;
//부모
public class actionSlime {
public void playAction() {
System.out.println("슬라임이 이동합니다");
}
}
actionSlimeBludslime
package package0004_gameSlimeLand.slime;
//actionSlime상속-자식
public class actionSlimeBludslime extends actionSlime {
//오버라이딩
@Override
public void playAction() {
System.out.println("푸른 슬라임이 행동합니다");
}
}
actionSlimeRedslime
package package0004_gameSlimeLand.slime;
//actionSlime상속-자식
public class actionSlimeRedslime extends actionSlime{
@Override
public void playAction() {
System.out.println("붉은 슬라임이 행동합니다");
}
}
NormalSlime
package package0004_gameSlimeLand.slime;
//RedSlime의 부모
public class NormalSlime {
//우리의 노멀슬라임은 lv1의 갸냘픈 슬라임입니다
//필드값
public int hp;
public int mp;
public int exp;
public String name;
public String color;
public void initSlime() {
System.out.println(this.name+" 슬라임이 태어났습니다");
}
public String getName() {
return this.name;
}
public int att() {
return 10;
}
//부모인 attionSlime을 매개로
public void getAction(actionSlime action) {
action.playAction();
}
}
RedSlime
package package0004_gameSlimeLand.slime;
//extends를 통해 NormalSlime의 데이터를 물려받았습니다 (상속) -자식
public class RedSlime extends NormalSlime {
public RedSlime(int input_hp, int input_mp, String input_color, String input_name) {
this.hp = input_hp;
this.mp = input_mp;
this.name = input_name;
this.color = input_color;
}
public void getColor() {
System.out.println("이 슬라임의 색상은 "+this.color+" 입니다");
System.out.println("이 슬라임의 이름은 "+this.name+" 입니다");
System.out.println("이 슬라임의 HP는 "+this.hp+" 입니다");
System.out.println("이 슬라임의 MP는 "+this.mp+" 입니다");
}
@Override
public int att() {
int rand = (int)Math.random();
if(rand==1) {
return criticalAtt();
}else {
return normalAtt();
}
}
public int criticalAtt() {
return hp/2;
}
public int normalAtt() {
return mp/3;
}
}
강제타입변환(Casting)
자식클래스 변수 = (자식클래스) 부모클래스타입;
ㄴ자식타입이 부모타입으로 변환된 상태
actionSlimeBludslime child = (actionSlimeBludslime) parent;
부모타입을 자식타입으로 변환하는 것을 말한다.
모든 부모타입을 자식클래스타입으로 강제변환할수있는것은아니다.
자식타입이 부모타입으로 자동변환한 후, 다시 자식 타입으로 변환할 때 강제타입변환을 사용 할 수있다.
객체타입확인(instanceof)
강제타입변환은 자식타입이 부모타입으로 변환되어있는 상태에서만 가능하기 때문에
다음과같이 부모타입의 변수가 부모객체를 참조할 경우 자식타입으로 변환할수없다.
Parent parent = new Parent();
Child child = (Child) parent;
부모변수가 참조하는 객체가 부모객체인지 자식객체인지 확인하는 방법
어떤 객체가 어떤클래스의 인스턴스인지 확인하려면 instanceof 연산자 사용
public void method(Parent parent){
//Parent 매개변수가 참조하는 객체가 Child인지 조사
//instanceof 로 parent와 Child가 같은지 확인해주고
//같으면 if문 안에 내용을 실행해준다.
if(parent instanceof Child){
Child child = (Child) parent;
}
}
public static void method1(actionSlime parent) {
if(parent instanceof actionSlimeBludslime) {
//자식클래스 변수 = (자식클래스) 부모클래스타입;
//강제타입변환 Castring 부모로바뀐것을 다시 자식으로
actionSlimeBludslime child = (actionSlimeBludslime) parent;
System.out.println("method1 - Child로 변환 성공");
} else {
System.out.println("method1 - Child로 변환되지 않음");
}
}
강제 타입 변환 예제-1
import package0004_gameSlimeLand.slime.NormalSlime;
import package0004_gameSlimeLand.slime.actionSlime;
import package0004_gameSlimeLand.slime.actionSlimeBludslime;
import package0004_gameSlimeLand.slime.actionSlimeRedslime;
public class main {
public static void main(String[] arg) {
CreateSlime();
}
public static void CreateSlime() {
//슬라임을 매개변수로 넣어서 출력하기
NormalSlime normalSlime = new NormalSlime();
actionSlimeBludslime blueActionSlime = new actionSlimeBludslime();
actionSlimeRedslime redActionSlime = new actionSlimeRedslime();
normalSlime.getAction(blueActionSlime);
normalSlime.getAction(redActionSlime);
//부모클래스타입으로 변수를만들었지만 = 실제로들어간것은 자식클래스이다.
actionSlime basicActionSlime_A = new actionSlimeBludslime();
method1(basicActionSlime_A);
method2(basicActionSlime_A);
//부모클래스타입으로 인스턴스 만든것
actionSlime basicActionSlime_B = new actionSlime();
method1(basicActionSlime_B);
// method2(basicActionSlime_B); //예외 발생
}
//강제타입형변환예시
public static void method1(actionSlime parent) {
if(parent instanceof actionSlimeBludslime) {
actionSlimeBludslime child = (actionSlimeBludslime) parent;
System.out.println("method1 - Child로 변환 성공");
} else {
System.out.println("method1 - Child로 변환되지 않음");
}
}
public static void method2(actionSlime parent) {
actionSlimeBludslime child = (actionSlimeBludslime) parent;
System.out.println("method2 - Child로 변환 성공");
}
}
강제 타입 변환 예제-2
private static void TodoList() {
Child Child_A = new Child();
Parent child_C = new Child();
Child_A.goToWork();
Child_A.goToPCRoom();
System.out.println("-------------");
Parent Not_Child_A = (Parent)Child_A;
Not_Child_A.goToWork();
System.out.println("--------------");
//자식클래스 변수 = (자식클래스)부모클래스타입
Child Child_B = (Child)Not_Child_A;
Child_B.goToWork();
Child_B.goToPCRoom();
}
출력값 :
나는 학교에 출근합니다
나는 PC방에 갑니다
-----------------
나는학교에 출근합니다
-----------------
나는 학교에 출근합니다
나는 PC방에 갑니다
Parent 에는 goToWork() 만 있고
Child 에는 goToWork(). goToPCRoom 둘다 있다.
강제 타입 변환 예제-3
import Package001.*;
public class main {
public static void main(String[] arg) {
TodoList();
}
private static void TodoList() {
Child Child_A = new Child("책가방", 3000);
Child Child_B = new Child("손가방", 60000);
Parent Child_C = new Child("서류가방" , 100000);
System.out.println("---------형변환전------------");
Child_A.goToWork();
Child_A.goToPCRoom();
Child_A.buyBranch(50000);
System.out.println("---------Child------------");
Child_B.goToWork();
Child_B.buyBranch(50000);
Child_B.goToPCRoom();
System.out.println("---------Sister------------");
Child_C.goToWork();
Child_C.buyBranch(50000);
// Child_C.goToPCRoom();
System.out.println("---------Parent------------");
Parent Not_Child_A = (Parent)Child_A;
Parent Not_Child_B = (Parent)Child_B;
Parent Not_Child_C = (Parent)Child_C;
System.out.println("---------형변환후------------");
Not_Child_A.goToWork();
// Not_Child_A.goToPCRoom();
Not_Child_A.buyBranch(50000);
}
}
package Package001;
public class Parent {
//필드
public String bagName;
public int money;
//생성자
public Parent(String input_bagName, int input_money) {
this.bagName = input_bagName;
this.money = input_money;
}
//메소드
public void goToWork() {
System.out.println("나는 회사에 출근합니다");
}
public boolean buyBranch(int cost){
if(cost < this.money){
System.out.println("사먹을수있습니다");
return true;
} else {
System.out.println("사먹을수없습니다");
return false;
}
}
}
package Package001;
//Parent상속받음
public class Child extends Parent {
public Child(String input_bagName, int input_money){
super(input_bagName, input_money);
}
//부모메소드 재정의
@Override
public void goToWork() {
System.out.println("나는학교에출근합니다");
}
public void goToPCRoom(){
System.out.println("나는PC방에갑니다");
}
}
package Package001;
public class Sister extends Parent {
public Sister(String input_bagName, int input_money){
super(input_bagName, input_money);
}
//부모메소드 재정의
@Override
public void goToWork() {
System.out.println("나는학교에출근합니다");
}
public void goToPCRoom(){
System.out.println("나는PC방에갑니다");
}
}
매개변수의 다형성
-참조형매개변수는 메소드 호출시 자신과 같은타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다
-인스턴스를 넘겨줄수있다.
package sample;
public class Sample
{
public static void main(String[] args)
{
Buyer a = new Buyer();
a.Buy(new Tv());
a.Buy(new Audio());
a.Buy(new Computer());
a.summary();
}
}
class Product
{
int price;
int bonusPoint;
Product(int price)
{
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product
{
Tv()
{
super(100);
}
public String toString()
{
return "Tv";
}
}
class Computer extends Product
{
Computer()
{
super(200);
}
public String toString()
{
return "Computer";
}
}
class Audio extends Product
{
Audio()
{
super(80);
}
public String toString()
{
return "Audio";
}
}
class Buyer
{
int money = 400;
int bonusPoint;
Product[] a = new Product[10];
int i;
void Buy(Product p)
{
if(money < p.price)
{
System.out.println("잔액이 부족하여 구매할 수 없습니다");
}
money -= p.price;
bonusPoint += p.bonusPoint;
a[i++] = p;
System.out.println(p + " 를 구매했습니다");
System.out.println("남은 금액은 " + money + " 입니다");
}
void summary()
{
int i;
String total = "";
for( i=0; i<a.length; i++)
{
if(a[i]==null) break;
total += (i==0) ? "" + a[i]: "," + a[i];
}
System.out.println("최종 적립포인트는 " + bonusPoint + " 입니다");
System.out.println("최종 구매내역은 " + total + " 입니다");
}
}
출처: https://moalgong.tistory.com/24 [모알공 - 모르니까 알 때까지 공부!:티스토리]
업캐스팅이란?
업캐스팅은 상속관계은 부모클래스와 자식클래스간의 형변환중의 하나이며,
자식클래스에서 부모클래스로 형변환하는 것을 업캐스팅이라고한다.
업캐스팅의 경우 기본적으로 하위 클래스의 형에서 상위 클래스의 형으로 캐스팅 시키는것이라 형만 정확하다면 묵시적으로 캐스팅이 가능하다.
public class Person {...}
public class Student extends Person {...}
Person human = new Student();
Person이라는 부모클래스와 Student라는 자식클래스가 있는데 Person클래스가 Student의 클래스보다 더 넓은 범위이기 때문에 묵시적으로 형변환이 가능하다.
다운캐스팅이란?
public class Person {...}
public class Student extends Person {...}
Person human= new Student(); //업캐스팅
Student gilDong = (Student)human; //다운캐스팅
예제처럼 human이라는 Person형 객체를 업캐스팅을 통하여 만들어주었고, human을 다시 Student형 객체로 다운캐스팅을 하여 gilDong이라는 Student형 객체를 만들어주었습니다.
출처: https://sundrystore.tistory.com/17 [잡다창고:티스토리]
이미지 출처 : 이것이자바다
'STUDY > JAVA' 카테고리의 다른 글
[JAVA] 22-07-01 인터페이스 ☑ (0) | 2022.07.01 |
---|---|
[JAVA] 22-06-30 추상클래스 ☑ (0) | 2022.06.30 |
[JAVA] 22-06-28 상속을 이용해 샌드위치 만들기 문제 ☑ (0) | 2022.06.28 |
[JAVA] 22-06-28 final / protected 접근제한자 ☑ (0) | 2022.06.28 |
[JAVA] 메소드 재정의, 상속 등을 이용해 게임 만들기 (0) | 2022.06.27 |