본문으로 바로가기
반응형

 

 

 

지난 포스팅에서 상속에 대해 다뤄봤습니다.

 

 

 

 

 

이번 포스팅에서는 자바의 다형성에 대해서 다뤄보고자 합니다.

 

 

 


 

 

먼저 다형성이란,,

 

 

 

 

객체지향 프로그래밍의 3대 특징 중 하나로서,


‘여러 개의 형태를 갖는다’는 의미로
하나의 행동으로 여러 가지 일을 수행하는 개념을 말합니다.

 


상속을 이용해 부모 타입으로부터 파생된 여러 가지 타입의 자식 객체를
부모 클래스 타입 하나로 다룰 수 있는 기술입니다.

 

 

 

 

 

 

 

그림으로 보면 아래와 같습니다.

 

 

 

 

원과 삼각형 객체가 도형을 참조하고 있죠.

 

그 말은 서로의 속성들을 사용할 수 있다는 말입니다.

 

 

 

 

 

 

 

 

 


클래스 형변환


 

 

 

클래스 형변환에는 두 가지가 있습니다.

 

 

업 캐스팅과  다운 캐스팅이 있는데요.

 

둘 다 알아봅시다.

 

 

 

 

 

● 업 캐스팅

 

 

  먼저 업캐스팅이란,,

 

 

상속 관계에 있는 부모, 자식 클래스 간에 부모타입의 참조형 변수가
모든 자식 타입의 객체 주소를 받을 수 있음을 의미합니다.

 

 

 

 

 

아래 예를 살펴보면,,

 

 

 

 

 

Car이라는 부모클래스가 있고,

그것의 후손 클래스인 Sonata 클래스가 있다고 합시다.

 

 

이때 c라는 car클래스의 참조 변수를 생성했다고 해봅시다.

 

 

이 참조형 변수 c에는 Sonata 객체가 생성되었지만,  Car의 속성들을 사용할 수 있습니다,

 

 

※ 이떄, 자식 객체의 주소를 전달받은 부모타입의 참조변수를 통해서

사용할 수 있는 후손의 정보는

원래 부모타입이었던 멤버만 참조 가능합니다.

 

 

 

 

● 다운 캐스팅

 

 

 

  다운 캐스팅이란,,

 

 

자식 객체의 주소를 받은 부모 참조형 변수를 가지고 자식의 멤버를 참조해야 할 경우, 

 

부모 클래스 타입의 참조형 변수

자식 클래스 타입으로 형 변환하는 것을 말합니다.

 

 


이떄, 자동으로 처리되지 않기 때문에 반드시 후손 타입 명시해서 형 변환해야 합니다.

 

 

 

 

 

예시를 살펴보면,,

 

 

 

Car 형태의 참조형 변수 c를 생성하고, 

Sonata 객체를 생성하였을때,

 

 

 

이때 Sonata 클래스에만 있는 moveSonata 메소드를 사용하고자 한다면,

((Sonata) c) 이런식으로 다운캐스팅을 해줘야 한다는 말이죠.

 

 

 

 

이때, 클래스 간의 형 변환은 반드시 상속 관계에 있는 클래스끼리만 가능합니다.

 

 

 

 

 

 

 

 

 

 


객체배열과 다형성


 

 

 

 

다형성을 이용하여 

 

상속 관계에 있는 하나의 부모 클래스 타입의 배열 공간에

여러 종류의 자식 클래스 객체 저장 가능합니다. 

 

 

 

 

 

 

 

 

 

 


매개변수와 다형성


 

 

 

 

다형성을 이용하여 메소드 호출 시 

부모타입의 변수 하나만 사용해 자식 타입의 객체를 받을 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 


instanceof 연산자


 

 

 

 

instanceof 연산자란,,

 

 

현재 참조형 변수가 어떤 클래스 형의 객체 주소를 참조하고 있는지

확인 할 때 사용하는 연산자로 

 

클래스 타입이 맞으면 true, 맞지 않으면 false 반환합니다.

 

 

 

 

쉽게 말해 해당 클래스의 속성인지 비교하는 것과도 비슷한 맥락입니다.

 

 

 

 

위를 간단히 설명하자면

 

c라는 Car의 참조형 변수가 가르키는 객체가 

Sonata객체인지,  Avante 객체인지,  Grandure 객체인지를 물어보는 것입니다.

 

 

크게 어렵지 않죠.

 

 

 

 

 

 

 

 

 


바인딩


 

 

 

 

바인딩이란,,

 

실제 실행할 메소드 코드와 호출하는 코드를 연결 시키는 것으로,


프로그램이 실행되기 전에 컴파일이 되면서 모든 메소드정적 바인딩 됩니다.

 

 

 

 

 

 

 

 ● 동적 바인딩

 

 

 

컴파일 시 정적 바인딩된 메소드를 실행할 당시의 

객체 타입을 기준으로 바인딩 되는 것을 말합니다.

 

 

 

 

 

 

 

 

 

 ● 동적 바인딩 성립 요건

 

 

 

상속 관계로 이루어져 다형성이 적용된 경우, 

메소드 오버라이딩이 되어 있으면 정적으로 바인딩 된 메소드 코드보다
오버라이딩 된 메소드 코드를 우선적으로 수행됩니다.

 

 

 

 

 

 

 

 

 


추상 클래스


 

 

 

 

 

● 추상 클래스

 

 

 

몸체 없는 메소드를 포함한 클래스로,


추상 클래스일 경우 클래스 선언부에 abstract 키워드 사용합니다.

 

 

ex)  [접근제한자] abstract class 클래스명 {}

 

 

 

 

 

 

 

 

  • 추상 클래스의 특징

 

  •   1. 미완성 클래스(abstract 키워드 사용)
          자체적으로 객체 생성 불가 → 반드시 상속하여 객체 생성
  •   2. abstract 메소드가 포함된 클래스는 반드시 abstract 클래스
          abstract 메소드가 없어도 abstract 클래스 선언 가능
  •   3. 클래스 내에 일반 변수, 메소드 포함 가능
  •   4. 객체 생성은 안되지만 참조형 변수 타입으로는 사용 가능

 

 

 

 

 

 

 

  • 추상 클래스의 장점

 

  • 일관된 인터페이스 제공
    꼭 필요한 기능 강제화(공통적이나 자식클래스에서 특수화 되는 기능)

 

 

 

 

 

 

 

● 추상 메소드

 

 

 

몸체 없는 메소드로,
추상 메소드의 선언부에 abstract 키워드 사용합니다.


상속 시 반드시 구현해야 하는, 오버라이딩이 강제화되는 메소드입니다.

 

 

 

ex)  [접근제한자] abstract 반환형 메소드명(자료형 변수명);

 

 

 

 

 

 

 

 

 

 

 

 


인터페이스


 

 

 

인터페이스란,,

 

 

상수형 필드와 추상 메소드만을 작성할 수 있는 추상 클래스의 변형체입니다.

 


메소드 통일성을 부여하기 위해 추상 메소드만 따로 모아놓은 것으로
상속 시 인터페이스 내에 정의된 모든 추상메소드를 구현해야 합니다.

 

 

 

 

 

 

 

 

 

 

 

  • 인터페이스 특징

 

  • 1. 모든 인터페이스의 메소드는 묵시적으로 public이고 abstract
  • 2. 변수는 묵시적으로 public static final,
    따라서 인터페이스 변수의 값 변경 시도 시 컴파일 시 에러 발생
  • 3. 객체 생성은 안되나 참조형 변수로는 가능

 

 

 

 

 

 

 

 

 

  • 인터페이스 장점

 

     - 상위 타입 역할로 다형성을 지원하여 연결
     - 해당 객체가 다양한 기능 제공 시에도 인터페이스에 해당하는
     - 기능만을 사용하게 제한 가능
     - 공통 기능 상의 일관성 제공
     - 공동 작업을 위한 인터페이스 제공

 

 

 

 

 

 

 

 

 

다음은 추상클래스와 인터페이스 비교입니다.

 

 

 

 

각 구분에 따라

 

차이를 인지하시길 바랍니다.

 

 

 

 

 

 


 

 

 

 

 

 

 

 

이제 다형성의 예제를 풀어봅시다.

 

 

 

 

 

 

 


자바 다형성  예제


 

 

 

 

 

난이도 ★

 

 

 

예제 1

 

 

Q : 다음 요구사항을 보고 프로그램을 작성하여라

 

 

  ●  1. 페이지 인터페이스 생성
           a. read()
       
       2. 페이지 인터페이스를 상속하여 책 클래스 생성
           a. 전체 페이지 번호, 현재 페이지 번호 속성을 정의
           b. page(), next(), prev() 메서드 정의
       
       3. 책 클래스를 상속하여 소설, 만화, 잡지 클래스 정의
           a. 책이름, 출판사
           b. 소설은 read() 구현할 때 "글자를 읽습니다." 로 구현
              만화는 read() 구현할 때 "그림을 봅니다." 로 구현
              잡지는 read() 구현할 때 "그림과 글자를 보고 읽습니다." 로 구현
          
       4. 소설 클래스에는 다음의 내용을 추가 구현
           a. 장르, 작가 속성 
           b. search() 구현
       
       5. 만화 클래스에는 다음의 내용을 추가 구현
           a. 글작가, 그림작가, 연령 제한 속성
       
       6. 잡지 클래스에는 다음의 내용을 추가 구현
           a. 에디터, 종류 속성
           b. QRCapture() 구현

 

 

 

     최종: toString() 을 오버라이딩 하여 책의 모든 정보가 출력 될 수 있도록 한다.
             형식은 다음과 같이 한다.

 

  ex)
      소설책 [제목:해리포터 마법사의 돌 1, 출판사:문학수첩, 장르:판타지, 작가:J.K 롤링, 총페이지:268, 현                  재페이지:0]
      코믹스 [제목:원피스, 출판사:대원, 글작가:오다에이치로, 그림작가:오다에이치로, 연령제한:12세, 총페                  이지:192, 현재페이지:0]
// 잡지 [제목:에스콰이어, 출판사:허스트중앙, 에디터:에스콰이어편집부, 종류:여성/남성 총페이지:156, 현재페이지:0]
 

 

 

       

 

 

 

 


 

 

 

Page 인터페이스

package com.kh.exam15;

public interface Page {
	// public abstract 생략 가능
	void read();
}

 

 

 

Book 클래스(추상)

package com.kh.exam15;

public abstract class Book implements Page {
	private int totalPageNum;
	private int currentPageNum;
	
	public Book(int totalPageNum) {
		this.totalPageNum = totalPageNum;
	}
	
	public void page(int pageNum) {
		this.currentPageNum = pageNum;
	}
	
	public void next() {
		this.currentPageNum++;
	}
	
	public void prev() {
		this.currentPageNum--;
	}
	
	public int getTotalPageNum() {
		return totalPageNum;
	}

	public int getCurrentPageNum() {
		return currentPageNum;
	}

	@Override
	public void read() {
		System.out.println("책을 읽습니다.");
	}

	@Override
	public String toString() {
		return ", 총페이지 : " + totalPageNum + ", 현재 페이지 : " + currentPageNum + "]";
	}

	
}

 

 

 

Comics 클래스

package com.kh.exam15;

public class Comics extends Book{
	private String name;
	private String company;
	private String writer;
	private String illuster;
	private int limitAge;
	
	public Comics(String name, String company, String writer, String illuster, int limitAge, int totalPageNum) {
		super(totalPageNum);
		this.name = name;
		this.company = company;
		this.writer = writer;
		this.illuster = illuster;
		this.limitAge = limitAge;
	}
	
	@Override
	public void read() {
		System.out.println("'" + this.name + "' 만화를 읽습니다.");
	}

	@Override
	public String toString() {
		if(limitAge<20) {
			return "만화책 [제목 : " + name + "], 출판사 : " + company + ", 글 작가 : " + writer + ", 그림 작가 : " + illuster
					+ ", 연령제한 : " + limitAge + "세 미만" + super.toString();
		}else {
			return "만화책 [제목 : " + name + ", 출판사 : " + company + ", 글 작가 : " + writer + ", 그림 작가 : " + illuster
					+ ", 연령제한 : " + limitAge + "세 이상" + super.toString();
		}
	}
	
	
	
}

 

 

 

 

Novel 클래스

package com.kh.exam15;

public class Novel extends Book {
	private String name;
	private String company;
	private String genre;
	private String writer;
		
	public Novel(String name, String company, String genre, 
				String writer,int totalPageNum) {
		super(totalPageNum);
		this.name = name;
		this.company = company;
		this.genre = genre;
		this.writer = writer;
	}

	@Override
	public void read() {
		System.out.println("'" + this.name + "' 소설을 읽습니다.");
	}
	
	public void search(String search) {
		System.out.println(search + " 내용을 '" + 
						this.name + "' 소설에서 검색합니다.");
	}

	@Override
	public String toString() {
		return "소설책 [제목 : " + name + ", 출판사 : " + company + ", 장르 : " + genre + ", 작가 :" + writer
				+ super.toString();
	}
	
	
}

 

 

 

 

 

Magazine 클래스

package com.kh.exam15;

public class Magazine extends Book {
	private String name;
	private String company;
	private String editor;
	private String type;
	
	public Magazine(String name, String company, String editor, String type,int totalPageNum) {
		super(totalPageNum);
		this.name = name;
		this.company = company;
		this.editor = editor;
		this.type = type;
	}
	
	@Override
	public void read() {
		System.out.println("'" + this.name + "' 잡지를 읽습니다.");
	}

	public void QRCapture() {
		System.out.println("QR 캡처로 해당 상품 구매 페이지로 이동할 수 있습니다.");
	}

	@Override
	public String toString() {
		return "잡지 [제목 : " + name + ", 출판사 : " + company + ", 에디터 : " + editor + ", 종류 : " + type
				+ super.toString();
	}

	
	
}

 

 

 

 

 

 

 

Sample 클래스(main 함수 포함)

 

package com.kh.exam15;

public class Sample1 {

	public static void main(String[] args) {
		Book[] books = new Book[5];
		books[0] = new Novel("해리포트 불의 잔", "문학수첩", "판타지", "J.K 롤링", 268);
		books[1] = new Comics("원피스 98", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		books[2] = new Magazine("에스콰이어", "허스트중앙", "에스콰이어 편집부", "여성/남성", 82);
		books[3] = new Novel("해리포트 마법사의 돌", "문학수첩", "판타지", "J.K 롤링", 244);
		books[4] = new Comics("원피스 97", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		
		for(Book b: books) {
			System.out.println(b);
		}
		
	}

}

 

 

 


 

 

 

 

 

난이도 ★

 

 

 

예제 2

 

 

Q : 위의 Book 배열 객체에서 소설책, 코믹스, 잡지를 분류하고 분류된 객체를 각 배열
     (Novel 배열, Comics 배열, Magazine 배열)로 이동 시킨다.
     동적 배열이 어려우면 정적 배열로 만들어서 진행해도 됨.

 

 

 

 

 

 

 

 


 

 

나머지 클래스는 위와 동일

 

 

Sample1 클래스(main 포함)

package com.kh.exam15;

import java.util.Arrays;

public class Sample1 {

	public static void main(String[] args) {
		
		
		Book[] books = new Book[5];
		books[0] = new Novel("해리포터 마법사의 돌 1", "문학수첩", "판타지", "J.K 롤링", 268);
		books[1] = new Comics("원피스 98", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		books[2] = new Magazine("에스콰이어", "허스트중앙", "에스콰이어편집부", "여성/남성", 156);
		books[3] = new Novel("해리포터 마법사의 돌 2", "문학수첩", "판타지", "J.K 롤링", 244);
		books[4] = new Comics("원피스 97", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		
		for(Book b: books) {
			System.out.println(b);
		}
		
		
		Novel[] novels = null;			int nCnt = 0;
		Comics[] comices = null;		int cCnt = 0;
		Magazine[] magazines = null;	int mCnt = 0;
		for(Book b: books) {
			if(b instanceof Novel) {
				nCnt++;
			} else if(b instanceof Comics) {
				cCnt++;
			} else if(b instanceof Magazine) {
				mCnt++;
			}
		}
		novels = new Novel[nCnt];
		comices = new Comics[cCnt];
		magazines = new Magazine[mCnt];
		nCnt = cCnt = mCnt = 0;
		for(Book b: books) {
			if(b instanceof Novel) {
				novels[nCnt++] = (Novel)b;
			} else if(b instanceof Comics) {
				comices[cCnt++] = (Comics)b;
			} else if(b instanceof Magazine) {
				magazines[mCnt++] = (Magazine)b;
			}
		}
		
		System.out.println(Arrays.toString(novels));
		System.out.println(Arrays.toString(comices));
		System.out.println(Arrays.toString(magazines));
	}

}

 

 

혹은

 

 

package com.kh.exam15;

public class Sample1 {

	public static void main(String[] args) {
		
		Magazine[] mArr = new Magazine[0];
		Comics[] cArr = new Comics[0];
		Novel[] nArr = new Novel[0];

		
		Book[] books = new Book[5];
		books[0] = new Novel("해리포트 불의 잔", "문학수첩", "판타지", "J.K 롤링", 268);
		books[1] = new Comics("원피스 98", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		books[2] = new Magazine("에스콰이어", "허스트중앙", "에스콰이어 편집부", "여성/남성", 82);
		books[3] = new Novel("해리포트 마법사의 돌", "문학수첩", "판타지", "J.K 롤링", 244);
		books[4] = new Comics("원피스 97", "대원", "오다에이이치로", "오다에이이치로", 12, 192);
		
		for(Book b: books) {
			System.out.println(b);
		}

		for(Book b: books) {
			if(b instanceof Magazine) {
				Magazine[] copy = new Magazine[mArr.length + 1];
				for(int i=0; i<mArr.length; i++) {
					copy[i] = mArr[i];
				}
				copy[copy.length - 1] = (Magazine) b;
				mArr = copy;
			}else if(b instanceof Novel) {
				Novel[] copy = new Novel[nArr.length + 1];
				for(int i=0; i<nArr.length; i++) {
					copy[i] = nArr[i];
				}
				copy[copy.length - 1] = (Novel) b;
				nArr = copy;
			}else if(b instanceof Comics) {
				Comics[] copy = new Comics[cArr.length + 1];
				for(int i=0; i<cArr.length; i++) {
					copy[i] = cArr[i];
				}
				copy[copy.length - 1] = (Comics) b;
				cArr = copy;
			}
		}
		for(Magazine m: mArr) {
			System.out.println(m);
		}
		for(Comics c: cArr) {
			System.out.println(c);
		}
		for(Novel n: nArr) {
			System.out.println(n);
		}
		
		
	}

}

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

이상 java의 다형성 실습 문제를 마치겠습니다.

 

 

 

 

 

 

다음 포스팅에선 java 기본 API 에대해 다뤄보고자 합니다.

https://healthdevelop.tistory.com/entry/java17

 

[Java] 자바 String 클래스 속성 | Wrapper 클래스 | Date 클래스 | 자바 기본 API | Format 클래스 | (java로

* 필요한 정보는 ctrl + f를 통해 검색하세요.  ex ) ctrl + f -> '문자열 분리' 지난 포스팅에서 다형성에 대해 다뤄봤습니다. 이번 포스팅에서는 자바의 기본 API에 대해서 다뤄보고자 합니다. 자바

healthdevelop.tistory.com

 

 

 

반응형