Java/라이브스터디

상속

목표

자바의 상속에 대해 학습하기

학습목표

  • 자바 상속의 특징
  • super 키워드
  • 메소드 오버라이딩
  • 다이나믹 메소드 디스패치 ( Dynamic Method Dispatch )
  • 추상 클래스
  • final 키워드
  • Object 클래스

 


 

상속

class SubClass extends SuperClass{
  /*...*/
}

자바에서의 상속은 extends키워드와 implements를 통하여 이루어집니다.
슈퍼 클래스에 작성된 내용을 서브클래스에서도 필요로 할때 주로 사용됩니다.

 

 

public class Parent {
  public int Parent_int;
  public String Parent_String;

  Parent(int Parent_int, String Parent_String){
    this.Parent_int = Parent_int;
    this.Parent_String = Parent_String;
  }
}
public class Child extends Parent {
  int Child_int;
  String Child_String;

  Child(int Child_int, int Parent_int, String Child_String, String Parent_String){
    super(Parent_int, Parent_String);
    // 부모 클래스의 생성자 호출

    this.Child_int = Child_int;
    this.Child_String = Child_String;
  }
}
package PlayGround;

public class Main {
    public static void main(String[] args) {
        Child child = new Child(10,20,"Child", "Parent");
        System.out.println(child.Child_int);
        System.out.println(child.Child_String);
        System.out.println(child.Parent_int);
        System.out.println(child.Parent_String);
    }
}
=== 출력 결과 ===
10
Child
20
Parent

위의 케이스처럼 서브클래스의 객체를 이용하여, 슈퍼클래스의 생성자 호출 및 접근이 가능합니다.

 

 

업 캐스팅과 다운캐스팅

상속관계에 있는 클래스에서 서브클래스는 서브클래스의 특징과 슈퍼클래스의 특징을 모두 지니고 있습니다.
따라서, 서브클래스 타입의 객체와 슈퍼 클래스 타입의 객체 생성이 모두 가능하고 슈퍼클래스 타입의 서브클래스 객체를 생성하는 것을 업 캐스팅 이라고 합니다.

 

Parent Obj = new Child();

// Parent = 슈퍼클래스
// Child = 서브클래스

생성되는 객체는 Child의 객체이지만 타입이 Parent이므로 Obj는 Parent의 필드와 메소드만 사용이 가능합니다.

이렇게 Child의 객체로 생성되었지만, Parent타입을 가진 객체에서 Child의 필드와 메소드를 사용하기 위해서는 아래의 모습으로 호출을 하면됩니다.

 

Child child_obj = (Child) obj;

// (Child)[객체명]

위와 같이 업캐스팅된 객체를 서브클래스의 객체로 되돌리는 작업을 다운 캐스팅이라고 부릅니다.

 

 

자바에서의 다중상속

결론부터 말하자면 자바에서 클래스의 경우 다중상속을 지원하지 않습니다.

그 이유를 간단하게 살펴봅시다.

 

 

class A{
  public void Method();
}

class B{
  public void Method();
}

class C extends A, B{

}

만약 다중상속이 가능하다고 가정하였을 때, 위 상황에서 C클래스의 객체를 생성하고 Method() 를 호출한다고 생각해보면 어느 클래스의 Method가 호출될까요?

위와 같은 이유들 말고도 더 많은 문제가 생길 수 있기때문에 클래스의 다중상속은 지원하지 않습니다.

 

 

interface A{
  public void Method();
}

interface B{
  public void Method();
}

class C implements A, B{
  @Override
  public void Method(){

  }
}

대신에 자바에서는 인터페이스의 다중상속을 지원합니다.
클래스의 경우 상속시에 정해져있는 메소드를 받아오는 형식인데 비하여 인터페이스의 경우 상속을 함과 동시에 모양은 그대로지만 나에게 맞게 내부내용을 재정의 하여아합니다.

 

인터페이스란, 상수와 추상메소드 만으로 이루어진 클래스를 의미합니다.
여기서 추상메소드란, 메소드의 구현부를 정의하지 않은 메소드를 의미합니다.

인터페이스의 상속을 받은 클래스는 반드시 인터페이스의 추상메소드를 재정의하여야 합니다.

 

 

super

상속관계에 놓여있는 클래스를 부르는 명칭은 두 가지가 있습니다.

  • 상위클래스와 하위클래스
  • 슈퍼클래스와 서브클래스

이번에 배울 super키워드는 super class의 super를 의미합니다. 즉, 서브클래스에게 있어서 자신이 상속하고있는 클래스를 의미합니다.

super키워드를 사용하는 방식을 살펴봅시다.

 

super.필드;
// 자신이 상속하고 있는 클래스의 필드값을 의미

super.메소드명();
// 자신이 상속하고 있는 클래스의 메소드를 호출

super();
super(/*파라미터*/);
// 자신이 상속하고있는 클래스의 생성자를 호출

 

메소드 재정의 ( 메소드 오버라이딩 )

클래스나 인터페이스의 상속에 있어서, 기존에 정의되어있는 메소드를 나의 입맛에 맞게 새롭게 구성하는 것을 의미합니다.

 

@Override
public void Method(){

}

@Override 어노테이션으로 재정의된 메소드를 확인하는 것이 가능하며, 보통 인터페이스를 상속받을 때 메소드 재정의를 사용하게됩니다.

 

클래스를 상속받아도 재정의가 가능하기는 하나, 재정의를 할 정도로 같은 형태의 메소드를 재사용한다면 인터페이스를 구현하는 것이 좀 더 효율적입니다.

 

동적 메소드 디스패치

인터페이스나 추상클래스의 추상메소드를 호출 하는 경우에 해당합니다.

 

interface Interface{
  public abstact void showme();
}

class Sub implements Interface{
  @Override
  public void showme(){
    /* Some codes..*/
  }
}
Sub sub = new Sub();
/* Sub클래스의 객체이므로 재정의된 showme() 메소드를 확실하게 알 수 있다.*/
// 정적 메소드 디스패치

Interface sub = new Sub(); 
/* 인터페이스 타입의 객체이기 때문에 new Sub(); 가 실행돼서 showme() 메소드가 재정의 되기 전 까지는 showme() 메소드가 뭘 하는지 알 수 없다.*/
// 동적 메소드 디스패치

위 상황과 같이 업캐스팅이 일어난 경우 동적 메소드 디스패치가 일어나게됩니다.

 

 

추상클래스

구현부가 정의되지 않은, 추상메소드를 포함하는 클래스를 의미합니다.
추상클래스는 추상메소드를 포함하기 때문에, 상속을 통하여 해당 메소드를 구현해야합니다.

  • 일반 메소드의 생성가능
  • 변수 선언 가능
  • 생성자 선언 가능
  • 다중상속 불가능

인터페이스와의 차이점을 정리해보면 위와 같습니다.

abstract 키워드를 사용하여 선언할 수 있습니다.

public abstract class Car {
    public abstract void showme();
    // 추상 메소드 

    String name;
    // 일반변수 선언 가능

    Car(String name){
        this.name = name;
    }
    // 생성자 선언 가능

    public void Hello(){
        System.out.println("Hello!!");
    }
    // 일반 메소드 선언 가능
}

 

final

수정되지 않는 이라는 의미를 가진 키워드.

클래스, 메소드, 필드에 해당 키워드를 붙힐 수 있다.

package PlayGround;

public final class Car {
    public final void Method(){
        System.out.println("오버라이딩이 불가능해요!");
    }
    // 서브클래스에서 재정의 불가능

    public int a = 0;
    public final int fnum = 42;
    // 상수처리
}

클래스 : 상속이 불가능
메소드 : 재정의가 불가능
필드 : 값의 수정이 불가능

 

Object 클래스

모든 클래스 상속관계의 최상위에 위치한 클래스
모든 클래스들은 Object클래스를 부모클래스로 하고있으며 배열을 포함한 모든 객체들은 이 클래스의 메소드를 가지고있다.

 

 

접근권한과 타입 메소드 설명
protected Object clone() 해당 객체를 복사하여 반환해준다
boolean equals(Object obj) 두 객체가 동일한지 검사해준다.
Class<?> getClass() 객체에 대한 런타임 클래스를 반환해준다.
int hashCode() 객체의 해쉬코드값을 반환해준다.
void notify() 대기중인 해당 객체에 단일스레드를 할당해준다.
void notifyAll() 대기중인 해당 객체에 모든스레드를 할당해준다.
String toString() 객체의 정보를 문자열로 반환해준다.
void wait() 현재 스레드를 무기한 잠들게 한다.
void wait(long timeoutMillis) 정해진 시간동안 스레드를 잠들게한다.
void wait(long timeoutMillis, int nanos) 정해진 시간동안 스레드를 잠들게한다.

 

 

 

참고자료