210107 이것이 자바다 7장

송은석·2021년 1월 7일
0
post-thumbnail

신용권 님의 ''이것이 자바다'' 7장 공부 기록

책을 보면서 내용을 정리했다.

7. 상속

7.1 상속 개념

상속(Inheritance)은 부모가 자식에게 물려주는 행위를 말한다. 자식은 상속을 통해 부모가 물려준 것을 이용할 수 있다.

  • 부모 클래스는 상위 클래스라고 부르기도 하고, 자식 클래스는 하위 클래스, 파생 클래스라고 하기도 한다.
  • 상속은 이미 잘 개발된 클래스를 재사용하여 새 클래스를 만듦으로 코드의 중복을 줄이며 보다 효율적으로 개발을 하게 한다.
  • 상속을 해도 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다.
  • 다른 패키지에 부모와 자식 클래스가 존재한다면, default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.
  • 부모 클래스를 수정함으로 자동으로 자식클래스도 수정될 수 있다. 따라서 유지 보수 시간을 최소화시킨다.

7.2 클래스 상속

  • 프로그램에서는 자식이 부모를 선택하여 참조한다.

    class 자식클래스 extends 부모 클래스{
        클래스 내용
    }
  • 자바는 다중 상속을 허용하지 않으며, 따라서 extends 뒤에 단 하나의 부모 클래스가 올 수 있다.


7.3 부모 생성자 호출

  • 자식 객체 생성시, 부모 객체가 먼저 생성되고 자식 객체가 그 다음에 생성된다. 자식 객체가 부모 객체를 참조하기 때문이다.
  • 부모 객체 생성을 위해 컴파일러는 자식 객체의 첫 줄에서 부모객체 기본 생성자를 호출한다.
public Child(){
    super();    //부모 객체 기본 생성자
}
  • 부모 객체에 기본 생성자가 없다면 자식 객체 생성자에 super(...)을 명시적으로 선언해야 한다. 이 때 부모 생성자의 명시적 생성자 선언과 일치하는 매개값을 조건으로 주어야 한다. 자식 생성자 첫줄에 위치해야 에러(Implicit super constructor People () is undefined. Must explicitly invoke another constructor)가 나지 않는다.

7.4 메소드 재정의

  • 부모 클래스의 일부 메소드가 자식 클래스에 적절하지 않을 경우, 해당 메소드를 자식 클래스에서 다시 수정해서 사용할 수 있다.

7.4.1 메소드 재정의(@Override)

  • 메소드 오버라이딩은 상속된 메소드의 내용이 자식 클레스에 맞지 않을 경우, 자식 클래스에서 동일한 메소드를 재정의하는 것을 말한다. 메소드가 오버라이딩되었다면 부모 객체의 메소드는 숨겨지고, 자식 객체의 오버라이딩된 자식 메소드가 호출된다.

  • 이 때.

    1. 부모의 메소드와 동일한 시그니처(리턴타입, 메소드 이름, 매개 변수 리스트)를 가져야 한다.
    2. 접근 제한을 더 강하게 오버라이딩할 수 없다.
    3. 새로운 예외(Exception)을 throws할 수 없다.
  • override 어노테이션은 생략 가능하나 사용 시 정확한 컴파일을 통해 개발자의 실수를 줄여줄 수 있다.

7.4.2 부모 메소드 호출(super)

  • 메소드 오버라이딩 시 부모 클래스의 해당 메소드는 숨겨지나, super.메소드 접근을 통해서 명시적으로 메소드를 호출할 수 있다.
super.부모메소드();

7.5 final 클래스와 final 메소드

  • final 키워드는 클래스, 필드, 메소드 선언 시 사용 가능하며, 해당 선언이 최종 상태이고 결코 수정될 수 없음을 뜻한다.

  • 클래스와 메소드에 final 키워드가 지정되면 상속과 관련이 있다.

  • final 키워드를 클래스 앞에 붙이게 되면 최종적인 클래스가 되므로 상속할 수 없는 클래스가 된다. 자식 클래스를 만들 수 없는 것이다. 대표적인 예로 String 클래스가 있다.

  • 메소드 선언시 final 키워드를 붙이면 최종적인 메소드가 되므로 오버라이딩을 할 수 없는 메소드가 된다. 자식 클래스에서 재정의할 수 없다는 것이다.


7.6 proteted 접근 제한자

  • protcted는 필드와 생성자, 메소드 선언에 사용될 수 있는데, 같은 패키지에서는 접근 제한이 없으나 다른 패키지에서는 자식 클래스만 접근을 허용한다.
  • new 연산자를 통해 생성자를 직접 호출하는 것이 아닌, 자식 생성자에서 super로 호출해야 한다.

7.7 타입 변환과 다형성

다형성은 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.

코드 측면에서 보면 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해준다. 자바는 다형성을 위해 부모 타입에 모든 자식 객체가 대입될 수 있도록 했다. 이것을 이용하면 객체는 부품화가 가능하다.

  • 자식 타입은 부모 타입으로 자동 타입 변환 이 가능하다.

7.7.1 자동 타입 변환(promotion)

  • 자동 타입 변환의 개념은 자식은 부모의 특징과 기능을 상속 받기 때문에 부모와 동일하게 취급될 수 있다. ex) 동물-고양이
Cat cat = new Cat();
Animal animal = cat; //Annimal animal = new Cat()도 가능하다.
  • 위 코드로 생성되는 메모리 상태를 보면, cat과 animal은 동일한 cat 객체를 참조한다.
  • 부모 클래스로 타입은 변해도, 참조하는 객체는 같다. ==연산 시 true를 산출한다.
  • 부모 타입으로 자동 변환 이후 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정된다. 다만 자식 클래스에서 오버라이딩된 메소드는 호출 가능하다.

7.7.2 필드의 다형성

  • 이러한 자동 타입 변환이 필요한 까닭은, 다형성을 구현하는 기술적 방법 때문이다.

다형성이란 동일한 타입을 사용하지만 다양한 결과가 나오는 성질을 뜻한다.

주로 필드의 값을 다양화함으로써 실행 결과가 다르게 나오도록 구현하는데, 필드의 타입은 변함이 없지만, 실행 도중에 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라질 수 있다. 이것이 필드의 다형성이다.

class Body{
    Hand leftHand = new Hand();
    Hand rightHand = new Hand();
    
    void touch(){···};
}
Body myBody = new Body();
myBody.leftHand = new ironHand();
myBody.rightHand = new spiderHand();
myBody.touch();
void touch(){
    leftHand.reachOut();
    rightHand.reachOut();
}
  • 위 코드와 같이 자동타입 변환을 통하여 Hand 필드값을 교체함으로써 Body의 touch ()메소드 수정 없이 다양한 실행 결과를 만들어낼 수 있었다. 이것이 필드의 다형성이다.

7.7.3 하나의 배열로 객체 관리

  • 객체들을 배열을 통하여 관리하면, 코드를 보다 깔끔하게 만들 수 있다.
public class Body{
    Hand[] hands = {
        new Hand();
        new Hand();
    };
}//Body 클래스 -> 반복문을 이용하여 hands를 사용할 수 있다.

7.7.4 매개 변수의 다형성

  • 자동 타입 변환은 필드의 값보다 메소드를 호출할 때 많이 발생한다.
  • 메소드를 호출할 때 매개 변수에 자식 타입 객체를 지정함으로써 매개 변수의 다형성을 높일 수 있다.
class Driver{
    void drive(Vehicle vihicle){
        vehicle.run();
    }
}

을 정상적으로 호출하면

Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);

이지만, Vehicle의 자식 클래스인 Bus나 Taxi 객체를 매개값으로 넘겨줄 수도 있는 것이다. 이로써 메소드의 실행 결과가 다양해진다.

7.7.5 강제 타입 변환

  • 강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말하는데, 자식 타입이 부모 타입으로 자동 변환한 후, 다시 자식 타입으로 변환할 때에 사용할 수 있다.
  • 이는 부모 타입으로 자동 변환된 자식 타입의 메소드와 필드를 다시 사용하고자 할 때 사용할 수 있다.
자식클래스 변수 = (자식클래스) 부모클래스 타입;//자동 변환된 상태

7.7.6 객체 타입 확인(instnaceof)

  • 자동 변환되지 않은, 자식 객체를 참조하지 않는 부모 타입의 변수는 자식 타입으로 변환할 수 없다. 이 때 부모 변수가 참조하는 객체가 부모 객체인지 자녀 객체인지 확인하기 위하여 instanceof 연산자를 사용할 수 있다.
  • instanceof 연산자의 좌항에는 객체, 우항에는 타입이 오고, 좌항의 객체가 우항의 타입으로 객체가 생성되었다면 true를 반환한다.
boolean result = 좌항(객체) instanceof 우항(타입)
  • 이는 주로 매개값의 타입을 확인할 때 사용된다. 타입을 확인하지 않고 잘못된 매개값으로 강제 타입 변환을 시도한다면 ClassCastException 예외가 발생할 수 있다.
public void method(Parent parent){
    if(parent instanceof Child){
        Child child = (Child) parent;
    }
}

7.8 추상 클래스

7.8.1 추상 클래스의 개념

사전적 의미로 추상(abstract)은 실체 간에 공통되는 특징을 추출한 것을 말한다.

  • 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 하고, 이 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.

  • 추상 클래스가 부모 클래스, 실체 클래스가 자식 클래스로 상속의 관계를 가지고 있다. 실체 클래스는 추상 클래스의 특성을 물려받고 추가적인 특성(필드와 메소드)을 가질 수 있다.

  • 추상 클래스는 new 연산자를 통해 객체(인스턴스)를 생성할 수 없다. 추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용된다. extends 뒤에만 오는 클래스인 것이다.

class Ant extends animal {···}

7.8.2 추상 클래스의 용도

  • 추상 클래스를 만드는 용도는?
    1. 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적
    2. 실체 클래스를 작성할 때 시간을 절약

7.8.3 추상 클래스 선언

  • 추상 클래스를 선언할 때는 클래스 선언에 abstract 키워드를 붙여야 한다.
public abstract class 클래스{
    //내용
}
  • new 연산자를 통한 객체 생성은 불가하고, 상속만 가능하다. 그러나 자식 객체가 생성될 때 super(···)을 호출해서 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야 한다.

7.8.4 추상 메소드와 오버라이딩

  • 추상 클래스는 실체 클래스의 멤버를 통일화하는데 목적을 둔다. 그러나 메소드의 선언만 통일화하고, 실행 내용은 실체 클래스마다 달라야 하는 경우가 있다. 이를 위해 추상 클래스는 추상 메소드를 선언할 수 있다.
  • 추상 메소드는 추상 클래스에서만 선언할 수 있다. 추상 메소드는 선언부는 있으나 실행 내용인 중괄호가 없다. 이 부분을 하위 클래스를 작성할 때 재정의를 통해 작성하게 된다. 재정의하지 않을 경우 컴파일 에러가 발생한다.
[public|protected] abstract 리턴타입 메소드명(매개변수,···);
profile
Done is better than perfect🔥

0개의 댓글