보통사람

[Study-6주차] 상속 본문

Study

[Study-6주차] 상속

pej4303 2020. 12. 22. 19:42
  • 목표

    • 자바의 상속에 대해 학습하세요.

  • 학습할 것 (필수)

    • 자바 상속의 특징

    • super 키워드

    • 메소드 오버 라이딩

    • 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

    • 추상 클래스

    • final 키워드

    • Object 클래스

 

1. 상속(Inheritance)

 

  • 다른 클래스(상위클래스)의 멤버 변수와 메소드를 물려받는 것을 의미함

  • 상속을 이용하면 적은 양의 코드로 새로운 클래스를 만들 수 있으며 코드의 재사용을 높일 수 있음

  • extends 키워드를 이용해서 상속할 클래스명을 명시함

  • 자바 상속의 특징
    • Object 클래스를 제외하고는 모든 클래스는 하나의 상위클래스만 상속받을 수 있으며 이를 단일 상속(Single Inheritance) 이라고 함
    • 상속을 선언하지 않아도 자동적으로 최상위 클래스인 Object 클래스를 상속 받음

    • 상속 횟수 제한이 없음

class 클래스명 extends 상속받고자하는 클래스명 {}


public class Me extends Parent {}

 

해당 소스코드를 그림으로 표현한 것

 

클래스간의 상속관계를 그림으로 표현한 상속계층도

 

2. Object 클래스

 

  • 위에서도 잠깐 언급했듯이 모든 클래스의 조상이며 상속계층도의 최상위 클래스

  • Object 클래스의 멤버들은 모든 클래스에서 바로 사용 가능하며 멤버 변수는 없고 11개의 메소드만 가지고 있음

package com.study.java.inheritance;

public class Parent {
    // 상속을 선언한 게 없음
    public Parent() {
        System.out.println("Parent 생성자입니다.");
    }
    
    public void print() {
        System.out.println("Parent 클래스 입니다.");
    }
}

Parent.java의 바이트코드

3. 오버 라이딩(Overriding)

 

  • 상위 클래스로부터 상속받은 메소드의 내용을 변경하는 것을 의미함

  • Java 1.5 이상부터 공변 반환타입(Convariant Return Type)이 추가되어 하위클래스 타입으로도 변환 가능함

  • @Override 어노테이션으로 오버 라이딩이 맞는지 확인할 수 있으며 어노테이션이 없어도 에러는 안 나지만 명확하게 하기 위해서 사용하는 게 좋음
  • 오버 라이딩의 조건

    • 선언부가(이름, 매개변수, 반환 타입) 동일해야 함

    • 접근 제어자를 상위 클래스의 메소드보다 좁은 범위로 변경할 수 없음

    • 예외(Exception)는 상위 클래스보다 많이 선언할 수 없음

    • 인스턴스메소드를 statice 메소드로 또는 그 반대로 변경할 수 없음

package com.study.java.inheritance;

public class Parent {
    protected void print2() {
        System.out.println("protected print2() - Parent");
    }
    
    protected void print3() {
        System.out.println("protected print3() - Parent");
    }
    
    public Parent getObj() {
        return new Parent();
    }
}
package com.study.java.inheritance;

public class Me extends Parent {
    // 접근 제어자 : public > protected > (default) > private
    
    // 에러 없음
    public void print2() {
        // Why? 상위클래스의 print2()의 접근 제어자보다 넒은 범위로 지정했기 때문에
    }
    
    // 에러 발생
    private void print3() {
        // Why? 상위클래스의 print3()의 접근 제어자보다 좁은 범위로 지정했기 때문에
    }
    
    // 에러 없음
    public Me getObj() {
        // Why? 공변 반환 타입이 때문에 반환타입을 하위클래스로 변경해도 상관없음
        return new Me();
    }
}

※  오버 로딩(Overloading)

 

  • 기존에 없는 새로운 메소드를 추가하는 것을 의미

  • 오버 로딩의 조건

    • 메소드의 이름이 동일해야 함

    • 매개변수의 타입 또는 개수가 달라야 하며 반환 타입은 상관없음

package com.study.java.inheritance;

public class Me extends Parent {
    // 오버라이딩(Overriding)
    public void print2() {
        System.out.println("public print2() - Me");
    }
    
    // 오버로딩(Overloading)
    public void print2(String str) {
        System.out.println("public print2("+ str+") - Me ");
    }

    public static void main(String[] args) {
        Me me = new Me();
        me.print2();
        me.print2("안녕");
    }
}

[실행결과]
public print2() - Me
public print2(안녕) - Me 

 

4. super, super()

 

  • super

    • 상위클래스의 참조변수

    • 하위클래스에서 상위클래스의 멤버를 사용하는 경우에 사용됨

  • super()

    • 상위 클래스의 생성자를 호출할 때 사용함

    • Object 클래스를 제외하고 모든 클래스의 생성자 첫 줄에는 'this()' 또는  'super()'를 호출해야 함 없으면 컴파일러가 자동으로 'super()' 추가함(하위 클래스가 상위 클래스의 멤버 변수를 사용할 수 있기 때문에 상위 클래스를 먼저 초기화하기 위해서 첫 줄에 추가)

package com.study.java.inheritance;

public class Me extends Parent {
    public Me() {
      // super() 를 선언하지 않았음
      System.out.println("Me 생성자입니다.");
    }

    public static void main(String[] args) {
        Me me = new Me();
    }
}

Me.java 바이트코드

5. final 

 

  • 클래스, 메소드, 멤버 변수, 지역변수 등 모든 대상에 final 키워드를 사용할 수 있음

  • 대표적인 final 클래스로 String과 Math가 있음

package com.study.java.inheritance;

public final class ParentFinal {    // 상속 받을 수 없음
    
    final int MAX_NUM = 100;        // 상수
    
    final void printFinal() {       // 오버라이딩 할 수 없음
        System.out.println("printFinal");
    }
}

 

6. 추상 클래스(Abstract Class)

 

  • 미완성 클래스를 의미함

  • abstract 키워드를 이용해서 추상 클래스를 만들 수 있음

  • 클래스 내에 추상 메소드(선언부만 있는 메소드)를 포함한 클래스를 의미하지만 추상 메소드가 없어도 abstract를 이용해서 추상 클래스로 지정할 수 있음

  • 일반 클래스와 동일하게 생성자, 멤버 변수, 메소드를 가질 수 있으나 인스턴스는 생성할 수 없음

  • 추상메소드를 선언하는 이유는 하위 클래스에서 반드시 구현하도록 강요하기 위해서 사용함

abstract class 클래스명 {}


public abstract class AbstractParent {}   
public abstract class AbstractParent {

    abstract void test();     // 추상메소드
}

public class Me2 extends AbstractParent {
    
    @Override
    void test() {             // 상속받으면 추상메소드를 반드시 구현해야함        
    
    }
}

 

7. 다형성(Polymorphism)

 

  • 여러 가지 타입을 가질 수 있는 것을 의미하며 Java는 한 타입의 참조 변수로 다양한 타입의 객체를 참조할 수 있도록 함으로 다형성을 구현하고 있음

  • 참조 변수의 형 변환은 참조하고 있는 객체에서 사용할 수 있는 멤버의 범위를 조절하는 것뿐

  • 상속 시 상위 타입의 참조 변수로 하위 타입의 객체를 참조할 수 있으나 그 반대는 안됨

하위 타입 → 상위 타입(Up-casting)   : 형변환 생략가능
하위 타입 ← 상위 타입(Down-casting) : 형변환 생략불가
Parent p = new Me();    // O
→ 상위 타입의 참조변수로 하위 타입의 객체를 참조

Me me = new Parent();   // X (에러발생)
→ 하위 타입의 참조변수는 상위 타입의 객체 참조 못함
→ Why? 하위 타입의 참조변수가 상위 타입에 없는 객체를 참조 할 수 있기때문에 허용되지 않음

 

8. 다이나믹 메소드 디스패치(Dynamic Method Dispatch)

 

  • 컴파일시가 아닌 런타임(Runtime)시에 어떤 메소드를 호출할지 결정하는 방법

  • Java가 런타임 다형성(Polymorphism)을 지원하는 방법 중 하나

public class Parent {
    public String myName = "Parent";
    
    public void print() {
        System.out.println("This is Parent");
    }
}

public class Me extends Parent {
    public String myName = "Me";
    public int x = 200;
    
    public void print() {
        System.out.println("This is Me");
    }
    
    public static void main(String[] args) {
        Me me = new Me();
        System.out.println(me.myName);
        me.print();
        
        System.out.println("####################");
        
        // 다이나믹 메소드 디스패치
        Parent p = new Me();
        System.out.println(p.myName);
        p.print();
    }
}

[실행결과]
Me
This is Me
####################
Parent
This is Me

Me.java의 바이트코드

  • 메소드 디스패치는 이것 말고도 2가지 방법이 더 있음

    • static 메소드 디스패치 : 정적인 메소드 디스패치

    • 더블 디스패치 : 다이나믹 메소드 디스패치가 2번 발생된 것

  • 자바는 싱글 디스패치를 지원하는 언어이기 때문에 최대 2번만 발생 할 수 있는 듯

  • 정리 잘된 링크 참조 (더블 디스패치 예제와 방문자 패턴에 대한 설명도 있음)

 

 

※ 참조

 

자바의 정석

nasanasa.tistory.com/258

www.geeksforgeeks.org/dynamic-method-dispatch-runtime-polymorphism-java/

defacto-standard.tistory.com/413

www.tcpschool.com/java/java_polymorphism_concept

 

 

'Study' 카테고리의 다른 글

[Study-8주차] 인터페이스  (0) 2021.01.04
[Study-7주차] 패키지  (0) 2020.12.29
[Study-5주차] 클래스  (0) 2020.12.13
[Study-4주차] 제어문  (0) 2020.12.07
[Study-3주차] 연산자  (0) 2020.11.28