본문 바로가기

WINK-(Web & App)/JAVA 스터디

[2024-2 Java 스터디] 정채은 #4주차

반응형

[5-5] 상속

상속 : 부모 기능 ---> 자식 클래스 

 

extends : 클래스 상속 위해 꼭 필요함 !!!

 

<자식 클래스의 기능 확장하기>

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name+" zzz");
    }
}

public class Sample {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");
        System.out.println(dog.name);
        dog.sleep();
    }
}

 

generally, 상속받은 자식 클래스 = 부모 클래스 기능 + 기능 + 기능 ....

 

<IS - A 관계>

 Animal ----> Dog

  (상위)         (하위)

Dog is a Animal(개는 동물이다) : IS-A 관계

 

자식 클래스 객체는 부모 클래스 자료형처럼 사용 O

 

Animal dog = new Dog();  // Dog is a Animal

 

{{{{{{주의}}}}}} 

Dog 객체를 Animal 자료형으로 사용할 경우 : Dog 클래스에만 존재하는 sleep 메서드 사용 X

                                                                      Animal 클래스에 구현된 setName 메서드만 사용 가능

 

부모 클래스로 만들어진 객체를 자식 클래스의 자료형으로는 사용할 수 없다

 

※ Object 클래스

자바 모든 클래스는 Object 클래스 상속받음

 

<메서드 오버라이딩>

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name+" zzz");
    }
}

class HouseDog extends Dog {
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();  // happy zzz 출력
    }
}

출력 : happy zzz

 

 

IF , 출력값 변경 ( happy zzz in house)

 

class HouseDog extends Dog {
}

                                                                 

void sleep() {
        System.out.println(this.name + " zzz in house");
    }
}

 

HouseDog 클래스 (자식 클래스) 에 Dog 클래스(부모 클래스)와 동일 형태인 sleep 메서드 ▶ (우선순위 : HouseDog 클래스의 sleep 메서드 > Dog 클래스의 sleep 메서드) 즉, HouseDog 클래스의 sleep 메서드 호출

 

메서드 오버라이딩 : 부모 클래스의 메서드를 자식 클래스가 동일한 형태로 또다시 구현하는 행위

 

<메서드 오버로딩>

 

위의 코드에 메서드 추가

void sleep(int hour) {
    System.out.println(this.name+" zzz in house for " + hour + " hours");
}

 

동일한 이름의 sleep 메서드 또 생성 O

★단, 메서드 입력 항목 다를 경우만

 

메서드 오버로딩 : 입력 항목이 다른 경우 동일한 이름의 메서드 생성 O

 

<다중 상속>

다중 상속 : 클래스가 동시에 하나 이상의 클래스를 상속받는 것

but ! 자바는 다중상속 XXXXXXXXX !!!!!!

이유 : 상속받은 거 중 뭘 선택해야할지 애매모호! 

 

[5-6] 생성자 

<생성자>

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

class HouseDog extends Dog {
    void sleep() {
        System.out.println(this.name + " zzz in house");
    }

    void sleep(int hour) {
        System.out.println(this.name + " zzz in house for " + hour + " hours");
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();
        houseDog.sleep(3);
    }
}

 

main 메서드 수정 

(... 생략 ...)

public class Sample {
    public static void main(String[] args) {
        HouseDog dog = new HouseDog();
        System.out.println(dog.name);
    }
}

이때 name 변수에 어떠한 값도 없기 때문에 null 출력

 

이때 생성자 !!!!로   객체 변수에 값을 무조건 설정해야만 객체가 생성될 수 있도록 강제할수 있는 방법을 사용해부자.

class HouseDog extends Dog {
    HouseDog(String name) {
        this.setName(name);
    }

 

생성자 : 메서드명이 클래스명과 동일하고 리턴 자료형을 정의하지 않는 메서드

 

{규칙}

  • 클래스명 = 메서드명
  • 리턴 타입 정의 X (void 사용 X)

생성자 호출 

: new 클래스명(입력인수, ...)

 

{new 키워드로 객체를 만들 때 문자열 전달해야함.}

 

즉 문자열 전달이 되지 않아서 위에서 null 이 나온겨.

 

<디폴트 생성자>

class Dog extends Animal {
    Dog() {
    }

    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

 

위의 코드 중

 Dog() {
    }

 

이 부분을  디폴트 생성자 : 생성자의 입력 항목 X, 생성자 내부에 내용 X

 

IF, 클래스에 생성자 X : 컴파일러 자동으로 디폴트 생성자 추가

 

<생성자 오버로딩>

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

class HouseDog extends Dog {
    HouseDog(String name) {
        this.setName(name);
    }

    HouseDog(int type) {
        if (type == 1) {
            this.setName("yorkshire");
        } else if (type == 2) {
            this.setName("bulldog");
        }
    }

    void sleep() {
        System.out.println(this.name + " zzz in house");
    }

    void sleep(int hour) {
        System.out.println(this.name + " zzz in house for " + hour + " hours");
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog happy = new HouseDog("happy");
        HouseDog yorkshire = new HouseDog(1);
        System.out.println(happy.name);  // happy 출력
        System.out.println(yorkshire.name);  // yorkshire 출력
    }
}

 

두개의 생성자 존재 

  1. String 자료형을 입력으로 받는 생성
                                                                →  차이 : 입력 항목
  2. int 자료형을 입력으로 받는 생성자                  

 

[5-7] 인터페이스

 

<인터페이스는 왜 필요한가?>

 

난 동물원(zoo)의 사육사(zookeeper)이다.

육식동물(predator)이 들어오면 난 먹이를 던져준다(feed).

호랑이(tiger)가 오면 사과(apple)를 던져준다.

사자(lion)가 오면 바나나(banana)를 던져준다.

 

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Tiger extends Animal {
}

class Lion extends Animal {
}

class ZooKeeper {
    void feed(Tiger tiger) {  // 호랑이가 오면 사과를 던져 준다.
        System.out.println("feed apple");
    }

    void feed(Lion lion) {  // 사자가 오면 바나나를 던져준다.
        System.out.println("feed banana");
    }
}

public class Sample {
    public static void main(String[] args) {
        ZooKeeper zooKeeper = new ZooKeeper();
        Tiger tiger = new Tiger();
        Lion lion = new Lion();
        zooKeeper.feed(tiger);  // feed apple 출력
        zooKeeper.feed(lion);  // feed banana 출력
    }
}

 

출력값 :

feed apple

feed banana

 

그런데 ZooKeeper는 클래스 추가될 때 마다 feed 메서드 추가해야함.

그런데 일일히 하면 너무 복잡해.

이때 ! 인터페이스 !

 

<인터페이스 작성하기>

 

interface Predator {
}

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

(... 생략 ...)

 

인터페이스 작성시     

: interface !!!!!!!! 키워드 추가

(... 생략 ...)

class Tiger extends Animal implements Predator {
}

class Lion extends Animal implements Predator {    
}

(... 생략 ...)

 

implements 키워드 : Tiger, Lion 클래스 인터페이스 구현

 

(... 생략 ...)

class ZooKeeper {
    void feed(Tiger tiger) {
        System.out.println("feed apple");
    }

    void feed(Lion lion) {
        System.out.println("feed banana");
    }
}

(... 생략 ...)

                                                                                 ↓

(... 생략 ...)

class ZooKeeper {
    void feed(Predator predator) {
        System.out.println("feed apple");
    }
}

(... 생략 ...)

 

feed 메서드 입력 : Tiger, Lion → Predator 인터페이스 대체

 

IS-A 관계 : 인터페이스에도 적용 

 

  • tiger: Tiger 클래스의 객체이자 Predator 인터페이스의 객체
  • lion: Lion 클래스의 객체이자 Predator 인터페이스의 객체

보통 중요 클래스(ZooKeeper)를 작성하는 시점에서 클래스(Animal)의 구현체(Tiger, Lion)가 몇 개가 될지 알 수 없으므로 인터페이스(Predator)를 정의하여 인터페이스를 기준으로 메서드(feed)를 만드는 것이 효율적

 

<인터페이스의 메서드>

(... 생략 ...)

class ZooKeeper {
    public void feed(Predator predator) {
        System.out.println("feed apple");  // 항상 feed apple 만을 출력한다.
    }
}

(... 생략 ...)

 

출력

: feed apple

  feed apple

 

 

▶ Predator 인터페이스에 getFood 메서드 추가

interface Predator {
    String getFood();
}

(... 생략 ...)

 메서드에 몸통 X 

 

인터페이스의 메서드는 메서드의 이름과 입출력에 대한 정의만 있고 그 내용은 없다

이유 : 인터페이스 = ' 규칙 ' 

 

(... 생략 ...)

class Tiger extends Animal implements Predator {
    public String getFood() {
        return "apple";
    }
}

class Lion extends Animal implements Predator {
    public String getFood() {
        return "banana";
    }
}

(... 생략 ...)

Tiger, Lion 클래스의 getFood 메서드 : 각각 apple과 banana 리턴

 

인터페이스의 메서드 : 항상 public으로 구현 !!!!!

 

ZooKeeper 클래스 변경

(... 생략 ...)

class ZooKeeper {
    void feed(Predator predator) {
        System.out.println("feed "+predator.getFood());
    }
}

(... 생략 ...)

 수정 feed 메서드 : feed apple"feed "+predator.getFood()

 

<인터페이스 더 파고들기>

 

ZooKeeper 클래스 :  동물 클래스에 의존적인 클래스   동물 클래스와 상관없는 독립적인 클래스가 되었다는 점

 

     상속 vs 인터페이스 

  • 상속 : 강제성 X 
  • 인터페이스 : 강제성O

 

 

<디폴트 메서드>

인터페이스의 메서드 : 구현체 X 

                                     but, 디폴트 메서드 사용 →  실제 구현된 형태의 메서드 O

 

디폴트 메서드 : 메서드명 가장 앞에 default라고 표기  , 오버라이딩 가능 

 

[5-8] 다형성 

 

반응형