2) 상속

이번엔 자바의 상속(Inheritance) 개념에 대해서 알아보자. 상속은 말 그대로 무언가를 물려받는 것이다.

 

Animal 클래스를 상속하는 Dog 클래스를 만들어 보자.

 

Animal.java


public class Animal {
    String name;

    public void setName(String name) {
        this.name = name;
    }
}

 

Dog.java


public class Dog extends Animal {

}

 

클래스 상속을 위해서는 extends 키워드를 사용한다. 위 Dog 클래스는 Animal 클래스를 상속했다.

 

Dog 클래스에 name 이라는 변수와 setName 이라는 메소드를 만들지 않았지만 상속을 받았기에 그대로 사용이 가능하다. Dog 클래스에 다음과 같은 main 메소드를 구현하고 실행시켜 보자.

 


public class Dog extends Animal {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");
        System.out.println(dog.name);
    }
}

 

예상했던 데로 "poppy" 라는 문자열이 출력될 것이다. 즉 상속을 하면 자식 클래스는 부모클래스의 모든 기능을 그대로 물려받을 수 있게 된다.

이제 Dog 클래스에 새로운 메소드를 추가 해 보자.

 


public class Dog extends Animal {
    public void sleep() {
        System.out.println(this.name+" zzz");
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");
        System.out.println(dog.name);
        dog.sleep();
    }
}

 

Dog 클래스에 sleep 이라는 메소드를 추가 했다. 이제 Dog 클래스는 Animal 클래스보다 좀 더 많은 기능을 가지게 되었다.

※ sleep 메소드의 가장 앞에 붙어있는 public 이라는 키워드는 접근을 제어하기 위한 접근제어자 중 하나로 public은 어떤 클래스던지 이 sleep 메소드에 접근할 수 있게 해 준다. 접근제어자에 대해서는 나중에 자세하게 다룰 것이다.

 

메소드 오버라이딩 (Method overriding)

 

이번에는 Dog 를 좀 더 구체화 시키는 HouseDog 클래스를 만들어 보자. HouseDog 클래스는 Dog 클래스를 상속하여 다음과 같이 만들 수 있다.

 

HouseDog.java


public class HouseDog extends Dog {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();
    }
}

 

HouseDog 클래스를 실행 해 보면 sleep 메소드가 호출되어 다음과 같은 결과가 출력된다.

 


happy zzz

 

그런데 HouseDog, 즉 집에서 키우는 개들은 잠을 집에서만 잔다고 한다. HouseDog 로 만들어진 객체들은 sleep 메소드 호출 시 "happy zzz" 가 아닌 "happy zzz in house" 를 출력해야 한다고 가정 해 보자.

 

이렇게 하려면 어떻게 해야 할까?

 

다음과 같이 해 보자.

 


public class HouseDog extends Dog {
    public void sleep() {
        System.out.println(this.name+" zzz in house");
    } 

    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();
    }
}

 

Dog 클래스에 있는 sleep 메소드를 HouseDog 에도 동일하게 구현하고 실행 해 보았더니 다음처럼 원하던 결과값을 얻을 수 있었다.

 


happy zzz in house

 

HouseDog 클래스에 Dog 클래스와 동일한 형태의 sleep 메소드를 구현하면 HouseDog 클래스의 sleep 메소드가 Dog 클래스의 sleep 메소드보다 더 높은 우선순위를 갖게 되어 HouseDog 클래스의 sleep 메소드가 호출되게 된다.

 

이렇게 부모클래스의 메소드를 자식클래스가 동일한 형태로 또다시 구현하는 행위를 메소드 오버라이딩(Method Overriding)이라고 한다. (※ 메소드 덮어쓰기)

 

다중 상속

 

다중 상속은 클래스가 하나 이상의 클래스를 상속받는 것을 뜻한다. C++, 파이썬 등 많은 언어들이 다중 상속을 지원하지만 자바는 다중 상속을 지원하지 않는다.

 

만약 자바가 다중 상속을 지원한다면 다음과 같은 코드가 만들어 질 수 있을 것이다.


class A {
    public void msg() {
        System.out.println("A message");
    }
}



 


class B {
    public void msg() {
        System.out.println("B message");
    }
}



 


class C extends A, B {
    public void static main(String[] args) {
        C test = new C();
        test.msg();
    }
}

 

자바가 다중 상속을 지원한다고 가정하고 A, B 라는 클래스를 다음과 같이 동시에 상속하도록 했다. (실제로는 동작할 수 없는 코드이다.)

 

위 main 메소드에서 test.msg(); 실행 시 A 클래스의 msg 메소드를 실행해야 할까? 아니면 B 클래스의 msg 메소드를 실행해야 할까?

 

다중 상속을 지원하게 되면 이렇듯 애매모호한 부분이 생기게 된다. 자바는 이러한 불명확한 부분을 애초에 잘라 낸 언어이다.

 

※ 다중상속을 지원하는 다른 언어들은 이렇게 동일한 메소드를 상속받는 경우 우선순위등을 적용하여 해결한다.