Loading...

JAVA / / 2022. 1. 17. 11:30

자바 17강. 오버라이딩 ★

반응형

 

부모가 들고 있는 메서드를 자식이 똑같이 들고 있거나,

자식이 들고 있는 메서드를 부모가 똑같이 들고 있는,

 

똑같은 메서드를 자식도 들고 있고 부모도 들고 있으면

부모의 메서드가 오버라이드 된다.

 

무효화된다는 말이다.

 

부모가 가지고 있기 때문에 자식에게 양보하는 것이다.

 

즉, 메모리를 위에서 밑으로 타고 내려간 것이다.

 

변수는 자식이 똑같은 변수를 들고 있어도 양보하지 않고,

부모가 가지고 있는 변수를 실행한다.

 

메서드는 동일한 메서드를 부모와 자식이 가지고 있다는 조건을 지킨다면

부모의 메서드오버라이드(무효화)시킨다.

 

부모의 메서드를 통로로 이용하는 것이다.

 

통로로 이용하기 때문에 부모 클래스에는 아무런 내용이 필요 없다.

 

이런 클래스를 abstract 추상 클래스라고 한다.

다형성을 위해 만들어진 것이다.

 

부모의 메서드 또한 오버라이드를 위해 만든 메서드이기 때문에

abstract 추상 메서드라고 한다.

 

부모의 메서드가 무효화되어 자식의 메서드를 찾으러 가는 행위를 동적 바인딩이라고 한다.

 

변수와 메서드의 차이점이다.

변수는 오버라이드를 못한다.

 

아래에서 위로 스캔을 할 때 원하는 것을 찾으면 더 이상 올라가지 않는데

위에서 아래로 오버라이드 되어 내려올 때는

찾으면 더 이상 내려가지 않을까?

똑같은 메서드를 가지고 있다면

가장 마지막에 있는 자식이 실행될 것이다.

똑같은 메서드를 가지고 있는 자식들 중 가장 아래 자식까지 가게 된다.

 


 

저번 시간에 오버 로딩을 배우며 썼던 코드를 추상화시켜보자.

package ex11;

class 동물 {
}

class 사자 extends 동물 {
    String name = "사자";
    int hp = 100;
    int attack = 10;
}

class 호랑이 extends 동물 {
    String name = "호랑이";
    int hp = 100;
    int attack = 15;
}

class 곰 extends 동물 {
    String name = "곰";
    int hp = 100;
    int attack = 50;
}

public class ExtendsEx02 {

    // 오버라이딩 = 무효화 하다 -> 아래로 타고 내려가는 기법
    // 사자 -> 호랑이 공격
    static void attack(동물 unit1, 동물 unit2) {
        // System.out.println(unit2.name + "가 공격당하고 있습니다.");
        // unit2.hp = unit2.hp - unit1.attack;
        // System.out.println(unit2.name + "의 hp : " + unit2.hp);
    }

    public static void main(String[] args) {
        동물 lion = new 사자();
        동물 tiger = new 호랑이();
        동물 bear = new 곰();

        attack(lion, tiger);
        attack(lion, bear);
    }
}

상속을 이용해 추상화시켜놓았다.

 

추상화를 사용해 공통 메서드(모듈)를 만들 수 있다.

 

그런데 주석 처리해놓은 attack 메서드 내부는 오류가 난다.

동물 타입 메모리에는 name, hp, attack 변수가 없기 때문에 호출이 불가능하기 때문이다.

 

자식 클래스를 찾아갔을 때는 위로 스캐닝해서

부모 클래스의 변수를 상속받을 수 있었지만,

부모 클래스를 찾아갔을 때는 아래로 스캐닝을 할 수 없기 때문에

자식의 변수를 사용할 수 없다.

 

오버 라이딩 = 무효화

위로 타고 스캐닝하며 올라가는 것은 상속이 해주는 기능인데

오버 라이딩은 아래로 타고 내려가며 스캐닝하는 기법이다.

 

이를 해결하기 위해 동물 메서드에 name 변수를 추가(String name = "동물";)해주면

결과는 사자, 호랑이가 아닌 동물이 뜰 것이다.

이때 부모를 무효화시키고 자식에게 접근하기 위해 메서드 오버 라이딩을 해주어야 한다.

 

package ex11;

class 동물 {
    String getName() {
        return "";
    }
}

class 사자 extends 동물 {
    String name = "사자";
    int hp = 100;
    int attack = 10;

    String getName() {
        return name;
    }
}

class 호랑이 extends 동물 {
    String name = "호랑이";
    int hp = 100;
    int attack = 15;

    String getName() {
        return name;
    }
}

class 곰 extends 동물 {
    String name = "곰";
    int hp = 100;
    int attack = 50;

    String getName() {
        return name;
    }
}

public class ExtendsEx02 {

    static void attack(동물 unit1, 동물 unit2) {
        System.out.println(unit2.getName() + "가 공격당하고 있습니다.");
        // unit2.hp = unit2.hp - unit1.attack;
        // System.out.println(unit2.name + "의 hp : " + unit2.hp);
    }

    public static void main(String[] args) {
        동물 lion = new 사자();
        동물 tiger = new 호랑이();
        동물 bear = new 곰();

        attack(lion, tiger);
        attack(lion, bear);
    }
}

변수로는 자식이 가지고 있는 변수를 접근할 수 없기 때문에

메서드를 통해 자식의 변수로 찾아간다.

 

name 변수를 받아온다는 의미로 getName 메서드를 만들어줬다.

똑같이 hp변수를 받아올 때 getHp,

attack 변수를 받아올 때 getAttack 메서드를 만들어준다.

 

공격을 당했을 때 hp가 깎이는 메서드도 하나 필요하다.

행위는 상태를 변화시키기 때문에 메서드를 만들어준다.

이때 hp의 값이 변경되기 때문에 이 메서드는 setHp라고 이름을 지어준다.

 

 

최종!

package ex11;

class 동물 {
    String getName() {
        return "";
    }

    void setHp(int hp) {

    }

    int getHp() {
        return 0;
    }

    int getAttack() {
        return 0;
    }
}

class 사자 extends 동물 {
    String name = "사자";
    int hp = 100;
    int attack = 10;

    String getName() {
        return name;
    }

    void setHp(int hp) {
        this.hp = hp;
    }

    int getHp() {
        return hp;
    }

    int getAttack() {
        return attack;
    }
}

class 호랑이 extends 동물 {
    String name = "호랑이";
    int hp = 100;
    int attack = 15;

    String getName() {
        return name;
    }

    void setHp(int hp) {
        this.hp = hp;
    }

    int getHp() {
        return hp;
    }

    int getAttack() {
        return attack;
    }
}

class 곰 extends 동물 {
    String name = "곰";
    int hp = 100;
    int attack = 50;

    String getName() {
        return name;
    }

    void setHp(int hp) {
        this.hp = hp;
    }

    int getHp() {
        return hp;
    }

    int getAttack() {
        return attack;
    }
}

public class ExtendsEx02 {

    static void attack(동물 unit1, 동물 unit2) {
        System.out.println(unit1.getName() + "(이)가 " + unit2.getName() + "(을)를 공격하고 있습니다.");
        System.out.println(unit2.getName() + "(이)가 공격당하고 있습니다.");
        unit2.setHp(unit2.getHp() - unit1.getAttack());
        System.out.println(unit2.getName() + "의 hp : " + unit2.getHp());
    }

    public static void main(String[] args) {
        동물 lion = new 사자();
        동물 tiger = new 호랑이();
        동물 bear = new 곰();

        attack(lion, tiger);
        attack(lion, bear);
        attack(tiger, bear);
    }
}

 

 

지금까지 우리가 배워온 게 바로 객체지향 원칙 두 번째이다.

DIP(Dependency 원칙 Inversion 역전 Principle 원칙)

 

원칙을 역전한다는 말이 무슨 말일까?

 

구체적인 자식 클래스에 의존하던 메서드가

추상적인 부모 클래스에 의존하게 되는 것을 말한다.

그러면 공통 모듈이 생성 가능해진다.

 

DIP를 사용해도 자식들의 상태에 접근이 불가능하므로

오버 라이딩(부모와 자식 클래스가 동일 -> 부모 메서드 무효화)이 필요하다.

 

 

 

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

 

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

반응형