국비교육

국비지원 60일차(JAVA - 다형성)

재밌는개발러 2023. 10. 18. 18:34

@지난 시간 복습

1) static 변수는 메서드 안에 못쓴다. static 변수는 클래스영역에만 사용가능하다.

2) 동일한 클래스에 다른메서드를 호출하려면 꼭 메서드를 만들어 메서드 안에만 다른 메서드를 호출할 수 있다.

    클래스영역에 바로 메서드 호출 시 오류가 먹는다.

3) 부모에 매개변수 가있는 생성자가 있는데  default 생성자를 만들어주지 않은 경우에는 상속받고 있는 자식클래스를 만        들어주면 오류가 먹는다.

    (매개변수가 있는 생성자 만들 시 default 생성자를 꼭 만들어주는 게 좋다.)

4) 문자 + 숫자시 = 문자형태가 되는 거는 문자가 숫자보다 크기가 크기 때문이다.

   ( int -> long -> float -> double 자료형의 크기별로 나타낸 것이다. long 형안에 int형 쓸 수 있고 , float 안에 long, int형       을 쓸수 있는 것도 같은 맥략이다.)

5) bolean의 기본값은 false이다.

6) int형의 변수나, String형의 변수나 이식에 어떤 값을 추가해 주는 거면 해당 변수에 초기값을 설정해줘야 한다.

    (int a = 0;   , String list = ""; 이렇게 설정해 주는 게 좋다.)

 

※JAVA - 다형성

1. 객체지향 언어에서도 중요한 부분에 속합니다.
    조상타입의 참조변수로 자손타입의 인스턴스(객체)를 다룸
    ex) Tv tv = new SmartTv(); // Tv 부모, SmartTv 자식클래스

2. 다형성 장점
    1) 유지보수: 여러 객체들을 하나의 타입으로 관리할 수 있기 때문에 유지보수가 편하다.
    2) 재사용성: 객체의 재사용이 쉽다.
    3) 느슨한 결합: 클래스 간의 의존성을 줄여서 확장성은 높이고 결합도는 낮춘다.

 

3. 업캐스팅이란?

    1) 부모타입변경, 자식클래스의 필드나 메서드는 못쓰고 부모클래스에 있는 메서드나 필드만 출력가능하다.

     -> Unit :부모클래스, Ani :자식클래스

         Unit u = (Unit) new Ani(); -> Ani라는 자식객체를 Unit의 부모타입으로 참조변수 u에 적용한 것이다.

    2) 업캐스팅 하는 이유: 상속관계에서 상속받은 서브클래스가 몇 개이든 간에 하나의 인스턴스 타입(부모타입)으로 묶             어서  관리할 수 있기 때문이다.

 

4. 다운캐스팅이란?

    1) 업캐스팅한 자식클래스를 복구하는 개념이다. 원래 자식클래스의 필드와 기능을 회복하는 것이다.

    2) 다운캐스팅 하게 되면 부모에 있는 필드나 메서드는 물론 , 자식클래스에 있는 필드나 메서드도 같이 쓸 수 있다.

 

5. instanceof 연산자

    객체에 대한 클래스(참조형) 타입에만 사용할 수 있고 true , false를 반환해 준다.

     (int, double 같은 기본형 타입은 사용불가능하다.)

 

※다형성 기본예제 1

class Tv {

    int volumn;
    int channel;
    boolean power; //초기값 false
    void power() {
        power = !power; // true
        System.out.println(power?"Tv 켜짐":"Tv 꺼짐"); //power->true 이니 참이된다.
    }

    void channelUp() {
        channel+=1;
    }
    void channelDown() {
        channel-=1;
    }
    void volumnUp() {
        volumn+=1;
    }
    void volumnDown() {
        volumn-=1;
    }
} //Tv클래스 끝

class SmartTv extends Tv {
    boolean ottPower; //SmartTv에만 있는 변수; false
    void ott() {
        ottPower=!ottPower; // true
        System.out.println(power?"Tv 켜짐":"Tv 꺼짐");
        System.out.println(ottPower?"OTT 켜짐":"OTT 꺼짐");
    }
    void power() {
        power = !power; //부모의 Tvㄹ부터 상속받은 변수; true
        ott();
    }

} //SmartTv 클래스 끝
class RollableTv extends Tv {
    boolean rolling;
    void rolling() {
        rolling=!rolling;
        if(rolling) System.out.println("화면 펼침");
        else        System.out.println("화면 말려들어가짐");
    }


    void volumnUp() {
        volumn+=2;
    }
    void volumnDown() {
        volumn-=2;
    }
}RollableTv클래스 끝

public class Ex25_1_다형성 {
    public static void main(String[] args) {

        // 다형성
        Tv stv = new SmartTv(); // 다형성인 경우 SmartTv로 인스턴스를 생성했더라도 Tv 한테 있는 멤버들만 사용 가능
        System.out.println(stv.power);
        stv.power();
        System.out.println(stv.power);

        System.out.println("====================");

        Tv rtv = new RollableTv();
        System.out.println(rtv.volumn);
        rtv.volumnUp();
        System.out.println(rtv.volumn);

    }
}

1) Tv stv = new SmartTv(); // 다형성인 경우 SmartTv로 인스턴스를 생성했더라도 Tv 한테 있는 멤버들만 사용 가능
        System.out.println(stv.power);
        stv.power();
        System.out.println(stv.power);

-> 이렇게 자식클래스 객체를 부모클래스타입으로 설정한 경우 변수의 값이 같아도 부모 타입의 변수의 값을 가져와 쓰게      되고, 메서드는 오버라이딩된 자식클래스의 메서드를 재정의해 쓰게 된다.

// 다형성
        Tv stv = new SmartTv(); // 다형성인 경우 SmartTv로 인스턴스를 생성했더라도 Tv 한테 있는 멤버들만 사용 가능
        System.out.println(stv.power); //결과값: false 자식에 새롭게 변수가 지정된것이고 그초기값은 false이다
        stv.power(); //결과값: TV켜짐, OTT켜짐 
        System.out.println(stv.power); //결과값: true ,위에 stv.power()실행시 power변수가 true로 바뀐다.

        System.out.println("====================");

 

※다형성 기본예제 2

class Parent {
    int x = 100;
    void method(){
        System.out.println("부모 메서드");
    }
}
class Child extends  Parent{
    int x = 200;

    void method(){
        System.out.println("자식 메서드");
    }

}

public class Ex25_2_다형성2 {
    public static void main(String[] args) {
        Parent p = new Child(); //타입이 Parent인 Child 인스턴스를 생성 -> Child에 있는 멤버중에 Parent클래스(타입)에 있는 멤버위주로만 쓸수있는것이다.
        Child c =new Child(); //타입이 Child인 Child 인스턴스를 생성

        /* Parent 참조변수 */
        System.out.println(p.x); //p꺼의 변수 x  - 상속받는 클래스중에 같은 이름의변수는 앞에 타입에 따라 달리 출력이된다
        p.method(); //Child 꺼의 메서드 method 출력됨

        System.out.println("==================");

        /* Child(본인) 참조변수 */
        System.out.println(c.x); //타입이 Child 니까 Child 에 있는 x변수가 출력이된다.
        c.method(); //Child 꺼의 메서드 method 출력됨


    }
}

1)  Child 인스턴스를 생성하더라도 멤버변수는 원래 꺼가 출력됨.
    -> 상속받는 클래스중에 같은 이름의 변수는 앞에 타입에 따라 달리 출력이 된다
    -> 타입에 있는 변수가 뽑아진다 , 오버라이드 된 메서드 타입이 아니라 인스턴스화한 객체의 클래스에 메서드값이 출            력  됨.
2) 상속된 다형성인 경우, 메서드는 new 한 객체껄 가져오고, 변수는 참조한 타입의 클래스 걸 가져온다.
    method는 오버라이드 된다.

 

 

※다형성 기본예제 3

- 시나리오 -
-> 커피 구매 애플리케이션 제작한다 치고
    그냥 코드를 짜게 되면 각 메뉴마다 가격이나 이름 같은 정보들이 다 다르기 때문에 각 메뉴마다 구매하는 메서드를 구         현해야 한다.
    그런데 다형성을 이용하면 개별적인 커피의 구매 메서드를 따로 구현하지 않아도 된다.(그냥 한방에 모든 메뉴를 구매        할  수 있는 기능 만들 수 있음)
    상위 클래스 Coffee의 자료형을 매개변수로 전달받으면, 하위 클래스 타입의 참조변수는 매개변수로 전달될 수 있다.

class Coffee {
    int price;
    public Coffee(int price) {
        this.price = price;
    }
}
class Americano extends Coffee {
    public Americano(int price) {
        super(price);
    }
    @Override
    public String toString() {
        return "아메리카노";
    }
}
class Latte extends Coffee {
    public Latte(int price) {
        super(price);
    }

    @Override
    public String toString() {
        return "라떼";
    }
}
class Afogatou extends Coffee  {
    public Afogatou(int price) {
        super(price);
    }

    @Override
    public String toString() {
        return "아포가토";
    }
}

class Customer {
    int money = 10000;
    int sum=0;
    String list = "";

    // 커피 구매 하는 메서드
    void buyCoffee(Coffee a) {
        if(money < a.price) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        money -= a.price;
        System.out.println(a+"를 구매하셨습니다.");

        // 구매한 물픔 총 합
        sum += a.price;

        // 구매한 물품 이름
        list += a+", ";
    }

    void summary() {
//        int sum=0;
        System.out.println("구매하신 물품은 "+list.lastIndexOf("메")+" 입니다.");
        System.out.println("구매하신 물품의 총 금액은 "+sum+" 입니다.");
        System.out.println("구매하신 물품은 "+list.substring(0, list.length()-2)+" 입니다.");
        ////라떼, 아메리카노,
    }


}

public class Ex25_3_다형성예제 {
    public static void main(String[] args) {
        Customer c1 = new Customer();

        c1.buyCoffee(new Latte(3900)); // 3900
        c1.buyCoffee(new Americano(1900)); // 1900
        c1.buyCoffee(new Afogatou(5000)); // 3900
        
        c1.summary();

        Customer c2 = new Customer();

1) 커피구매할 때 다형성활용

-> 아래는  메서드를 매개변수에 각각의 타입에 해당인스턴스를 만드는 코드이다. 

    이렇게 각각의 타입으로 관리하면 유지보수나, 재사용성이 좋지 못할 것이다. 

    

void buyCoffee(Americano a) { // 아메리카노
    money = money - a.price;
}
void buyCoffee(Latte a) { // 아메리카노
    money = money - a.price;
}
void buyCoffee(Afogatou a) { // 아메리카노
    money = money - a.price;
}

 

2) 커피구매할 때 다형성활용 - 업캐스팅

-> 이렇게 상속관계에서 하나의 부모로부터 상속받는다면 해당 인스턴스의 객체들을 부모클래스 타입으로 명시하게 되면 

    하나의 타입으로 여러 인스턴스를 참조할 수 있을 것이다.

    그래서 메서드를 활용해 이 타입에 들어가는 자식인스턴스들을 생성해 한방에 모든 메뉴들을 구매할 수 있게 될 것이다.

    (유지보수, 재사용성 이 용이하게 된다.)

void buyCoffee(Coffee a) {
    if(money < a.price) {
        System.out.println("잔액이 부족합니다.");
        return;
    }
    money -= a.price;
    System.out.println(a+"를 구매하셨습니다.");

}

 

3) 구매한 물품들의 총합, 구매한 물품이름 출력코드

void buyCoffee(Coffee a) {
        if(money < a.price) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        money -= a.price;
        System.out.println(a+"를 구매하셨습니다.");

        // 구매한 물픔 총 합
        sum += a.price;

        // 구매한 물품 이름
        list += a+", ";
    }

    void summary() {
//        int sum=0;
        System.out.println("구매하신 물품은 "+list.lastIndexOf("메")+" 입니다.");
        System.out.println("구매하신 물품의 총 금액은 "+sum+" 입니다.");
        System.out.println("구매하신 물품은 "+list.substring(0, list.length()-2)+" 입니다.");
        ////라떼, 아메리카노,
    }

-> buyCoffee 메서드를 활용해  Coffee 타입에 자식클래스들을 인스턴스화해서 가격과, tostring으로 각자의 이름들을 반환하게 하고, 그 인스턴스의 가격을 sum이라는 변수에 합쳐놓고, 그 인스턴스의 return 한 반환이름들을  list에 문자형으로 저장하게 되면 , 이 sum과 list라는 변수들로 총금액과, 구매한 물품명을 출력하는 메서드를 만들 수 있을 것이다.

단, sum이나 list는 해당 클래스영역에 선언을 해놓고 써야지 2개의 메서드에 오고 가면서 사용할 수 있을 것이다.