<Java> 상속, 오버라이딩, package

·2023년 6월 9일
0

Java

목록 보기
7/7

상속 (inheritance)

extends 키워드를 사용한다.

  • 기존의 클래스를 재사용해서 새로운 클래스를 작성하는 것.
  • 두 클래스를 조상과 자손으로 관계를 맺어주는 것.
  • 자손은 조상의 모든 멤버를 상속받는다. (생성자와 초기화블럭 제외)
  • 자손의 멤버 개수는 조상보다 적을 수 없다. (같거나 많을 뿐)
  • Java에서는 다중 상속을 지원하지 않는다. (단일 상속 지원)
    - 이유 : 복잡성이 커지기 때문에

⭐️ 부모의 인스턴스가 먼저 만들어지고 자식의 인스턴스가 만들어진다.

class Point {
	int x;
    int y;
}

class Point3D(자손 클래스) extends Point(조상 클래스) { // Point3D는 Point 클래스를 상속
	int z;
}

// 최종 결과 (Point3D)
class Point3D {
	int x; // int x, int y를 상속받고 int z를 생성.
    int y;
    int z;
}

클래스간의 관계

상속 관계(inheritance)

Truck is a Car 관계. is a
자식은 부모를 대신할 수 있지만, 부모가 자식을 대신 할 수 없음.

즉, 뒤집어서 Car is a Truck는 말이 안된다.

  • 공통 부분은 조상에서 관리하고 개별부분은 자손에서 관리한다.
  • 조상의 변경은 자손에 영향을 미친다. 하지만 자손의 변경은 조상에 영향을 미치지 않는다.
  • 클래스의 계층 구조가 만들어진다. 아래서 위로 ➡️ 일반화
  • 위에서 아래로 ➡️ 구체화(상세화)

포함 관계(composite)

__has a __ 관계.

  • 다른 객체의 레퍼런스를 가지고 있는 것
  • 한 클래스의 멤버변수로 다른 클래스를 선언하는 것
  • 작은 단위의 클래스를 먼저 만들고, 이들을 조합해서 하나의 커다란 클래스를 만든다.
class Car {
	Engine e = new Engine(); // 엔진
    Door[] d = new Door[4]; // 문, 문의 개수를 넷으로 가정하고 배열로 처리
}

관계 결정하기 (상속, 포함)

  • 가능한 많은 관계를 맺어주어 재사용성을 높이고 관리하기 쉽게 한다.
  • is-ahas-a를 가지고 문장을 만들어 본다.

원(Circle)은 점(Point)이다. Circle is a Point
원(Circle)은 점(Point)을 가지고 있다. Circle has a Point

상속관계 ) ~은 ~이다. (is-a)
포함관계 ) ~은 ~을 가지고있다. (has-a)

단일 상속 (Single Inheritance)

Java는 단일상속만을 허용한다.

class TVCR extends TV, VCR { // 이와같은 표현은 허용되지 않음.
	// ... 
}

Object 클래스 - 모든 클래스의 최고 조상

모든 Java 클래스가 필수적으로 필요한 기능을 정의한 것이 기본 Object이다.

기본 Object를 상속받아 오버라이딩하여 재정의하고 사용할 수 있어야 한다.

  • 조상이 없는 클래스는 자동적으로 Object 클래스를 상속받게 된다.
  • 상속 계층도의 최상위에는 Object 클래스가 위치한다.
  • 모든 클래스는 Object 클래스에 정의된 11개의 메서드를 상속받는다.
    toString(), equals(Object obj), hashCode() 등등..

부모로부터 상속받은 것을 재정의 ➡️ 오버라이딩
오버라이딩하여 재사용 할 수 있어야 한다.

오버라이딩 (Over Riding)

조상클래스로 부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것을 오버라이딩이라고 한다.**

입맛에 맞게 속성을 재정의한다.

사전적 의미 : ~위에 덮어쓰다, ~에 우선하다

🔥 기존 상속받은 메서드의 내용을 변경할 수 없다. (이름, 반환형, 매개변수)

오버라이딩의 조건

  1. 선언부가 같아야 한다. 이름, 매개변수, 리턴타입
  2. 접근제어자를 좁은 범위로 변경할 수 없다.
    • 조상의 메서드가 protected라면, 범위가 같거나 넓은 protected나 public으로만 변경 가능.
  3. 조상클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

오버로딩 vs 오버라이딩

오버로딩

기존에 없는 새로운 메서드를 정의 new 키워드

오버라이딩

상속받은 메서드의 내용을 변경하는 것

오버라이딩 예시 코드

// parent class
package chap07;

public class Account {
    String accountNo;
    String name;
    int balance;

    void deposit(int amount) {
        balance += amount;
    }

    int withDraw(int amount) {
        if(amount > balance) {
            amount = -1; // 잔액 부족, 출금 불가능.
        } else {
            balance -= amount; // 현재 계좌 금액에서 인출
        }

        return amount;
    }


}

// parent class를 끌어와서 오버라이딩 한 class
package chap07;

public class CreditLineAccount extends Account {
    int creditLine;

    CreditLineAccount(int creditLine) {
        this.creditLine = creditLine;
    }

    int withDraw(int amount) { // Account에 있던 것을 재정의
        if(amount > (balance + creditLine)) { // 200만 > 150만 + 500만 => else문으로
            amount = -1; // 잔액 부족, 하지만 출금 가능_마이너스 통장
        } else {
            balance -= amount; // 현재 계좌 금액에서 인출
        }

        return amount;
    }

}

// main
package chap07;

public class Ex3 {
    public static void main(String[] args) {
        CreditLineAccount cAccount = new CreditLineAccount(5000000);
        System.out.println(cAccount.creditLine);

        cAccount.accountNo = "A1234";
        cAccount.name = "김철수";
        cAccount.balance = 1000000;

        cAccount.deposit(500000);
        System.out.println("현재 잔액 : " + cAccount.balance); // 150만

        if(cAccount.withDraw(2000000) == -1) { // WTF
            System.out.println("현재 잔액이 부족합니다. ");
            System.out.println("현재 잔액 : " + cAccount.balance);
        } else {
            System.out.println("현재 잔액 : " + cAccount.balance);
            System.out.println("else문 실행");
        }

        if(cAccount.withDraw(10000000) == -1) {
            System.out.println("현재 잔액이 부족합니다. ");
            System.out.println("현재 잔액 : " + cAccount.balance);
        } else {
            System.out.println("현재 잔액 : " + cAccount.balance);
            System.out.println("else문 실행");
        }
    }
}

super / super()

부모 Class의 생성자가 먼저 호출된다.

super

부모의 레퍼런스 변수다.

숨겨진 부모의 변수를 명시적으로 불러옴.

자식 클래스의 인스턴스를 생성하면 자동으로 부모 클래스의 인스턴스가 먼저 만들어진다.
그 후, 나중에 자식의 인스턴스가 만들어진다.

super()

숨겨진 부모의 생성자를 명시적으로 호출할 때, 사용한다.

매개변수가 있는 부모 생성자를 명시적으로 호출할 때.

먼저 생성되어지는 부모의 인스턴스는 디폴트로 매개변수가 없는 생성자를 이용해서 만들어진다.

만약, 부모클래스에 매개변수 없는 생성자가 없다면?
=> == 매개변수가 있는 생성자만 존재한다. 부모 인스턴스가 안 만들어진다.
자동으로 생성되는 생성자 ➡️ 매개변수가 없는 생성자만 가능.
생성자에 매개변수가 있다면, 자동으로 생성되지 않는다.

이 때, super()를 사용한다.
매개변수가 있는 생성자를 상속하려면? super()로 끌어다 온다.

// parent
package chap07;

public class Parent {
    String name;
    Parent(String name) {
        this.name = name;
        System.out.println("Parent 인스턴스 생성");
    }

    void methodA() {
        System.out.println("Parent 클래스 methodA()입니다.");
    }


}


// child
package chap07;

public class Child extends Parent {
    String gender;

    Child(String name, String gender) {
        super(name); // 부모 인스턴스로 먼저 초기화
        this.gender = gender;
        System.out.println("Child 인스턴스 생성");
    }

    void methodA() {
        super.methodA(); // 상속받은 부모 methodA() 출력. super. 키워드를 이용하면 가능하다.
        System.out.println("Child 클래스 methodA()입니다.");
    }
}

// main
package chap07;

public class Ex4 {
    public static void main(String[] args) {
        Child child = new Child("손흥민", "남자");
        //        child.methodA(); // 오버라이딩 한 Child 클래스 methodA() 출력;
        System.out.println(child.name + " : " + child.gender);
    }
}

패키지 (Package)

  • 서로 관련된 클래스와 인터페이스의 묶음
  • 클래스가 물리적으로 클래스파일(*.class)인 것처럼, 패키지는 물리적으로 폴더이다.
  • 패키지는 서브패키지를 가질 수 있으며, .으로 구분한다. == 하위폴더를 가질 수 있다는 뜻.
  • 클래스의 실제 이름은 패키지명이 포함된 것이다.
profile
- 배움에는 끝이 없다.

0개의 댓글