728x90

다형성(Polymorphism)

- 같은 타입이지만 실행 결과가 다양한 객체 대입 가능한 성질

- 조상 타입의 참조변수로 자손 타입의 객체를 다룰 수 있는 것이 다형성

 

예제1)

public class Ex7_7 {
    public static void main(String[] args) {
        // 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성
        // 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.
        Car car = null; // 조상 타입의 참조변수
        FireEngine fe = new FireEngine(); // 실제 인스턴스가 무엇인지가 중요
       
        car = fe; // 자손 → 조상으로 형변환. 형변환 생략됨
        car.drive();
       
        FireEngine fe2 = null; // 자손 타입의 참조변수
        fe2 = (FireEngine) car; // 조상 → 자손으로 형변환. 형변환 생략불가.
        fe2.drive();
        fe2.water();
    }
}

class Car {
    String color;
    int door;
   
    void drive() {
        System.out.println("운전중!");
    }
   
    void stop() {
        System.out.println("정지.");
    }
}

class FireEngine extends Car {
    void water() {
        System.out.println("물 뿌리는 중!");
    }
}
 

 

예제1은 문제없이 잘 동작된다.

예제2는 자손 타입의 참조변수로 조상 타입의 인스턴스를 참조할 수 없다는 사항에 위배된다.

 

예제2)

public class Ex7_7 {
    public static void main(String[] args) {
        // 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성
        // 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.
        Car car = new Car(); // 조상 인스턴스
        FireEngine fe = (FireEngine) car; // Car cannot be cast to FireEngine
        fe.drive();
    }
}

class Car {
    String color;
    int door;
   
    void drive() {
        System.out.println("운전중!");
    }
   
    void stop() {
        System.out.println("정지.");
    }
}

class FireEngine extends Car {
    void water() {
        System.out.println("물 뿌리는 중!");
    }
}
 

 

예제3)

public class Polymorphism {
    public static void main(String[] args) {
        // 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성
        // 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.
        Car car = null// 조상 타입의 참조변수
        FireEngine fe = new FireEngine(); // 실제 인스턴스가 무엇인지가 중요
 
        car = fe; // 자손 → 조상으로 형변환. 형변환 생략됨
        car.drive(); // 부모 타입에 선언된 변수와 메소드만 사용 가능
 
        FireEngine fe2 = null// 자손 타입의 참조변수
        if(car instanceof FireEngine){ // 먼저 자식 타입인지 확인 후 강제 타입 실행.
            System.out.println("===== 객체 타입 확인 =====");
            fe2 = (FireEngine) car; // 조상 → 자손으로 형변환. 형변환 생략불가
            fe2.drive();
            fe2.water(); // 자식 타입에 선언된 변수와 메소드를 다시 사용해야 하는 경우
        }
 
        Car car1 = new FireEngine(); // 부모 클래스 변수 = 자식 클래스 타입;
        car1.drive(); // 변환 후에는 부모 클래스 멤버만 접근 가능
 
        System.out.println("===== 상속 처리 =====");
        FireEngine fe3 = new FireEngine();
        fe3.drive();
        fe3.water();
 
        System.out.println("===== 부모 타입 =====");
        Car car2 = new Car();
        // 자식타입의 참조변수로 부모타입의 인스턴스를 참조할 수는 없다.
        FireEngine fe4 = (FireEngine) car2;
        fe4.drive();
 
    }
}
 
class Car {
    String color;
    int door;
 
    void drive() {
        System.out.println("운전중!");
    }
 
    void stop() {
        System.out.println("정지.");
    }
}
 
class FireEngine extends Car {
    void water() {
        System.out.println("물 뿌리는 중!");
    }
}
 

 

 

예제4)

상위클래스 타입의 변수가 복수의 하위클래스 객체를 참조할 수 있도록 하는 것을 다형성이라 한다.

- Product 가 상위 클래스, Tv, Computer, Audio 는 하위 클래스

import java.util.ArrayList;
 
class Product {
    int price;            // 제품의 가격
    int bonusPoint;    // 제품구매 시 제공하는 보너스점수
 
    public Product(int price) {
        this.price = price;
        this.bonusPoint = (int)(price / 10.0);
    }
 
    public Product() {
    }
}
 
class Tv extends Product {
    public Tv() {
        // 조상 클래스의 생성자 Product(int price)를 호출.
        super(100);
    }
 
    @Override
    public String toString(){
        // Object 클래스의 toString()을 오버라이딩한다.
        return "Tv";
    }
}
 
class Computer extends Product {
    public Computer() {
        // 조상 클래스의 생성자 Product(int price)를 호출.
        super(200);
    }
 
    @Override
    public String toString() {
        // Object 클래스의 toString()을 오버라이딩한다.
        return "Computer";
    }
}
 
class Audio extends Product {
    public Audio() {
        // 조상 클래스의 생성자 Product(int price)를 호출.
        super(50);
    }
 
    @Override
    public String toString() {
        // Object 클래스의 toString()을 오버라이딩한다.
        return "Audio";
    }
}
 
class Buyer {
    int money = 1000;      // 소유금액
    int bonusPoint = 0// 보너스점수
    ArrayList<Product> cart = new ArrayList<>();// 구입한 제품을 저장하기 위한 배열
 
    void buy(Product p) { // 매개 변수가 Product 타입의 참조변수
        if(money < p.price) {
            System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
            return;
        }
 
        money -= p.price;             // 가진 돈에서 구입한 제품의 가격을 뺀다.
        bonusPoint += p.bonusPoint;   // 제품의 보너스 점수를 추가한다.
        cart.add(p);                // 제품을 ArrayList<Product> cart에 추가한다.
        System.out.print(p + "를 구입하셨습니다.");
        System.out.println("현재 잔액은 " + money + " 만원입니다.");
    }
 
    void summary() {                  // 구매한 물품에 대한 정보를 요약해서 보여 준다.
        int sum = 0;                 // 구입한 물품의 가격합계
        String itemList ="";         // 구입한 물품목록
 
        // 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
        for(int i=0; i < cart.size();i++) {
            sum += cart.get(i).price;
            if(i == cart.size() -1){
                itemList += cart.get(i) + " ";
            } else {
                itemList += cart.get(i) + ", ";
            }
        }
        System.out.println("구입하신 물품의 총 금액은 " + sum + "만원입니다.");
        System.out.println("구입하신 제품은 " + itemList + "입니다.");
    }
}
 
public class Ploymorphism {
    public static void main(String[] args) {
        Buyer b = new Buyer();
 
        b.buy(new Tv());
        b.buy(new Computer());
        b.buy(new Audio());
        b.summary();
    }
}
 

 

 

블로그 이미지

Link2Me

,
728x90

패키지의 선언
-
패키지는 소스파일의 첫 번째 문장으로 단 한번 선언
-
같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 된다.
-
패키지 선언이 없으면, 이름없는 패키지에 속하게 된다.

- 패키지명은 선언시 반드시 소문자로 선언해야 한다.


import
-
클래스를 사용할 때 패키지 이름을 생략할 수 있다.
-
컴파일러에게 클래스가 속한 패키지를 알려준다.
-
java.lang 패키지의 클래스는 import 하지 않고도 사용할 수 있다.
- import
문은 패키지문과 클래스 선언의 사이에 선언한다.

접근 제어자

제어자

같은 클래스

같은 패키지

자손 클래스

전체

 public





 protected



 

 (default)

 

 

private

 

 

 


아래 코드는 Eclipse 툴이 아니라 Android Studio 에서 Android 어플 작성을 위한 코드 생성으로 테스트했다.

개념은 동일하므로 Eclipse, Android Studio 상관 없다.

package com.link2me.android.pkg1;

public class MyParent { // 접근 제어자가 public
    private int prv; // 같은 클래스
    int dft; // 같은 패키지
    protected int prt; // 같은/다른 패키지 + 자손
    public int pub; // 접근 제한 없음

    public void printMembers() {
        System.out.println(prv); // OK, 같은 클래스
        System.out.println(dft); // OK, 같은 클래스
        System.out.println(prt); // OK, 같은 클래스
        System.out.println(pub); // OK, 같은 클래스
    }
}

class MyParentTest { // 접근제어자가 default
    // 하나의 파일에 public class 이름이 2개 오면 에러가 발생한다.
    // 같은 패키지
    public void printMembers(){
        MyParent mp = new MyParent();
        //System.out.println(mp.prv); // 에러, private은 같은 class 내에서만 접근 가능
        System.out.println(mp.dft); // OK, default는 같은 패키지내에서 접근 가능
        System.out.println(mp.prt); // OK, protected는 같은/다른 패키지 + 자손
        System.out.println(mp.pub); // OK, public은 접근 제한이 전혀 없다
    }

package com.link2me.android.pkg2;

import com.link2me.android.pkg1.MyParent;

public class MyChild extends MyParent { // 상속 받음
    // 다른 패키지 + 자손
    public void printMembers(){
        //System.out.println(prv); // 에러, private은 같은 class 내에서만 접근 가능
        //System.out.println(dft); // 에러, default는 같은 패키지내에서만 접근 가능
        System.out.println(prt); // OK, protected는 같은/다른 패키지 + 자손
        System.out.println(pub); // OK, public은 접근 제한이 전혀 없다
    }
}

class MyParentTest { // 접근제어자가 default
    // 하나의 파일에 public class 이름이 2개 오면 에러가 발생한다.
    // 다른 패키지 + 다른 class
    public void printMembers(){
        MyParent mp = new MyParent();
        //System.out.println(mp.prv); // 에러 private은 같은 class 내에서만 접근 가능
        //System.out.println(mp.dft); // 에러, default는 같은 패키지내에서만 접근 가능
        //System.out.println(mp.prt); // 에러, protected는 같은/다른 패키지 + 자손
        System.out.println(mp.pub); // OK, public은 접근 제한이 전혀 없다
    }
}


블로그 이미지

Link2Me

,