[Programming]/[Language]

[Java] Ch7. 상속과 다형성 / K-Digital Credit Java / 객체 지향 프로그래밍 기초 / Summary

김파고띠 2022. 3. 19. 14:07

// 09.상속이란 - 1 & 10.상속이란 - 2

 

상속 & 다형성 > 유지 보수, 확장성 있는 시스템 설계 가능

추상 클래스, 인터페이스까지 이어지는 부분

 

| 클래스에서 상속의 의미

새로운 클래스를 정의할 때 이미 구현된 클래스를 상속(inheritance) 받아서

속성이나 기능이 확장되는 클래스를 구현함

 

상위 클래스 : A 클래스 A 클래스가 B 클래스에게 상속한다
= B 클래스가 A 클래스를 상속받는다
하위 클래스 : B 클래스

 

상속하는 클래스 : 상위 클래스, parent class, base class, super class

상속 받는 클래스 : 하위 클래스, child class, derived class, subclass

 

| 상속을 사용하는 경우

상위 클래스는 하위 클래스 보다 일반적인 개념과 기능을 가짐

하위 클래스는 상위 클래스 보다 구체적인 개념과 기능을 가짐

 

포유류
사람

 

class Mammal{

}

 

class Human extends Mammal {

}

 

extends 뒤에는 단 하나의 class만 사용할 수 있음

자바는 single inheritance만을 지원함

 

| 코딩 하기 - 상속을 사용하여 고객관리 프로그램 구현하기

 

고객 등급에 따른 차별화된 서비스를 제공할 수 있다

고객의 등급에 따라 할인율, 적립금이 다르게 적용된다

구현해보자

 

| Customer 클래스

 

멤버 변수 설명
customerID 고객 아이디
customerName 고객 이름
customerGrade 고객 등급
기본 생성자에서 지정되는 기본 등급은 SILVER
bonusPoint 고객의 보너스 포인트
  • 고객이 제품을 구매할 경우 누적되는 보너스 포인트
bonusRatio 보너스 포인트 적립 비율
  • 고객이 제품을 구매할 때 구매 금액의 일정 비율이
보너스 포인트로 적립된다. 이때 계산되는 적립 비율
  • 기본 생성자에서 지정되는 적립 비율은 1%
즉 10,000원 구매 시 100원 적립

 

/// Customer.java ///

 

package inheritance;

 

public class Customer{

 

protected int customerId;

protected String customerName;

protected String customerGrade;

int bonusPoint;

double bonusRatio;

 

public Customer(){

customerGrade = “SILVER”;

bonusRation = 0.01;

}

 

public int calcPrice(int price){

bonusPoint += price * bonusRation;

return price;

}

 

//?

public String showCustomerInfo(){

return customerName + “ 님의 등급은 ” + customerGrade + “ 이고, 적립한 포인트는 ” + bonusPoint + “ 입니다. ”

}



public int getCustomerId(){

return customerId;

}

 

public void setCustomerId(int customerId){

this.customerId = customerId;

}

 

public String getCustomerName(){

return customerName;

}

 

public void setCustomerName(String customerName){

this.customerName = customerName;

}

 

public String getCustomerGrade(){

return customerGrade;

}

 

public void setCustomerGrade(String customerGrade){

this.customerGrade = customerGrade;

}

 

}

 

—-----------—-----------—- 상속이란 - 2

 

| Customer를 상속받아 구현하는 VIPCustomer 클래스

VIPCustomer 클래스의 기능 : 단골고객으로 혜택이 더 다양해짐

제품 구매시 10% 할인

보너스 포인트 5% 적립

담당 상담원 배정

Customer 클래스와 유사하지만, 그보다 더 많은 속성과 기능이 필요



customerID
customerName
customerGrade
bonusPoint
bonusRatio
Customer 클래스
 
agentID
salesRation
VIPCustomer 클래스

 

| protected 예약어

외부 클래스에는 private으로 하위 클래스에서 public의 기능을 구현한 키워드

 

상위 클래스에 protected로 선언된 변수나 메서드는 다른 외부 클래스에서는

사용할 수 없지만 하위 클래스에서는 사용 가능

  • private으로 access modifier이 설정이 되어있으면

상속 클래스라도 사용할 수 없음

> 고로 protected 사용

 

| 접근 제한자(access modifier)의 가시성

 

  외부 클래스 하위 클래스 동일 패키지 내부 클래스
public O O O O
protected X O O O
default
(선언되지 않음)
X X O O
private X X X O

 

/// VIPCustomer.java ///

 

package inheritance;

 

public class VIPCustomer extends Customer{

 

double saleRatio;

private int agentId;

 

public VIPCustomer(){

customerGrade = “VIP”

bonusRatio = 0.05;

saleRatio = 0.1;

 

}

 

}

 

| 테스트 시나리오

일반 고객 1명과 VIP 고객 1명이 있다

일반 고객의 이름은 이순신, 아이디는 10010, 보너스 포인트는 1000점

VIP 고객의 이름은 김유신, 아이디는 10020, 보너스 포인트는 10000점

 

두 고객을 생성하고 이에 대한 고객 정보를 출력해라

 

/// CustomerTest.java ///

 

package inheritance;

 

public class CustomerTest{

 

public static void main(String[] args){

 

Customer customerLee = new Customer();

customerLee.setustomerName(“이순신");

customerLee.setCustomerId(10010);

customerLee.bonusPoint = 1000;

System.out.println(customerLee.showCustomerInfo());

 

VIPCustomer customerKim = new VIPCustomer();

customerKim.setCustomerName(“김유신");

customerKim.setCustomerId(10020);

customerKim.bonusPoint = 10000;

System.out.println(customerKim.showCustomerInfo());

 

}

 

}

 

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

// 11. 상속에서 클래스 생성과정과 형 변환

 

| 하위 클래스가 생성되는 과정

하위 클래스가 생성 될 때 상위 클래스가 먼저 생성 됨

 

상위 클래스의 생성자가 호출되고 하위 클래스의 생성자가 호출 됨

하위 클래스의 생성자에서는 무조건 상위 클래스의 생성자가 호출되어야 함

 

하위 클래스에서 상위 클래스의 생성자를 호출하는 코드가 없는 경우

컴파일러는 상위 클래스 기본 생성자를 호출하기 위한

super( )를 추가함

 

super( )

상위 클래스의 메모리 위치, 참조값을 가지고 있다

super( )을 사용시 상위 클래스의 디폴트(기본) 생성자가 호출된다

 

만약 상위 클래스의 기본생성자가 없는 경우 ( 매개변수가 있는 생성자만 존재 하는경우 )

하위 클래스는 명시적으로 상위 클래스의 생성자를 호출해야 함

 

| 상속에서의 메모리 상태

상위 클래스의 인스턴스가 만저 생성이 되고,

하위 클래스의 인스턴스가 생성 됨

 

< 힙 메모리 >

 

customerId
customerName
customerGrade
bonusPoint
bonusRatio
agentId
salesRatio

 

  1. BLUE_Customer() 생성자 호출 > Customer 클래스의 멤버 변수가 메모리에 생성됨
  2. RED_VIPCustomer() 생성자 호출 > VIPCustomer 클래스의 멤버 변수가 메모리에 생성됨

 

| 상위 클래스로의 묵시적 형 변환(업캐스팅)

상위 클래스 형으로 변수를 선언하고 하위 클래스 인스턴스를 생성할 수 있다

 

하위 클래스는 상위 클래스의 타입을 내포하고 있으므로

상위 클래스로 묵시적 형변환이 가능함

 

상속 관계에서 모든 하위 클래스는 상위 클래스로 묵시적 형 변환이 됨

BUT 그 역은 성립하지 않음



선언된 클래스형
( 상위 클래스형 )
생성된 인스턴스의 클래스형
( 하위 클래스형 )
Customer vc = new VIPCustomer( );

 

| 형 변환에서의 메모리

Customer vc = newVIPCustomer(); 에서 vc가 가리키는 것은?

>

VIPCustomer() 생성자의 호출로 인스턴스는 모두 생성 되었지만

타입이 Customer 이므로 접근 할 수 있는 변수나 메서드는

Customer의 변수와 메서드임

 

| 클래스 계층구조가 여러 단계인 경우 ( = 가능 )

 

Ex) Human은 내부적으로 Primate와 Mammal의 자료형을 모두 내포하고 있음

 

포유류 (Mammal)
호랑이 (Tiger) 영장류 (Priamte)
 
인간 (Human)

 

Primate aHuman =new Human();

Mammal mHuman = new Human();

 

/// CustomerTest2.java ///

 

package inheritance;

 

public class CustomerTest{

 

public static void main(String[] args){;

 

// 하위 클래스 생성자가 생성될 시

VIPCustomer customerKim = new VIPCustomer( 10020, “김유신” );

// customerKim.setCustomerName(“김유신");

// customerKim.setCustomerId(10020);

customerKim.bonusPoint = 10000;

System.out.println(customerKim.showCustomerInfo());

// 메서드 안에 로그를 남기면, 상위 클래스에서 기본 생성자가 생기는 것 확인 가능

// super( )이 생성이 됨, 프리컴파일 단계에서

 

}

 

}

 

/// Customer.java ///

 

package inheritance;

 

public class Customer{

 

protected int customerId;

protected String customerName;

protected String customerGrade;

int bonusPoint;

double bonusRatio;

 

public Customer(){

customerGrade = “SILVER”;

bonusRation = 0.01;

}

 

public Customer( int customerId, String customerName ){

 

this.customerId = customerId;

this.customerName = customerName;

 

customerGrade = “SILVER”;

bonusRatio = 0.01;

 

}

 

~~~~

 

}

 

/// VIPCustomer.java ///

 

package inheritance;

 

public class VIPCustomer extends Customer{

 

double saleRatio;

private int agentId;

 

// 기본생성자가 없고, 매개변수 있는 생성자가 있을 시에는

// 하위 클래스의 생성자에도 매개변수를 두고, super( int, String )으로 한다

// 허나 상위 클래스에 어떠한 생성자도 없을 경우

// 기본 생성자가 생성이 된다 ( 컴파일러가 제공함 )

public VIPCustomer( int customerId, String customerName ){

 

super( customerId,customerName );

 

customerGrade = “VIP”

bonusRatio = 0.05;

saleRatio = 0.1;

 

}

 

}



—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

// 12. 메서드 오버라이딩

 

| 하위 클래스에서 메서드 재정의 하기

오버라이딩 ( overriding )

: 상위 클래스에 정의된 메서드의 구현 내용이 하위 클래스에서 구현할

내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있음

 

예제의 Customer 클래스의 calcPrice()와 VIPCustomer의 calcPrice() 구현 내용은

할인율과 보너스 포인트 적립 내용 부분의 구현이 다름

 

따라서 VIPCustomer 클래스는 calcPrice() 메서드를 재정의 해야 함

 

///

 

public VIPCustomer( int customerId, String customerName ){

 

super( customerId,customerName );

 

customerGrade = “VIP”

bonusRatio = 0.05;

saleRatio = 0.1;

}

 

@Override

public int calcPrice(int price){

bonusPoint = price*bonusRatio;

return price - ( int ) ( price*saleRatio )

 

}

 

| @override 애노테이션 (Annotation)

재정의된 메서드라는 의미로 선언부가 기존의 메서드와 다른 경우 에러 발생

 

애노테이션은 컴파일러에게 특정한 정보를 제공해주는 역할

 

애노테이션 설명
@Override 재정의된 메서드라는 정보 제공
@Functionalinterface 함수형 인터페이스라는 정보 제공
@Deprecated 이후 버전에서 사용되지 않을 수 있는 변수, 메서드에 사용됨
@SuppressWarnings 특정 경고가 나타나지 않도록 함
EX) @SuppressWarnings(“deprecation”)은
@Deprecated가 나타나지 않도록 함

 

| 형 변환과 오버라이딩 메서드 호출

 

Customer vc =new VIPCustomer();

vc.calcPrice(10000);

 

위 코드에서 calcPrice() 메서드는 어느 메서드가 호출될 거 인가?

자바에서는 항상 인스턴스 ( 여기서는 VIPCustomer )의 메서드가 호출됨

 

/// OverridingTest.java ///

 

package inheritance;

 

public class Overriding{

 

public static void main(String[] args){

 

Customer customerSeo = new VIPCustomer(10030, “서상원");

/// customerSeo는 VIP등급으로 지정됨 B/C VIPCustomer로 생성되니까

}

 

}

 

| 가상 메서드 ( virtual method )

 

메서드의 이름과 메서드 주소를 가진 가상 메서드 테이블에서

호출될 메서드의 주소를 참조함

 

Customer 클래스의 가상 메서드 테이블   메서드 영역
메서드 메서드 주소 Customer 클래스
calcPrice()
calcPrice(재정의됨) 0xFF00FFAA
showCustomerInfo(재정의X) 0x112233AA Customer 클래스
showCustomerInfo()
VIPCustomer 클래스의 가상 메서드 테이블
메서드 메서드 주소 VIPCustomer클래스
재정의된 calcPrice()
calcPrice(재정의됨) 0x00335577
showCustomerInfo(재정의X) 0x112233AA VIPCustomer 클래스
getAgentID()
getAgentID
(하위 클래스에서 추가된 메서드 )
0x8899BB33



메서드의 이름은 그 자체가 주소 고로 같은 이름 존재 X

BUT 메서드가 재정의 되는 경우는 이름이 같을 수도 있다.

이러할 경우에는 각각 맵핑되는 주소가 따로 있다.

또한 호출은 타입에 기반이 아닌 생성된 인스턴스에 기반해서 호출된다.

 

| 재정의된 메서드의 호출 과정

 

Customer vc = new VIPCustomer(); 일때

 

vc.calcPrice(); ➡ calcPrice()재정의 안된 경우 호출 ➡ Customer 클래스
calcPrice()
➡ calcPrice()재정의된 경우 호출 ➡ VIPCustomer 클래스
재정의한 calcPrice()

 

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

// 13. 다형성 1 & 14. 다형성 2

 

| 다형성 ( polymorphism ) 이란?

하나의 코드가 여러 자료형으로 구현되어 실행되는 것

같은 코드에서 여러 실행 결과가 나옴

 

정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나

객체지향 프로그래밍의 유연성, 재활용성, 유지보수성에 기본이 되는 특징

 

/// AnimalTest.java ///

 

package polymorphism;

 

class Animal{

public void move(){

System.out.println(“동물이 움직입니다");

}

}



class Human extends Animal {

public void move(){

System.out.println(“사람이 두 발로 걷습니다");

}

 

public void readBooks(){

System.out.prinln(“사람이 책을 읽습니다")

}

}

 

class Tiger extends Animal {

public void move(){

System.out.println(“호랑이가 네 발로 뜁니다 ");

}

public void hunting(){

System.out.println(“호랑이가 사냥을 합니다")

}

 

}

 

class Eagle extends Animal {

public void move(){

System.out.println(“독수리가 하늘을 날아갑니다");

}

public void wander(){

System.out.println(“독수리가 하늘을 떠돕니다")

}

 

}

 

public class AnimalTest {

public static void main(String[] args){

 

/// Animal이라는 Type 하나로 만들고

Animal hAnimal = new Human();

Animal tAnimal = new Tiger();

Animal eAnimal = new Eagle();

 

AnimalTest test = new AnimalTest();

 

/// 다형성 방법 1 : ArrayList에 추가 후 for문 하나로 다양한 구현(다양한 타입)

/// 코드 재사용의 한 방법

ArrayList<Animal> animalList = new ArrayList<Animal>();

animalList.add(hAnimal);

animalList.add(tAnimal);

animalList.add(eAnimal);

 

for( Animal animal : animalList ){

animal.move();

}

}



/// 다형성 방법2 : 상속 > 형변환 > 오버라이딩 > 가상함수 > 다형성

public void moveAnimal(Animal animal){

animal.move();

 

}

}

 

| 다형성의 사용으로써 갖는 장점

다양한 여러 클래스를 하나의 자료형(상위 클래스)로 선언하거나

형변환 하여 각 클래스가 동일한 메서드를 오버라이딩 한 경우,

하나의 코드가 다양한 구현을 실행할 수 있음

 

유사한 클래스가 추가되는 경우 유지보수에 용이하고

각 자료형 마다 다른 메서드를 호출하지 않으므로 코드에서 많은 if 문이 사라짐

 

Ex) 위 CustomerTest를 통한 이해

 

기존 Customer, VIPCustomer만이 아닌 GoldCustomer 클래스를 추가 시,

grade에 대한 기준을 위해서 수 많은 if문이 들어가야하지만

Customer 클래스에서 상속을 받아서 오버라이딩 해야하는 부분만 해준다면

많은 메서드에 대한 if문에 추가가 필요가 없고,

이후에 다른 grade ( PlatinumCustomer, RubyCustomer )에 따른 클래스 추가에도

훨씬 적은 코드로 추가하기 편함

 

| 상속은 언제 사용할까?

IS-A 관계 ( is ar relationship : inheritance )

일반적인(General) 개념과 구체적인(Specific) 개념과의 관계

상위 클래스 : 일반적인 개념 클래스 ( 예 : 포유류 )

하위 클래스 : 구체적인 개념 클래스 ( 예 : 사람, 원숭이, 고래, 등 )

단순히 코드를 재사용하는 목적으로 사용하지 않음

HAS-A 관계 ( Composition )

한 클래스가 다른 클래스를 소유한 관계

코드 재사용의 한 방법

Ex) Student가 Subject을 포함한 관계



—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

// 15. 다운 캐스팅과 instanceof

 

| 하위 클래스로 형 변환, 다운캐스팅

묵시적으로 상위 클래스 형변환된 인스턴스가

원래 자료형(하위클래스)로 변환되어야 할 때 다운캐스팅이라 함

 

하위 클래스로의 형 변환은 명시적으로 되어야 함

 

Customer vc = new VIPCustomer(); // 묵시적

VIPCustomer vCustomer = (VIPCustomer)vc; // 명시적

 

| instanceof

True, False를 반환하는



/// 캐스팅 오류 & instanceof 사용 설명

 

/// AnimalTest.java /// ( 위 파일에서 일부 첨부 )

 

public class AnimalTest {

public static void main(String[] args){

 

Animal hAnimal = new Human();

Animal tAnimal = new Tiger();

Animal eAnimal = new Eagle();

 

/// human이라는 변수로 다운캐스팅

Human human = (Human)hAnimal;

human.readBook();

 

/// 잘못된 캐스팅 오류의 예

// Eagle human = (Eagle)hAnimal;

/// 잘못된 캐스팅을 하는 것을 방지하는 구문 instanceof

if (hAnimal instanceof Human){

Human human = (Human)hAnimal;

human.readbooks();

}

 

AnimalTest test = new AnimalTest();

 

ArrayList<Animal> animalList = new ArrayList<Animal>();

animalList.add(hAnimal);

animalList.add(tAnimal);

animalList.add(eAnimal);

 

for( Animal animal : animalList ){

animal.move();

}

}

 

/// 다운 캐스팅

 

public class AnimalTest

{

public static void main(String[] args)

{

 

Animal hAnimal = new Human();

Animal tAnimal = new Tiger();

Animal eAnimal = new Eagle();

 

ArrayList<Animal> animalList = new ArrayList<Animal>();

animalList.add(hAnimal);

animalList.add(tAnimal);

animalList.add(eAnimal);

 

AnimalTest test = new AnimalTest();

test.testDownCasting(animalList);

 

 

}

 

public void testDownCasting(ArrayList<Animal> list)

{

for(int i = 0; i<list.size(); i++)

{

Animal animal = list.get(i);

 

if( animal instanceof Human)

{

Human human = (Human)animal;

human.readBooks();

}

 

else if( animal instanceof Tiger)

{

Tiger tiger = (Tiger)tiger;

tiger.hunting();

}

 

else if( animal instanceof Eagle)

{

Eagel eagler = (Eagle)animal;

eagler.wander();

}

 

else

{

System.out.println(“Not Defined”);

}

}

}



—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

/// 16. 코딩해보세요

 

| 일반 고객와 VIP 고객의 중간 등급 만들기

 

고객이 늘어 VIP 고객만큼 물건을 많이 구입하지 않지만,

단골인 분들을 GOLD 등급으로 관리하고 싶습니다.

혜택은 다음과 같습니다.

 

  • 제품을 살 때는 항상 10%를 할일해 줍니다.
  • 보너스 포인트는 2%를 적립해 줍니다.
  • 담당 전문 상담원은 없습니다.

 

Customer 클래스에서 상속을 받아 GoldCustomer를 구현해 보세요

 

| 배열을 활용하여 구현하기

 

고객은 현재 5명입니다.

VIP 1명, GOLD 2명, SILVER 2명 일때, 각 고객이 10,000원짜리 제품을 구매한 경우

지불한 금액과 적립된 보너스 포인트를 출력해보세요

 

ArrayList를 활용하여 구현해봅니다.

 

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

—-----------—-----------—-----------—-----------—-----------—-----------—-----------—-----------

 

이 정리 내용은 패스트 캠퍼스, K-Digital Credit Java 강의를 참고했습니다