코딩하는 털보

STUDY HALLE - 6주차 본문

Diary/Study Halle

STUDY HALLE - 6주차

이정인 2021. 1. 6. 06:12

STUDY HALLE

6주차 : 상속


목표

자바의 상속에 대해 학습하세요.

학습할 것

  • 자바 상속의 특징

  • super 키워드

  • 메소드 오버라이딩

  • 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

  • 추상 클래스

  • final 키워드

  • Object 클래스


자바의 상속

이미 구현되어 있는 기존 클래스의 속성과 기능을 그 하위 클래스에서 사용하는 것을 상속이라고 한다.

기존의 클래스를 상속받아 기능을 확장하거나 새로 구현할때 사용할 수 있다.

이러한 상속 관계에 있는 상위 및 하위 클래스를 수퍼 클래스와 서브 클래스 또는 부모 클래스와 자식 클래스라고 한다.

참조 : 위키백과 상속 (객체 지향 프로그래밍)

클래스 상속받기

class B extends A {
    ...
}

인터페이스 상속받기

interface B extends A {
    ...
}

자바에서는 클래스의 다중 상속이 불가능하다.

//컴파일 에러가 발생함    
public class Child extends Father, Mother{
    ...
}

인터페이스는 다중 상속이 가능하다.

public interface Child extends Father, Mother{
    ...
}

상위 클래스의 private class, method, variable은 상속받아 사용할 수 없음을 알고있자.

하위 클래스 객체의 생성에는 항상 상위 클래스 객채의 생성이 동반되는데,

아무런 상위 클래스 생성자 호출 명령 없이 하위 클래스를 생성하면 상위 클래스의 기본 생성자가 호출된다.

만약 상위 클래스의 기본 생성자가 없으면, 명시적으로 상위 클래스의 생성자를 호출해야 한다.

public class Father {
    public Father(String string) {
        System.out.println(string);
    }
}
public class Child extends Father{
    public Child() {
        super("My"); //상위 클래스 생성자 명시적 호출
        System.out.println("child");
    }
}

super 키워드에 대하여

하위 클래스 객체가 만들어질 때 같이 생성된 상위 클래스 객체를 하위 클래스 객체에서 참조하는 참조변수이다.

  • super() : 상위 클래스의 기본 생성자 호출한다.
  • 부모 클래스의 인스턴스 변수를 참조할 때 사용한다.
  • 부모 클래스의 메소드를 호출할 때 사용한다.
class Animal {
    public String type;
    public void move() {
        System.out.println("동물이 움직입니다.");
    }
}

class Human extends Animal {

    @Override
    public void move() {
        super.move(); //부모 클래스의 메소드 호출
        super.type = "포유류"; //부모 클래스의 인스턴스 변수 참조
        System.out.println("사람이 두 발로 걷습니다.");
    }
}

메소드 오버라이딩

상위 클래스에 정의된 메소드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우, 하위 클래스에서 동일한 이름의 메소드를 재정의할 수 있다.

오버라이딩을 할때는 보통 @Override 어노테이션을 사용한다.

상위 클래스

    public int calcPrice(int price) { 
        bonusPoint += price*bonusRatio;
        return price;
    }

하위 클래스

    @Override
    public int calcPrice(int price) { //상위 클래스의 메소드와 선언부가 동일해야 한다
        bonusPoint += price*bonusRatio;
        return price - (int)(price*salesRatio);
    }

다이나믹 메소드 디스패치

동적 디스패치(dynamic dispatch)는 메소드 오버라이딩이 되어있는 경우 런타임 시점에 어떤 메소드를 실행할 지 결정되는 것이다. 정적 디스패치는 그와 다르게 컴파일 시점에 어떤 메소드를 실행할지 결정된다.

참조 : 위키백과 동적 디스패치

예를들어, 상위 클래스 Animal의 move 메소드를 오버라이딩 하는 하위 클래스들이 있다고 가정했을때,

컴파일러는 컴파일 시점에 어떤 move 메소드가 실행될 지 알 수 없기 때문에

실행 시점에서 객체의 타입을 확인한 뒤 메소드를 결정한다.

class Animal {

    public void move() {
        System.out.println("동물이 움직입니다.");
    }
}
class Human extends Animal {

    @Override
    public void move() {
        System.out.println("사람이 두 발로 걷습니다.");
    }
}

class Tiger extends Animal {

    @Override
    public void move() {
        System.out.println("호랑이가 네 발로 뜁니다.");
    }
}

class Eagle extends Animal {

    @Override
    public void move() {
        System.out.println("독수리가 하늘을 날아갑니다.");
    }
}
class AnimalTest {

    @Test
    public void test() {
        Animal animal = new Animal();
        Animal human = new Human();
        Animal tiger = new Tiger();
        Animal eagle = new Eagle();

        List<Animal> animalList = new ArrayList<>();
        animalList.add(animal);
        animalList.add(human);
        animalList.add(tiger);
        animalList.add(eagle);

        //Animal.move() 메소드가 실행시점에 결정된다.
        for (Animal ani : animalList) {
            ani.move();
        }
        //동물이 움직입니다.
        //사람이 두 발로 걷습니다.
        //호랑이가 네 발로 뜁니다.
        //독수리가 하늘을 날아갑니다.
    }
}

추상 클래스

추상 메소드를 포함한 클래스, 클래스 생성에서 abstract 키워드를 사용한다. new(인스턴스화) 할 수 없으며 인터페이스와 매우 유사하다.

상속 관계에서 상위 클래스로 사용되며 추상 메소드는 하위 클래스에서 꼭 구현되어야 한다.

추상 메소드 : 구현부 없이 선언부만 있는 메소드.

abstract class AbsClass {
    public abstract void absMethod();
}
public class Child extends Mother{
    //상위 클래스의 모든 추상 메소드들을 구현해주지 않으면 컴파일 에러가 발생한다.
    //만약 구현하지 않거나 부분만 구현해야 할 경우 abstract 클래스가 되어야 한다.
    @Override
    public void hello() {
        ...
    }
}

final 키워드에 대하여

final class {
    final String ID = "ID";
    final void unChangeable() {
        ...
    }
}

final 변수 : 변경될 수 없는 상수

final 메소드 : 하위 클래스에서 재정의 할 수 없음

final 클래스 : 더 이상 상속될 수 없는 클래스

디자인 패턴의 일종으로 추상 클래스와 final을 사용하는 템플릿 메소드 패턴이 있다.

추상 클래스로 선언된 상위 클래스에서 추상 메소드를 이용하여 전체 구현의 흐름을 정의하고, 각 메소드의 구체적인 구현은 하위 클래스에 위임하는 패턴이다. 하위 클래스에서 어떻게 구현을 하든지 템플릿 메소드에 정의된 흐름대로 수행된다.

public abstract class Car {

    public abstract void drive(); //훅메소드, 하위 클래스에서 재정의 용으로 생성
    public abstract void stop();

    public void startCar() {
        System.out.println("시동을 켭니다.");
    }
    public void turnOff() {
        System.out.println("시동을 끕니다.");
    }

    public void washCar() {}; //훅메소드이지만, 구현의 강제성이 없음.

    final public void run() { //템플릿 메소드
                              //흐름이 정의되어있다.
        startCar();
        drive();
        stop();
        turnOff();
        washCar();
    }
}

Object 클래스

모든 클래스의 최상위 클래스이다.

  • 모든 클래스는 Object 클래스를 상속 받는다.
  • 모든 클래스는 Object 클래스의 메소드를 사용할 수 있다.
  • 모든 클래스는 Object 클래스의 일부 메소드를 재정의하여 사용할 수 있다.
    (final로 정의된 메소드 제외.)

Object 클래스의 메소드

  • toString()
    • 객체의 정보를 String으로 바꿀 때 사용하는 메소드이다.
    • 자바에서 제공되는 클래스들에서는 이미 재정의 되어있는 경우가 많다. (String, Integer, Calendat, ...)
class Book{
    String title;
    String author;

    public Book(String title,String author) {
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return "title='" + title + '\'' + ", author='" + author + '\'';
    }
}
  • equals()

    • 두 객체의 논리적인 동일성을 확인하는 메소드이다.
    • 객체 마다의 논리적인 동일함을 구현하기 위해 재정의하여 사용한다.
    • 물리적인 동일(==, 메모리 주소)과 다르다.
  • hashCode()

    • 인스턴스가 저장된 가상머신의 주소를 10진수로 반환한다. (각 객체의 고유한 값)

    • 객체의 동일성을 구현하기 위해 재정의하여 사용한다.

학번으로 학생 구분하기

class Student {
    int studentNum;
    String studentName;

    public Student(int studentNum, String studentName) {
        this.studentNum = studentNum;
        this.studentName = studentName;
    }

    public boolean equals(Object object) {
        if (object instanceof Student) {
            Student student = (Student)object;
            if (this.studentNum==student.studentNum) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return studentNum;
    }
}
  • clone()
    • 객체의 복사본을 만들 때 사용한다.
    • 기본 틀로부터 같은 속성 값을 가진 객체의 복사본을 생성할 수 있다.
class Book implements Cloneable{ //마크인터페이스 Cloneable : 이 클래스는 복제 가능하다는 것을 명시한다.
    String title;
    String author;

    public Book(String title,String author) {
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return "title='" + title + '\'' + ", author='" + author + '\'';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  • finalize()
    • 인스턴스가 힙메모리에서 해제될 때 가비지 콜렉터에서 호출되는 메서드이다.
    • 주로 리소스 해제 또는 소켓 닫기 등에 사용된다.
Comments