HAZEL

[ CH03. 객체지향 핵심 ] 상속 , 형변환, super 키워드 , overriding , 다형성, 다운 캐스팅, instanceof 본문

PROGRAMMING/Java

[ CH03. 객체지향 핵심 ] 상속 , 형변환, super 키워드 , overriding , 다형성, 다운 캐스팅, instanceof

Rmsid01 2021. 4. 5. 15:37

CH03. 객체지향 핵심 

: 패스트 캠퍼스 강의를 공부하고 정리한 내용입니다.

 

01. 상속 

1. 클래스 상속 

: 클래스를 정의할 때, 이미 구현된 클래스를 상속 받아서 속성이나 기능을 확장하여 클래스를 구현함

: 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야 할 때, 기존 클래스를 상속함 

 

- 상위 클래스 = parent class = base class = super class

- 하위 클래스 = child class = derived class = subclass

 

2. 상속하기

class B extends A {

}

 

: B(하위) A(상위)

: A의 클래스를 확장한다는 개념인데, A는 한개의 클래스만 올 수 있다. - 자바는 단일 상속 만 지원함

 ( 인터페이스에서는 여러개의 상속도 가능하다 ) 

 

3. 상속을 구현하는 경우

: 상위 클래스와 하위클래스 보다 더 일반적. 

: 하위 클래스가 상위 클래스의 속성과 기능을 확장한다는 의미! 

 

4. protexted 접근 제어자

: private 멤버 변수는 하위 클래스에 접근 못한다!  그래서, 외부 클래스는 접근할 수 없지만, 하위 클래스는 접근할 수 있도록 protected를 사용한다. 

 

- 멤버변수를 만들려면 메모리가 있어야한다! 그런데, 아래에는 없다! 왜냐하면 상위 클래스에 이미 있기 때문이다!

public class VIPCustomer extends Customer {

    private  int agentID;  // 담당하는 상담원 아이디
    double salesRatio;

    // customer 구현되 내용이 중복이므로 customer를 확장하여 구현함 ( 상속 ) - 상속받았기 때문에, 이미 있는 변수는 초기화 안해두됨

    // 생성자
    public VIPCustomer(){
        customerGrade = "VIP"; // 상속을 받으려니깐, 오류발생 - 왜냐면 , privite 이기 때문 - 클래스 내부에만 사용
                                // 하지만 상속관계에서는 사용할일이 많음. - 외부는 못해도 하위는 접근 가능하게 해랏 -> protected로 변경
        bounsRatio = 0.05;
        salesRatio = 0.1;
    }
}

 

5. 하위 클래스가 생성되는 과정

customer() call
Vipcustomer() call


customer(int, string) call
이순신님의 등급은 BASIC이며, 보너스 포인트는 1000입니다.
customer(int, string) call
Vipcustomer(int, string) call
Kim님의 등급은 VIP이며, 보너스 포인트는 1000입니다.

: 하위 클래스를 호출하면 -> 상위 클래스가 호출되고, 하위 클래스가 호출된다.

 

아무코드도 없는데 어떻게 상위 클래스가 호출이 되는가?

- 클래스 생성자가 상속을 받은 경우에는, 컴파일러가 super(); 를 넣어주게 됨. 

 

6. super() 키워드

생성된 상위 클래스 인스턴스의 참조값을 가지므로 super를 이용하여 상위 클래스의 메서드나 멤버 변수에 접근할 수 있다. 

: 상위 클래스의 기본 생성자를 호출함. - 하위 클래스에서 명시적으로 상위 클래스의 생성자를 호출하지 않으면, super()가 호출됨. 

: 내가 직접 코드로 입력하지 않아도, 컨파일러가 알아서 적고 프로그래밍 해준다. ( 묵시적으로 )  - 직접써주는 일은 거의 없음. 

: 만약, 상위 클래스의 기본 생성자가 없는 경우,  내가 직접 하위 클래스에서 super을 이용하여, 명시적으로 상위 클래스의 생성자를 호출해야한다. 

// 생성자로 호출 받는 법
public VIPCustomer(){
    super(0,"no-name");
    customerGrade = "VIP";
    bounsRatio = 0.05;
    salesRatio = 0.1;
    System.out.println("Vipcustomer() call"); // 얘가 불렸을때 출력되는 로그
    }
    
    
// 생성자를 안쓰고 이렇게 써도 가능 - 위에랑 같은 코드 
public VIPCustomer(int customerID, String cutomerName){
    super(customerID, cutomerName);
    customerGrade = "VIP";
    bounsRatio = 0.05;
    salesRatio = 0.1;
    }

// test코드 
 public static void main(String[] args) {
        Customer customerLee = new Customer(10010, "이순신"); // test코드

 

7. 상속에서 인스턴스 메모리의 상태 

: 항상 상위 클래스의 인스턴스가 생성된 후에 하위 클래스의 인스턴스가 생성된다. 

이미지 출처 : 패스트 캠퍼스 강의 

 

8. 형 변환(업캐스팅)

: 상위 클래스로 변수를 선언하고 하위 클래스의 생성자로 인스턴스를 생성 , 단 이 역은 성립 하지 않음

 

: 즉, 아래처럼 코드를 작성할 수 있다. 

Customer customerLee = new VIPCustomer();

- 이렇게 할수있는 이유는, vip를 생성하면, customer을 내포하고 있기 때문에, 이 타입으로 형변환 되는 것은 가능하다. 

  즉, vipcustomer 의 인스턴스는 customer 타입으로 대입될 수 있음. 

VIPCustomer vCustomer = new VIPCustomer();
addCustomer(vCustomer);
int addCustomer(Customer customer){
}

- 즉, 상위 클래스로 형변환이 됨.  <-> 원래 자기 인스턴스로 되는것  - 다운 캐스팅

 

: 아래 사진과 같이, customer로 형변환이 되면, 인스턴스는 vip를 받지만, 고유한 vip의 변수나 메서드는 사용하지 못한다.

  즉, customer 것만 사용가능하다. 

 

02. 메서드 재정의하기 ( overriding )

1. 하위 클래스에서 메서드 재정의하기 

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

# 주의점 : 반환값, 메소드이름, 매개변수의 타입과 갯수가 동일해야함. . 맞지 않을 경우 다른 메소드로 처리됨.

@Override  // 컴파일에게 정보를 제공해주는 역할
public int calcPrice(int price) {
bounsPoint += price * bounsRatio;
price -= (int)(price * salesRatio);
return price;
}

 

2. 애노테이션 ( annotation )

 : 컴파일러에게 특별한 정보를 제공해주는 역할

 

- 애노테이션의 종류

1) @Overrride : 재정의된 메서드라는 정보 제공 

2) @Fuctionallnterface : 함수형 인터페이스라는 정보 제공 

3) Deprecated : 이후 버전에서 사용되지 않을 수 있는 변수, 메서드에 사용

4) @SuppressWarnings : 특정 경고가 나타나지 않도록 함 

 

3. 형 변환과 오버라이딩 메서드 호출

: vs 변수의 타입은 Customer지만 인스턴스의 타입은 VIPCustomer 이다. 자바에서는 항상 인스턴스의 메서드가 호출됨. (가상 메서드의 원리), 자바의 모든 메서드는 가상 메서드 ( virtual method ) 이다.

Customer vc = new VIPCustomer(1234, "noname"); // 형변환 가능
System.out.println( vc.calcPrice(1000)); // 900

 

03. 메서드 재정의와 가상 메서드 원리

1. 메서드 호출 및 실행 방법

  • 자바는 그냥 가상함수 메서드
  • 메서드(함수)의 이름은 주소값을 나타냄
  • 메서드 명령어의 set이고 프로그램이 로드되면 메서드 영역(코드 영역)에 명령어 set이 위치
  • 해당 메서드가 호출 되면 명령어 set 이 있는 주소를 찾아 명령어가 실행됨
  • 이때 메서드에서 사용하는 변수들은 스택 메모리에 위치 하게됨
  • 따라서 다른 인스턴스라도 같은 메서드의 코드는 같으므로 같은 메서드가 호출됨
  • 인스턴스가 생성되면 변수는 힙 메모리에 따로 생성되지만, 메서드 명령어 set은 처음 한번만 로드 됨
public class TestMethod {
    int num;

    void aaa(){
        System.out.println("TestMethod.aaa 호출");
    }

    public static void main(String[] args) {
        TestMethod a1 = new TestMethod();
        a1.aaa();

        TestMethod a2 = new TestMethod();
        a2.aaa();
    }
}

 

이미지 출처 : 패스트캠퍼스 

 

04. 다형성 ( polymorphism )

1. 다형성 이란  ?

 

  • 하나의 코드가 여러 자료형으로 구현되어 실행되는 것. 같은 코드에서 여러 다른 실행 결과가 나옴
  • 객체지향 프로그래밍의 가장 큰 특징 중 하나임  -> 유연하고 확장성있고, 유지보수가 편리한 프로그램을 만들수 있음

2. 다형성을 사용하는 이유?

- 다른 동물을 추가하는 경우

- 상속과 메서드 재정의를 활용하여 확장성 있는 프로그램을 만들 수 있음 

   만약, 안그렇게 한다면, if-else 문이 너무 많이 구현되서 코드의 유지보수가 어려워짐

- 상위 클래스에서 공통적인 부분을 제공하고 하위 클래스에서는 각 클래스에 맞는 기능 구현 

- 여러 클래스를 하나의 타입(상위 클래스)으로 핸들링 할 수 있음 

 

 

05. 상속을 사용하는 경우

1. IS-A관계 ( is a relationship : ingeritance )

 

  • 일반적인(general) 개념과 구체적인(specific) 개념과의 관계
  • 상위 클래스 : 하위 클래스보다 일반적인 개념 ( 예: Employee )
  • 하위 클래스 : 상위 클래스보다 구체적인 개념들이 더해짐 ( 예: Engineer, Manager...)
  • 상속은 클래스간의 결합도가 높은 설계
  • 상위 클래스의 수정이 많은 하위 클래스에 영향을 미칠 수 있음
  • 계층구조가 복잡하거나 hierarchy가 높으면 좋지 않음

 

2. HAS-A 관계 ( composition ) 

 

  • 클래스가 다른 클래스를 포함하는 관계 ( 변수로 선언 )
  • 코드 재사용의 가장 일반적인 방법
  • Student가 Subject를 포함하는
  • Library를 구현할 때 ArrayList 생성하여 사용
  • 상속하지 않음

06. 다운 캐스팅과 instanceof 

1.  다운 캐스팅( downcasting )

: 업 캐스팅된 클래스를 다시 원래의타입으로 형 변환

: 하위 클래스의 형 변환은 명시적으로 해야함 ( 업캐스팅은 묵시적으로 일어남 )

Customer vc = new VIPCustomer();              //묵시적
VIPCustomer vCustomer = (VIPCustomer)vc;      //명시적

 

2. instanceof를 이용한 인스턴스의 형 체크

: if 문을 이용하여 원래 인스턴스의 형이 맞는지 여부를 체크하는 키워드. 맞으면 true, 틀리면 false를 반환 

if ( customerE instanceof GoldCustomer) {  // 원래의 인스턴스 형이 맞는지 체크하는 것 
    GoldCustomer vc = (GoldCustomer) customerE; // 원래 골드인데 vip로 할수 없어서 에러 발생
    System.out.println(customerE.showCustomerInfo());

 

다운캐스팅을 쓰면, 다시 되돌리는 것이고 코드가 복잡해지기 때문에, 가능하다면 오버라이딩으로 쓰는 것이 깔끔함. 

하자만, 꼭 써야한다면 instanceof 로 꼭 확인 해야한다.