무작정 개발.Vlog

자바의 정석 | Ch 07 - 객체지향 프로그래밍2-2

by 무작정 개발
반응형
다형성

 

다형성이란?

 

객체지향 개념에서 다형성이란 '여러 가지 형태를 가질 수 있는 능력'을 의미하며, 자바에서는

한 타입의 참조 변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로

구현했다. 

 

장점

  • 부모 타입 참조 변수로 자식 타입 객체를 다루는 것
  • 하나의 배열에 여러 종류의 객체 저장
참조 변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.

참조 변수 타입과 인스턴스 타입은 보통 일치하지만 일치하지 않을 수도 있다.

 

참조 변수의 형 변환

 

부모. 자식(상속관계)의 참조 변수는 서로 형 변환이 가능하다.

 

자식 타입 -> 부모 타입(up-casting) : 형 변환 생략 가능
부모 타입 -> 자식 타입(down-casting) : 형 변환 생략 불가
package Chapter07;

class Car {

    String color;
    int door;

    void drive() {
        System.out.println("drive, 부릉부릉~");
    }

    void stop() {
        System.out.println("stop, 멈춰!정지");
    }
}

class FireEngine extends Car {

    void water() {
        System.out.println("물뿌리기!");
    }
}

//부모 클래스 : Car / 자식 클래스 : FireEngine
public class CastingTest1 {
    public static void main(String[] args) {
        
        // Car 클래스, FireEngine 클래스는 상속관계
        Car car = null; // Car타입 참조변수 car를 선언하고 null로 초기화
        FireEngine fe = new FireEngine(); //인스턴스(객체)생성 / 포함관계
        FireEngine fe2 = null;

        fe.water();
        car = fe; // 자식 -> 부모 : up-casting / 형변환 생략가능
        //car.water(); // 에러!
        fe = (FireEngine)car; // 부모->자식 : down-casting
        fe2.water();

    }
}

 

instance of 연산자

 

참조 변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용

  • 참조 변수의 형 변환 가능 여부 확인용. 가능하면 true 반환
  • 형 변환 전에 반드시 instanceof로 확인해야 함
  • 주로 조건문에 사용 -> if(참조 변수 instanceof 타입(클래스명))

 

★ instanceof연산의 결과가 true가 나오면 검사한 타입으로 형 변환이 가능하다는 것을 뜻함

 


매개변수의 다형성

 

  • 참조형 매개변수는 메서드 호출 시 자신과 같은 타입 또는 자식 타입의 인스턴스를 넘겨줄 수 있다.

여러 종류의 객체를 배열로 다루기

 

  • 부모 타입의 배열에 자식 타입 객체를 담을 수 있다.
  • 다루고 싶은 객체들의 상속관계를 따져서 가장 가까운 공통조상 클래스 타입의 참조 변수 배열을 생성해서 객체들을 저장

 

Product클래스가 Tv, Computer, Audio클래스의 부모일 때 하단과 같이 가능

Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

위를 Product타입의 참조 변수 배열로 처리하면 하단과 같다.

Product p [] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
package Chapter07;

import java.util.*; // Vector클래스를 사용하기 위해서 추가

class Product {
    int price;			// 제품의 가격
    int bonusPoint;		// 제품구매 시 제공하는 보너스점수

    Product(int price) {
        this.price = price;
        bonusPoint =(int)(price/10.0);
    }

    Product() {
        price = 0;
        bonusPoint = 0;
    }
}

class Tv2 extends Product {
    Tv2() { 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(50); }
    public String toString() { return "Audio"; }
}

class Buyer {			// 고객, 물건을 사는 사람
    int money = 1000;  	// 소유금액
    int bonusPoint = 0;	// 보너스점수
    Vector item = new Vector();	// 구입한 제품을 저장하는데 사용될 Vector객체

    void buy(Product p) {
        if(money < p.price) {
            System.out.println("잔액이 부족하여 물건을 살수 없습니다.");
            return;
        }
        money -= p.price;			// 가진 돈에서 구입한 제품의 가격을 뺀다.
        bonusPoint += p.bonusPoint;	// 제품의 보너스 점수를 추가한다.
        item.add(p);				// 구입한 제품을 Vector에 저장한다.
        System.out.println(p + "을/를 구입하셨습니다.");
    }

    void refund(Product p) {	// 구입한 제품을 환불한다.
        if(item.remove(p)) {	// 제품을 Vector에서 제거한다.
            money += p.price;
            bonusPoint -= p.bonusPoint;
            System.out.println(p + "을/를 반품하셨습니다.");
        } else {			//  제거에 실패한 경우
            System.out.println("구입하신 제품 중 해당 제품이 없습니다.");
        }
    }

    void summary() {		      // 구매한 물품에 대한 정보를 요약해서 보여준다.
        int sum = 0;		      // 구입한 물품의 가격합계
        String itemList =""; 	  // 구입한 물품목록

        if(item.isEmpty()) {	// Vector가 비어있는지 확인한다.
            System.out.println("구입하신 제품이 없습니다.");
            return;
        }

        // 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
        for(int i=0; i<item.size();i++) {
            Product p = (Product)item.get(i);
            sum += p.price;
            itemList += (i==0) ? "" + p : ", " + p;
        }
        System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
        System.out.println("구입하신 제품은 " + itemList + "입니다.");
    }
}

public class PolyArgumentTest3 {
    public static void main(String args[]) {
        Buyer b = new Buyer();
        Tv2 tv = new Tv2();
        Computer com = new Computer();
        Audio audio = new Audio();

        b.buy(tv);
        b.buy(com);
        b.buy(audio);
        b.summary();
        System.out.println();
        b.refund(com);
        b.summary();
    }
}

추상 클래스 - (abstract class)

 

클래스를 설계도에 비유하자면, 추상 클래스는 미완성 설계도에 비유할 수 있다.

  • 미완성 메서드를 갖고 있는 클래스
  • 다른 클래스 작성에 도움을 주기 위한 것 / 인스턴스 생성 불가
  • 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능

추상 클래스 상속 -> 추상 메서드의 구현부 완성 -> 완성도니 설계도(객체 생성)


추상 메서드 - (abstract method)

 

메서드는 선언부와 구현부로 구성되어 있는데 선언 부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상 메서드

  • 공통적으로 꼭 필요하지만 자식마다 다르게 구현될 것으로 예상되는 경우 사용
  • 추상 메서드를 1개라도 구현하지 않으면 여전히 미완성
  • 추상 클래스로부터 상속받는 자식 클래스는 오버 라이딩을 통해 부모인 추상 클래스의 추상 메서드를 모두 구현해주어야 한다.
  • 여러 클래스에 공통적으로 쓸 수 있는 추상 클래스를 바로 작성하거나 기존 클래스의 공통된 부분을 뽑아서 추상 클래스를 작성

추상 클래스의 작성

 

장점

  • 설계도를 쉽게 작성 가능
  • 코드 중복제거
  • 코드 관리가 용이함
  • 구체화된 코드보다 우연(변경에 유리함)

추상화 : 클래스 간의 공통점을 찾아내서 공통의 부모를 만드는 작업


인터페이스 - (interface)

 

인터페이스란?

 

인터페이스는 일종의 추상 클래스이다. 추상 클래스처럼 추상 메서드를 갖지만 추상 클래스보다 추상화 정도가 높아 추상 클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버 변수를 구성원으로 가질 수 없다.

오직 추상 메서드와 상수만을 멤버로 가질 수 있다.

  • 추상 메서드의 집합
  • 구현된 것이 전혀 없는 설계도(모든 멤버가 public)

 

추상 메서드 : 추상 메서드를 가진 일반 클래스

 

인터페이스 : 추상 메서드 빼고 구현된 것이 아무것도 없다.

 

 

인터페이스 선언

interface 인터페이스 이름 {
	  public static final 타입 상수이름 = 값; // 갑=상수
      public abstract 메서드이름(매개변수목록);
      }

 

인터페이스의 멤버들의 제약사항

  • 모든 멤버 변수는 public static final이어야 하며, 생략 가능함
  • 모든 메서드는 public abstract 이어야 하며, 생략 가능함 (단, static메서드. 디폴트 메서드는 예외 JDK1.8부터)

인터페이스의 상속

 

  • 인터페이스는 인터페이스만 상속 가능
  • 클래스와 달리 다중 상속 가능
  • 인터페이스는 클래스와 달리 Object클래스와 같은 최고 조상이 없다.

인터페이스의 구현

 

인터페이스는 추상 클래스처럼 그 자체로는 인스턴스(객체)를 생성할 수 없으며, 자신에 정의된 추상 메서드의 몸통을 만들어주는 클래스를 작성해야 함.

  • 인터페이스에 정의된 추상 메서드를 완성하는 것

 

클래스를 상속받을 땐 'extend'를 사용하는데 인터페이스를 상속받을 때는 'implements'를 사용

class 클래스이름 implements 인터페이스이름 {

		// 인터페이스에 정의된 추상 메서드를 모두 구현해야 함.
}


class Fighter implements Fightable {
	public void move(int x, int y) {  }
    public void attack(Unit u)
    
    //이때 Fighter클래스는 Fightable인터페이스를 구현한다
  • 일부만 구현하는 경우, 클래스 앞에 abstract를 붙여야 한다.
  • 인터페이스는 인스턴스 변수를 가질 수 없다.

인터페이스를 이용한 다형성

 

  • 인터페이스도 구현 클래스의 부모이다.
  • 인터페이스 타입의 매개변수는 인터페이스를 구현한 클래스의 객체만 가능하다.
  • 인터페이스를 메서드의 리턴 타입으로 지정할 수 있다. (안 맞으면 형 변환) -> 이 인터페이스를 구현한 것을 반환하겠다는 뜻)

인터페이스의 장점

  • 두 대상(객체) 간의 연결, 대화, 소통을 돕는 중간 역할을 함.
  • 변경에 유리한 설계가능
  • 선언과 구현을 분리할 수 있다.
  • 개발 시간 단축 가능
  • 표준화 가능
  • 서로 관계없는 클래스들을 맺어줄 수 있다.
반응형

블로그의 정보

무작정 개발

무작정 개발

활동하기