전체 방문자
오늘
어제
21종
종이의 코딩 공부방
21종
  • 분류 전체보기 (171)
    • JAVA (64)
    • Springboot (46)
      • 블로그만들기 (45)
    • Database (60)
      • Oracle (60)
    • 프로젝트 3 (CELOVER) (0)
    • 개발서버 구축 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 글

최근 댓글

hELLO · Designed By 정상우.
21종

종이의 코딩 공부방

JAVA

[자바/JAVA] 프로그래밍 - 다형성 (Polymorphism)

2023. 6. 13. 19:24

 

// 기억해둘 것 !! '=' 기준으로 해서 왼쪽과 오른쪽의 자료형(타입)은 같아야 됨

System.out.println("1. 부모타입 레퍼런스로 부모객체를 다루는 경우");
Parent p1 = new Parent();
p1.printParent();
// p1 레퍼런스로 Parent 에만 접근 가능

System.out.println("2. 자식타입 레퍼런스로 자식객체를 다루는 경우");
Child1 c1 = new Child1();
c1.printChild1();
c1.printParent();	// 자동형변환 된거였음!! (Child1 => Parent)
// ((Parent)c1).printParent();
// c1 레퍼런스로 Child1, Parent 둘다 접근 가능
// Parent 접근시 자동으로 형변환된 채로 진행된거임

System.out.println("3. 부모타입 레퍼런스로 자식객체를 다루는 경우(다형성)");
Parent p2 = /*(Parent)*/new Child1();	// 자료형이 다르다 ? => 에러안뜸! => 자동형변환 된거임
p2.printParent();
// p2.printChild();	=> 안됨
((Child1)p2).printChild1(); // 강제 형변환을 하면 호춣은 가능!!

// p2 레퍼런스로 지금 당장은 Parent에만 접근 가능하지만
// Child1에 접근하고자 한다면 강제형변환을 하면 접근은 가능!!

빨간색 빗금 친 부분만 접근 가능


상속 구조의 클래스들 간에는 형변환 가능

1. UpCasting

자식타입 -> 부모타입 형변환
자동형변환
 ex) 자식.부모메소드();

 2. DownCasting

 부모타입 -> 자식타입 형변환
 강제형변환
 ex) ((자식)부모).자식메소드();

String str = (String)new Child1(); 상속구조 아니면 안된다.

Child1 Class

package com.kh.chap01_poly.part01_basic.model.vo;

public class Child1 extends Parent {
	
	private int z;
	
	public Child1() {
		super();	// 생략돼있음. 부모 기본 생성자가 없어지면 오류남
	}
	
	public Child1(int x, int y, int z) {
		super(x,y);
		this.z = z;
	}
	
	public int getZ() {
		return z;
	}
	
	public void setZ(int z) {
		this.z = z;
	}

	public void printChild1() {
		System.out.println("나 첫번째 자식이야");
	}
	
	@Override
	public void print() {
		System.out.println("나 첫번째 자식이야");
	}

}

Child2 Class

package com.kh.chap01_poly.part01_basic.model.vo;

public class Child2 extends Parent {
	
	private int n;
	
	public Child2() {
		
	}
	
	public Child2(int x, int y, int n) {
		super(x,y);
		this.n = n;
	}
	
	public int getN() {
		return n;
	}
	
	public void setN(int n) {
		this.n = n;
	}
	
	public void printChild2() {
		System.out.println("나 두번째 자식이야");
	}

	@Override
	public void print() {
		System.out.println("나 두번째 자식이야");
	}
}

Parent Class

package com.kh.chap01_poly.part01_basic.model.vo;

public class Parent {
	private int x;
	private int y;
	
	public Parent() {
		
	}
	
	public Parent(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public int getX() {
		return x;
	}
	
	public void setX(int x) {
		this.x = x;
	}
	
	public int getY() {
		return y;
	}
	
	public void setY(int y) {
		this.y = y;
	}
	
	public void printParent() {
		System.out.println("나 부모야");
	}
	
	public void print() {
		System.out.println("나 부모야");
	}

}

PolyRun Class

package com.kh.chap01_poly.part01_basic.run;

import com.kh.chap01_poly.part01_basic.model.vo.Child1;
import com.kh.chap01_poly.part01_basic.model.vo.Child2;
import com.kh.chap01_poly.part01_basic.model.vo.Parent;

public class PolyRun {

	public static void main(String[] args) {
		
		// 다형성 정의 
		// - 부모타입으로 부터 파생된 여러가지 타입의 자식 객체들을 부모클래스 타입 하나로도 다룰 수 있다.
		
		// 다형성을 쓰는 목적
		
		// 다형성을 배우기전..
		Child1[] arr1 = new Child1[2];
		arr1[0] = new Child1(1, 2, 4);
		arr1[1] = new Child1(2, 3, 5);
		
		Child2[] arr2 = new Child2[2];
		arr2[0] = new Child2(2, 1, 5);
		arr2[1] = new Child2(5, 7, 2);
		
		// -----------------------------------------------------------
		// 다형성(부모타입 레퍼런스)을 적용한 후..
		Parent[] arr = new Parent[4];
		// Parent 타입
		arr[0] = new Child1(1, 2, 4);
		arr[1] = new Child2(2, 1, 5);
		arr[2] = new Child1(2, 3, 5);
		arr[3] = new Child2(5, 7, 2);
		// 하나의 부모타입만으로 여러 자식 객체들을 받을 수 있음 => 편리하다, 코드길이 감소
		
		System.out.println("===================================");
//		arr[0].printChild1();	=> 안된다.
		((Child1)arr[0]).printChild1();
//		arr[1].printChild2();	=> 안된다.
		((Child2)arr[1]).printChild2();
		((Child1)arr[2]).printChild1();
//		((Child2)arr[2]).printChild2();		// ClassCastException : 부적절한 형변환
		
		// arr[3]
		((Child2)arr[3]).printChild2();
		
		System.out.println("======== 반복문 이용해서 출력 =========");
		for(int i = 0; i < arr.length; i++) {
			/*
			 * instanceof 연산자 => 연산결과 true / false 변환
			 * 현재 레퍼런스가 실질적으로 어떤 클래스 타입을 참조하는지 확인할 때 사용
			 */
			/*if(i == 0 || i == 2) {*/
			if(arr[i] instanceof Child1) {	// 해당 레퍼런스가 실제 Child1 참조하고 있다면 true 아니면 false
				((Child1)arr[i]).printChild1();
			}else {
				((Child2)arr[i]).printChild2();
			}
		}	// 양다리 => 공유 : 연상(오빠) , 차은우 : 연하(은우야) 
		
		Parent pp = new Child1();
		pp.print();
		/*
		 * 동적바인딩 : 프로그램이 실행되기 전에는 컴파일이 되면서 정적바인딩(레퍼런스 타입의 메소드를 가리킴)
		 * 			단, 실질적으로 참조하는 자식클래스에 해당메소드가 오버라이딩 돼있다면 
		 * 			프로그램 실행시 동적으로 그 자식클래스의 오버라이딩 된 메소드를 찾아서 실행
		 * 
		 */
		
		System.out.println("==================================");
		for(int i = 0; i < arr.length; i++) {
			arr[i].print();
		}
	}
}

실행 결과


제대로 다형성 사용 전 후 비교해보자


공통된 Class

 

Electronic Class

package com.kh.chap01_poly.part02_electronic.model.vo;

public class Electronic {
	
	private String brand;
	private String name;
	private int price;
	
	public Electronic() {
		
	}
	
	public Electronic(String brand, String name, int price) {
		this.brand = brand;
		this.name = name;
		this.price = price;
	}
	
	public String getBrand() {
		return brand;
	}
	
	public void setBrand(String brand) {
		this.brand = brand;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getPrice() {
		return price;
	}
	
	public void setPrice(int price) {
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "brand : " + brand + ", name : " + name + ", price : " + price;
	}

}

Desktop Class

package com.kh.chap01_poly.part02_electronic.model.vo;

public class Desktop extends Electronic {
	
	public static final String CPU = "intel";
	private String graphic;
	
	public Desktop() {
		
	}
	
	public Desktop(String brand, String name, int price, String graphic) {
		super(brand, name, price);
		this.graphic = graphic;
	}
	
	public String getGraphic() {
		return graphic;
	}
	
	public void setGraphic(String graphic) {
		this.graphic = graphic;
	}
	
	@Override
	public String toString() {
		return super.toString() + ", graphic : " + graphic;
	}

}

NoteBook Class

package com.kh.chap01_poly.part02_electronic.model.vo;

public class NoteBook extends Electronic {
	
	private int usbPort;
	
	public NoteBook() {
		
	}
	
	public NoteBook(String brand, String name, int price, int usbPort) {
		super(brand, name, price);
		this.usbPort = usbPort;
	}
	
	public int getUsbPort() {
		return usbPort;
	}
	
	public void setUsbPort(int usbPort) {
		this.usbPort = usbPort;
	}
	
	@Override
	public String toString() {
		return super.toString() + ", usbPort : " + usbPort;
	}
	
}

Tablet Class

package com.kh.chap01_poly.part02_electronic.model.vo;

public class Tablet extends Electronic {

	private boolean penFlag;
	
	public Tablet() {
		
	}
	
	public Tablet(String brand, String name, int price, boolean penFlag) {
		super(brand, name, price);
		this.penFlag = penFlag;
	}
	
	public boolean isPenFlag() {
		return penFlag;
	}
	
	public void setPenFlag(boolean penFlag) {
		this.penFlag = penFlag;
	}
	
	@Override
	
	public String toString() {
		return super.toString() + ", penFlag : " + penFlag;
	}

}

다형성 적용 전

 

ElectronicShop1 Class

package com.kh.chap01_poly.part02_electronic.controller;

import com.kh.chap01_poly.part02_electronic.model.vo.Desktop;
import com.kh.chap01_poly.part02_electronic.model.vo.NoteBook;
import com.kh.chap01_poly.part02_electronic.model.vo.Tablet;

// 다형성 적용 안했을 때 !!!
public class ElectronicShop1 {

	// 용산 전자상가에 있는 가게
//	private int price; // 기본 자료형
	
	// 3개 제품을 마련할 자리부터 만들자
	private Desktop desk;	// 내가 만든 자료형
	private NoteBook note;	// 객체 생성은 안되고 텅 비어있음
	private Tablet tab;
	
	// 이건 실제로 객체 생성 된 것은 아님
	// 필드가 메모리상에 확보되는 순간 => 객체가 생성되는 순간!!!
	public void insert(Desktop d) {	// Desktop d = new Desktop(~~~);
		desk = d;
	}
	public void insert(NoteBook n) {	// Notebook n = new NoteBook(~~~);
		note = n;
	}
	
	public void insert(Tablet t) {	// Tablet t = new Tablet(~~~);
		tab = t;
	}
	
	// 동일한 클래스에 동일한 메소드 명으로 여러개 만들어져있는 것 => 오버로딩
	// 단, 매개변수 명은 달라야한다!!
	// 오버로딩이 적용 돼 있음
	
	// 조회
	// 모르겠으면 일단은 반환병을 void 가자 => 나중에 수정 가능!
	public Desktop selectDesktop() {
		return desk;
	}
	
	public NoteBook selectNoteBook() {
		return note;
	}
	
	public Tablet selectTablet() {
		return tab;
	}
	
	// insert 처럼 select도 같은 이름으로 하면 안되는 이유는?
	// 매개변수가 없기 때문에 불가능함!! => 오류남
	
	// 현재는 메소드가 총 6개 !!
	// 다형성 적용하면? 2개~3개로 줄이기 가능!!
}

실행 Class

package com.kh.chap01_poly.part02_electronic.run;

import com.kh.chap01_poly.part02_electronic.controller.ElectronicShop1;
import com.kh.chap01_poly.part02_electronic.model.vo.Desktop;
import com.kh.chap01_poly.part02_electronic.model.vo.NoteBook;
import com.kh.chap01_poly.part02_electronic.model.vo.Tablet;

public class Run {

	public static void main(String[] args) {

		// 실행용 클래스는 납품업체라 생각!
		
		// 1. 다형성 적용 안했을 경우(ElectronicShop1)
		
		ElectronicShop1 es = new ElectronicShop1();
		// es에서 마련해놓은 desk, note, tab이라는 필드에
		// 객체를 생성해서 넣어주기 위해서 우선 es 생성!!
		
		// 메소드를 써서 생성하겠음
		// 먼저 필요한 메소드를 생각해보자
		
		// 아직은 없는 메소드
		// 추가용 메소드 => insert
		// 데스크탑 이라는 객체를 생성해서 넘기는 메소드
		
		es.insert(new Desktop("samsung", "데땁", 1200000, "gtx1070"));
		
		// 노트북이라는 객체를 생성해서 넘기는 메소드
		es.insert(new NoteBook("LG", "그램", 2000000, 4));
		
		// 태블릿 이라는 객체를 생성해서 넘기는 메소드
		es.insert(new Tablet("Apple", "아이패드", 800000, false));
		
		// 가게에 해당 객체들이 잘 생성돼있는지를 확인해보자
		// 조회용 메소드 => select();
		
		// String desk = es.selectDesktop();
		Desktop d = es.selectDesktop();
		NoteBook n = es.selectNoteBook();
		Tablet t = es.selectTablet();
		
		System.out.println(d);
		System.out.println(n);
		System.out.println(t);
		
	}
	
}

실행 결과


다형성 적용 후

 

ElectronicShop2 Class

package com.kh.chap01_poly.part02_electronic.controller;

import com.kh.chap01_poly.part02_electronic.model.vo.Electronic;

// 다형성 개념을 적용했을때 !!
public class ElectronicShop2 {
	// 자리를 마련하자
	// 다형성 : 부모타입 레퍼런스 하나로 다양한 자식객체를 담을 수 있음!!
	
	// 부모 : Electonic
	// 자식 : Desktop, noteBook, Tablet
	
	// Parrent[] arr = new Parent[4];
	// Parent 타입
	// arr[0] = new Child1(1,2,4)
	// arr[1] = new child2(1,2,4)
	
	// 부모타입 배열로 모든 자식 객체 다루기
	private Electronic[] elec = new Electronic[3];
	private int count = 0;
	
	// inset 함수 구현
	// 매개변수 => Desktop, NoteBook, Tablet 전부 다 받을 수 있는 부모 Electronic 으로 생성
	
	public void insert(Electronic any) {
		elec[count++] = any;
	}	
	// 맨처음 => count : 0 이었을 경우
	// any = new Desktop(~~~)
	// elec[0] = new Desktop(~~~); 이거 실행하고 count 1
	
	// 그다음 => count : 1 이었을 경우 
	// any = new NoteBook(~~~)
	// elec[1] = new NoteBook(~~~); 이거싱행하고 count 2
	
	// 그다음 => count : 2 이었을 경우
	// any = new Tablet(~~~);
	// elec[2] = new Tablet(~~~); 이거 실행하고 count 3
	
	public Electronic select(int index) {
		// Desktop => elec[0];
		// NoteBook => elec[1];
		// Tablet => elec[2];
		return elec[index];
	}
	
}

실행 Class

package com.kh.chap01_poly.part02_electronic.run;

import com.kh.chap01_poly.part02_electronic.controller.ElectronicShop2;
import com.kh.chap01_poly.part02_electronic.model.vo.Desktop;
import com.kh.chap01_poly.part02_electronic.model.vo.Electronic;
import com.kh.chap01_poly.part02_electronic.model.vo.NoteBook;
import com.kh.chap01_poly.part02_electronic.model.vo.Tablet;

public class Run {

	public static void main(String[] args) {

		// 실행용 클래스는 납품업체라 생각!
		
		// 2. 다형성 적용 했을 경우 (ElectronicShop2)
		ElectronicShop2 es = new ElectronicShop2();
		
		// 추가용 메소드 => insert
		es.insert(new Desktop("samsung", "데땁", 1200000, "gtx1070"));
		es.insert(new NoteBook("LG", "그램", 2000000, 4));
		es.insert(new Tablet("Apple", "아이패드", 800000, false));
		
		// 조회용 메소드 => select
		// 이번에는 이름을 하나로 !!
		// es.select(인덱스값);
		//	Desktop d = es.select(0);
		// 실제로 들어있는 값은 Desktop 객체가 맞으나 반환형이 Electronic 이라서 맞춰줘야함!! => 강제형변환
		
        /*
		Desktop d = (Desktop)es.select(0);
		NoteBook n = (NoteBook)es.select(1);
		Tablet t = (Tablet)es.select(2);
		*/
		Electronic d = es.select(0);
		Electronic n = es.select(1);
		Electronic t = es.select(2);
		
		// 이런걸 다운캐스팅 이라고 한다!!!
		
		// 위아래 방법 둘다 가능
		
		// 그럼 toString() 할 때 부모에 있는 toString을 불러오지 않을까?
		// 아님 => 왜?? 동적바인딩 !!

		System.out.println(d);
		System.out.println(n);
		System.out.println(t);
	
	}
	
}

실행 결과


다형성을 사용하는 이유

1. 부모타입 배열로 다양한 자식객체들을 받을 수 있음
2. 메소드 정의시 매개변수로 다형성을 적용하게 되면 메소드 개수가 확 줄어든다!!
3. 필수로 써야하는 곳이 있음  => 추상클래스(인터페이스)

    'JAVA' 카테고리의 다른 글
    • [자바/JAVA] 프로그래밍 - 다형성 (Polymorphism) - 추상(abstract) - Interface
    • [자바/JAVA] 프로그래밍 - 다형성 (Polymorphism) - 추상(abstract)
    • [자바/JAVA] 프로그래밍 - 상속 (inheritance) 실습 문제_2
    • [자바/JAVA] 프로그래밍 - 상속 (inheritance) 실습 문제_1
    21종
    21종
    코딩 공부한 것 정리하려고 만든 블로그

    티스토리툴바