Java - 상속

김민1·2023년 2월 8일
3

Java

목록 보기
4/8

상속

class 자식클래스 extends 부모클래스 {}

상속은 이미 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드를 줄여줌
현실에서 부모가 자식에게 물려주는 것이라고 보면 됨

하지만 현실과 다른 점은 현실에선 부모가 자식을 선택해서 상속해주지만
프로그래밍에서의 상속은 자식이 부모를 선택함

특징

  1. 여러 개의 부모 클래스를 상속할 수 없음 (다중상속 불가, extends 뒤에는 하나의 부모 클래스만)

  2. 부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외됨
    또한 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면
    default 접근 제한을 갖는 필드와 메소드 또한 상속 대상에서 제외됨

부모 생성자 호출

현실에서 부모 없는 자식이 없듯이 자바에서도 자식 객체를 생성하면 부모 객체가 먼저 생성됨


super

super()는 부모의 기본 생성자를 호출

super(매개값, ...)는 매개값의 타입과 일치하는 부모 생성자를 호출
만약 매개값의 타입과 일치하는 부모 생성자가 없을 경우 컴파일 에러 발생

super(매개값, ...)가 생략되면 컴파일러에 의해 super()가 자동적으로 추가되기 때문에 부모의 기본 생성자가 존재해야 함. 또한 자식 생성자 첫 줄에 위치해야 함


메소드 재정의(Overriding)

매소드 재정의는 자식 클래스에서 부모 클래스의 메소드를 다시 정의하는 것을 말함

메소드가 재정의 되었다면 부모 객체의 메소드는 숨겨짐 -> 자식 객체에서 호출하면 재정의된 자식 메소드 호출

메소드 재정의할 때의 주의점

  • 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 목록)를 가져야 함
  • 접근 제한을 더 강하게 재정의 할 수 없음 (반대로 더 약하게는 할 수 있음)
  • 새로운 예외(Exception)를 throws할 수 없음

부모 메소드 호출

자식 클래스에서 부모 클래스의 메소드를 재정의하게 되면, 부모 클래스의 메소드는 숨겨지고
재정의된 자식 메소드만 사용됨. but 자식 클래스 내부에서 재정의된 부모 클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여 부모 메소드 호출 가능

super.부모메소드();

final 클래스와 final 메소드

final 키워드는 클래스, 필드, 메소드를 선언할 때 사용될 수 있음(but 각각 해석이 조금씩 달라짐)
final은 최종 상태이고 결코 수정될 수 없음을 의미
필드를 선언할 때 final이 지정되면 초기값 설정 후 더 이상 값을 변경할 수 없음

클래스와 메소드를 선언할 때 final 키워드가 지정됨 -> 상속과 관련이 있다는 의미

상속할 수 없는 final 클래스

클래스 선언 시 class 앞에 final 키워드를 붙이면 이 클래스는 최종적인 클래스라는 뜻
-> 상속할 수 없는 클래스가 됨 -> 부모 클래스가 될 수 없음 -> 자식 클래스를 만들 수 없음

재정의할 수 없는 final 메소드

메소드 선언 시 final 키워드를 붙이면 이 메소드는 최종적인 메소드라는 뜻
-> 재정의 할 수 없는 메소드 -> 부모 클래스를 상속해서 자식 클래스를 선언할 때 부모 클래스에 선언된 final 메소드는 자식 클래스에서 재정의 불가

마치며

OOP 4가지 특성 중 한 부분인 상속(상속화)인만큼
객체지향프로그래밍을 공부할 때 꼭 알아야 되는 부분이라고 생각해 글을 남기게 되었습니다.

수정할 사항이나 추가할 사항이 있으면 댓글이나 이메일을 남겨주세요.

아래는 공부하며 작성한 코드입니다.


Main.java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("자동차 내기 게임입니다.");
        System.out.println("당신은 자동차를 몰고 있으며, 이동할 때 마다 타이어가 닳게 됩니다.");
        System.out.println("처음 타이어의가 펑크나는 시점은 랜덤(최대 내구도 20)이며 펑크가 날 때 마다 타이어는 교체됩니다.");
        System.out.println("교체된 타이어 또한 펑크나는 시점은 랜덤(최대 내구도 15)입니다.");
        System.out.println("펑크가 많이 나는 사람이 이기는 방법도 있고 적게 나는 사람이 이기는 방법도 있고 근사치를 맞추는 사람이 이기는 방법도 있습니다.");
        System.out.println("하지만 지켜야할 룰로는 모든 사람이 같은 칸을 입력해야 합니다.");
        System.out.println("몇 칸을 이동하시겠습니까?");
        System.out.print("이동하실 칸을 입력해주세요 :");
        Scanner sc = new Scanner(System.in);

        int destination = sc.nextInt();

        Car car = new Car();

        for(int i = 0;i<=destination;) {
            int problemLocation = car.run();
            System.out.println("--------------------------");
            System.out.println("남은 칸 수: " + destination);
            System.out.println("--------------------------");
            switch(problemLocation) {
                case 1 :
                    System.out.println("전면 좌측 KumhoTire로 교체");
                    car.frontLeftTire = new KumhoTire("전면 좌측", (int) (Math.random()*16));
                    break;
                case 2 :
                    System.out.println("전면 우측 KumhoTire로 교체");
                    car.frontRightTire = new KumhoTire("전면 우측", (int) (Math.random()*16));
                    break;
                case 3 :
                    System.out.println("후면 좌측 KumhoTire로 교체");
                    car.rearLeftTire = new KumhoTire( "후면 좌측", (int) (Math.random()*16));
                    break;
                case 4 :
                    System.out.println("후면 우측 KumhoTire로 교체");
                    car.rearRightTire = new KumhoTire("후면 우측", (int) (Math.random()*16));
                    break;
            }
            destination--;
        }
        System.out.println("\n\n\n\n");
        System.out.println("--------------------------");
        System.out.println("펑크난 횟수 : "+ Tire.funk_times);
        System.out.println("--------------------------");

    }
}

Tire.java


public class Tire {

    int maxRotation;
    int accumulatedRotation;
    String location;

    static int funk_times;
    public Tire(String location, int maxRotation) {
        this.location = location;
        this.maxRotation = maxRotation;
    }

    public boolean roll() {
        ++accumulatedRotation;

        if (accumulatedRotation < maxRotation) {
            System.out.println(location + "Tire 수명: " + (maxRotation - accumulatedRotation));
            return true;
        } else {
            System.out.println("*** " + location + " Tire 펑크 ***");
            funk_times++;
            return false;
        }
    }

}

KumhoTire.java

public class KumhoTire extends Tire{

    public KumhoTire(String location, int maxRotation) {
        super(location, maxRotation);
    }

    public boolean roll() {
        ++accumulatedRotation;
        if(accumulatedRotation < maxRotation) {
            System.out.println(location + "KumhoTire 수명: " + (maxRotation - accumulatedRotation) + "회");
            return true;
        }
        else {
            System.out.println("*** " + location + "KumhoTire 펑크 ***");
            return false;
        }
    }
}

Car.java

public class Car {
    int num1 = (int) (Math.random() * 21);
    int num2 = (int) (Math.random() * 21);
    int num3 = (int) (Math.random() * 21);
    int num4 = (int) (Math.random() * 21);

    Tire frontLeftTire = new Tire("전면 왼쪽", num1);
    Tire frontRightTire = new Tire("전면 오른쪽", num2);
    Tire rearLeftTire = new Tire("후면 왼쪽", num3);
    Tire rearRightTire = new Tire("후면 오른쪽", num4);

    int run() {
        System.out.println("자동차가 달리는 중");
        if(frontLeftTire.roll()==false) {stop();return 1;};
        if(frontRightTire.roll()==false) {stop();return 2;};
        if(rearLeftTire.roll()==false) {stop();return 3;};
        if(rearRightTire.roll()==false) {stop();return 4;};
        return 0;
}

void stop () {
    System.out.println("자동차가 멈춤");}

}


profile
일단 부딪혀보자

1개의 댓글

comment-user-thumbnail
2023년 4월 11일

저도 디자인을 공부하며 상속에 대해서 배워서 그런지 더 흥미롭군요

답글 달기