JAVA(상속)

김민성·2023년 7월 6일

JAVA

목록 보기
6/11

상속

: 이미 잘 개발된 부모 클래스를 재사용해 자식 클래스에게 물려주기 때문에 중복되는 코드를 줄여 개발 시간을 단축시킴

  • IS - A 관계 (가장 추상적인 클래스가 부모 클래스)
    -> Notebook is a Computer (O)
    -> Coputer is a Notebook (X)

클래스 상속

: 사실 자식이 부모를 선택하는 방법

  • extends 키워드로 부모 클래스 상속
  • 자바에서는 여러 클래스 상속 불가

부모 생성자 호출

: 자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체 생성

자식클래스 변수 = new 자식클래스();

  • 생성자가 없을 경우 자동으로 no-parameter 생성자가 만들어짐
    -> 생성자가 하나라도 있을 경우 자동으로 만들어지지 않음
  • 모든 자식클래스의 생성자는 먼저 부모클래스의 생성자 호출
    -> super()를 통해 명시적으로 호출
    -> 그렇지 않을 경우, 자동으로 no-parameter 생성자 호출
  • 부모클래스에 no-parameter 생성자가 없는데 자식클래스의 생성자에서 super()호출을 안 해주는 오류 흔함

메소드 오버라이딩

: 부모 클래스의 메소드가 자식 클래스에 딱 맞지 않을 때, 자식 클래스에서 메소드를 재정의해서 사용하는 것

규칙

  • 부모 메소드의 선언부(리턴 타입, 메소드 이름, 매개변수)와 동일
  • 접근 제한을 더 강하게 오버라이딩 불가
    -> public에서 private으로 변경 불가
  • 새로운 예외 throws 불가

부모 메소드 호출

: 메소드를 재정의하면 자식 메소드에서 1줄만 추가하고 싶더라도 부모 메소드의 내용을 다시 작성해야 함
-> 공동 작업 처리 기법 이용하여 해결

class Parent {
	public void method() {
    	...
    }
}

class Child extends Parent {
	@Override
    // 재정의된 메소드
    public void method() {
    	super.method();
    }
}
  • super.method()로 부모 메소드를 호출함으로써 자식 메소드에서 중복 코딩을 방지할 수 있음

final 클래스와 final 메소드

final 클래스

: final을 붙이면 더 이상 상속할 수 없는 클래스가 됨
-> 자식을 만들 수 없음

  • 대표적인 예가 String 클래스

final 메소드

: final을 붙이면 오버라이딩 할 수 없는 메소드가 됨
-> 부모클래스에 선언된 final 메소드는 자식 클래스에서 재정의 못 함

protected 접근 제한자

  • protected는 같은 패키지에선 default처럼 접근 가능하나, 다른 패키지에서는 자식 클래스만 접근 허용
  • new 연산자로 생성자 직접 호출할 수는 없고, 자식 생성자에서 super()로 호출해야 함

자동 타입 변환

: 클래스의 타입 변환은 상속 관계에 있는 클래스 사이에서 발생

Cat cat = new Cat();
// 부모타입 변수 = 자식타입 객체
Animal animal = cat;

Animal animal = new Cat();
  • 부모 타입으로 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능
  • 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로 한정됨
  • 그러나 자식 클래스에서 오버라이딩된 메소드가 있다면 부모 메소드 대신 오버라이딩된 메소드가 호출됨.

강제 타입 변환

  • 부모 타입 객체를 자식타입 변수로 무조건 강제 변환할 수 있는 것은 아님
    -> 자식 객체가 부모 타입으로 자동 변환 된 후 다시 자식 타입으로 변환될 때 강제 타입 변환 사용 가능
  • 자식 객체가 부모 타입으로 자동 변환 되면 부모 필드, 메소드만 사용해야 하는 제약
    -> 자식 필드, 메소드 꼭 사용해야 하면 강제 타입 변환

다형성

: 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질

  • 부모 타입 변수가 자식 타입의 객체를 참조할 수 있다.
  • 다형성을 구현하기 위해서는 자동 타입 변환과 메소드 재정의
    가 필요
  • 객체 사용 방법이 동일하다는 것은 동일한 메소드를 가지고 있다는 뜻
  • 타이어 : 부모 메소드 / 금호 타이어 : 자식 메소드 / 한국 타이어 : 자식 메소드
  • 한국 타이어와 금호 타이어가 타이어 메소드를 오버라이딩 하고 있다면, 타이어 메소드 호출 시 오버라이딩된 메소드가 호출됨
  • 오버라이딩된 내용은 두 타이어가 다르기 때문에 실행 결과가 다름

필드 다형성

: 필드 타입은 동일하지만 대입되는 객체가 달라져서 실행 결과가 다르게 나올 수 있는 것

public class Car {
	publit Tire tire;
    
    public void run() {
    	tire.roll();
    }
}

public class Tire {
	public void run() {
    	System.out.println("타이어가 회전합니다.");
    {
}

public class HanKookTire extends Tire() { 
	public void run(){
    	System.out.println("한국 타이어가 회전합니다.")
    }
}

public class KumHoTire extends Tire() { 
	public void run(){
    	System.out.println("금호 타이어가 회전합니다.")
    }
}

public static void main(String [] args) {
	Car myCar = new Car();
    
    myCar.tire = new Tire();
    myCar.run();
    
    myCar.tire = new HanKookTire();
    myCar.run();
    
    myCar.tire = new KumHoTire();
    myCar.run();

매개변수 다형성

: 다형성은 필드보다는 메소드를 호출할 때 자주 발생. 메소드가 클래스 타입의 매개변수를 가지고 있을 경우, 호출할 때 동일한 타입의 객체를 제공하는 것이 정석이지만 자식 객체를 제공할 수도 있음. 여기서 다형성이 발생.

  • Driver 클래스의 drive 메소드의 매개 변수로 Vehicle 타입이 오는 상황
public class Driver() {
	public void drive(Vehicle vehicle) {
    	vehicle.run();
    }
}

Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
  • 위 상황에서 매개변수로 Vehicle객체만 제공할 수 있는 것이 아닌 자동 타입 변환으로 인해 Vehicle의 자식 객체들도 제공할 수 있음
  • drive()메소드는 매개변수로 오는 vehicle이 참조하는 객체의 run()메소드에 따라 결과값이 달라지므로 매개변수로 인해 다형성이 발생하는 것.

객체 타입 확인

: 변수가 참조하는 객체의 타입을 확인하고자 할 때, instanceof 연산자 사용

boolean result = 객체 instanceof 타입;
  • 강제 타입 변환 전 Child 타입인지 확인하는 코드
  • 강제 타입 변환을 하는 이유는 Child 객체의 모든 멤버(필드, 메소드)에 접근하기 위해서
public void method(Parent parent) {
	if (parent instanceof Child child) {
    	// child 변수 그냥 사용
        // true이면 강제 타입 변환이 필요 없음
    }
}

추상 클래스

: 클래스들의 공통 필드, 메소드를 추출해서 선언한 클래스

  • 실체 클래스를 만들기 위한 부모 클래스로만 사용됨
    -> 추상 클래스를 상속 받아 공통 필드, 메소드 물려받아서 재정의
  • 실체 클래스의 공통 필드와 메소드를 추출해서 만들었기 때문에 new 연산자를 사용해서 객체를 직접 생성할 수 없다.
  • 필드와 메소드를 선언할 수 있고, 자식 객체가 생성될 때 super()로 추상 클래스의 생성자가 호출되기 때문에 생성자도 반드시 있어야 한다.

추상 메소드 / 재정의

: 공통 메소드를 뽑아내어 추상 메소드를 만들 때, 선언부만 동일하고 실행 내용은 달라야 하는 경우가 많다.
-> ex) Animal 클래스의 sound 메소드
-> 동물 별로 울음 소리는 내지만 다 다르기 때문

  • 이러한 상황에서 추상 클래스에서는 실행부 중괄호{} 가 없는 추상 메소드를 선언
  • 추상 메소드는 자식 클래스에서 반드시 재정의하여 실행부를 채워야 함

봉인된 클래스

: sealed 키워드를 사용하면 permits 키워드 뒤에 상속 가능한 자식 클래스를 지정해야 함

public sealed class Person permits Employee, Manager {...}

public final class Employee extends Person { }
public non-sealed class Manager extends Person { }
  • Employee는 final로 선언되어 자식을 더 만들 수 없음
  • Manager는 non-sealed로 봉인을 해제해서 자식을 만들 수 있음

0개의 댓글