한 걸음 두 걸음

자바 JAVA ] 상속 Inheritance 본문

Language/Java

자바 JAVA ] 상속 Inheritance

언제나 변함없이 2019. 11. 20. 15:02
반응형

재사용을 위해 상속 혹은 결합을 하는데, 상속에 대해 알아보겠습니다.

상속

상속이란 이미 존재하는 클래스로부터 멤버들을 물려받는 것입니다. 이 때 상속하는 클래스를 수퍼클래스 혹은 부모클래스, 상속받는 클래스를 서브클래스 혹은 자식클래스라고 합니다.
수퍼클래스(부모클래스, 베이스클래스)와 서브클래스(자식클래스, 파생된클래스 )

class Employee{

}
class Manager extends Employee{

}

자바에서 상속은 extends키워드를 사용하여 상속시킬 수 있으며, 클래스 정의 옆에 작성해주면 됩니다.

1. 오버라이딩

메소드 재정의란 서브 클래스가 필요에 따라 상속된 메소드를 다시 정의하여 사용하는 것을 의미합니다. 같은 메소드 명을 가지고 있지만 상속받은 클래스에서는 다른 작업을 하게 하고 싶을 때 오버라이딩을 사용하며(단, 리턴타입, 메소드이름, 파라미터 목록 등을 모두 똑같이 맞춰주어야 이뤄집니다.) 자신의 클래스에게 맞는 함수로 바꾸어 활용하게 됩니다.
@Override어노테이션은 생략이 가능하지만, 명시적으로 오버라이딩 되었다는 것을 알려줄 수 있습니다.(: 명확한 코드 작성) 오버라이드 어노테이션을 적어놓으면 제대로 오버라이딩이 된 것인지 컴파일러가 확인도 해줍니다.
예 )

 class Animal{
     void sound(){}
 }

 class Cat extends Animal{
     @Override 
    void sound(){
        System.out.println("야옹");
    }
 }

중복정의는 같은 클래스 내에서 같은 이름을 가진 여러 개의 메소드를 작성하는 것이지만, 재정의는 부모 클래스의 메소드의 내용을 일부 수정하는 것입니다.

2. is-a관계

서브클래스 객체를 수퍼클래스 타입 변수에 할당이 가능합니다.  
Manager가 Employee를 상속받은 클래스라고 했을 때,

//Manager is a Employee
Employee e = new Manager();
//오른쪽에 있는 객체가 왼쪽의 자식일 때 위처럼 할당할 수 있습니다.


아처럼 Employee클래스에 Manager()를 할당할 수 있습니다.

UML표시

또 다른 예로, 자동차가 있습니다.
스포츠카를 만들 때 Car를 상속받으면
Car의 기본적인 기능(주행, 후진, 주차) 등을 모두 상속받고 스포츠카만의 기능(뚜껑 열기) 등을 추가해줄 수 있게됩니다.

이처럼 is-a관계인 클래스는 상속을 사용하는 것이 좋지만, has a관계를 갖느는 클래스에서는 상속이 아닌 클래스 내부에 다른 클래스의 객체를 포함시키는 방법을 사용해야합니다.
예 ) 도서관class , 책class = 도서관은 책을 가지고 있다.

3. 동적메소드(Runtime Binding)

메소드가 호출 될 때 가상머신은 객체의 `실제 클래스`를 보고 호출하기 때문에

Employee e = new Manager();


이렇게 생성했다고 해서, e를 사용하여 메소드를 호출할 때 Employee 클래스의 메소드가 불리는 것이 아니라 Manager에 명시된 메소드로 호출됩니다.

4. 사용예시

이제 상속받은 클래스를 활용해봅시다.

class Employee{
void a(){}
void b(){}
}
class Manager extends Employee{
@Override
void a(){}
void c(){}
}


위와 같은 클래스가 있을 때

public class Main {
public static void main(String[] args) {
Manager m = new Manager();
m.a(); //manager의 a()함수 호출
m.b(); //employee의 b()함수 호출
m.c(); //manager()의 c()함수 호출

 Employee h = new Manager();
 h.a(); //manager의 a()함수 호출
 h.b(); //employee의 b()함수 호출
 h.c(); //manager()의 c()함수 호출

  Employee e = new Employee();
  h.a(); //employee의 a()함수 호출
  h.b(); //employee의 b()함수 호출
 //불가  h.c(); //manager()의 c()함수 호출불가

}
}

여기서 접근지정자가 public, protected인 경우는 모두 자식이 부모클래스의 함수 등에 접근할 수 있었지만, private로 지정되어있으면 외부에서 접근할 수 없습니다. 재정의 또한 마찬가지로 적용됩니다.

Super()

super키워드는 상속관계에서 수퍼 클래스의 메소드나 필드를 명시적으로 참조하기 위해 사용합니다.(즉, 자식클래스에서 부모클래스를 호출할 때 사용합니다. ) 이를 사용하는 이유는 부모클래스의 메소드를 그대로 실행시키고 그 뒤에 추가 작업을 해주는 등의 일을 하기위해서입니다.

class Animal(){
    int a = 10;
       public void sound(){
        System.out.println("짖을 준비");
    }
}

 class Cat extends Animal{
    int b = 20;
     @Override 
    void sound(){
        super.sound();//짖을준비 출력
        System.out.println("야옹");

        System.out.println(this.b + super.a +"");
    }
 }

 public class Main {
    public static void main(String[] args) {
        Cat c = new Cat();

        System.out.println(c.print());//짖을 준비 \n 야옹 \n 10 20

    }
}

이러한 super키워드를 가장 흔하게 볼 수 있는 곳이 바로 생성자인데, 위의 클래스에서도 생략된 생성자가 불립니다.
Main함수에서 Cat클래스의 객체를 만들었을 때, Cat생성자가 불리고, Animal생성자가 불려서 돌아옵니다.

//Cat의 생성자
public Cat(){
    super(); //Animal생성자를 부른다.
}

이렇게 명시적으로 표현할 때에는 생성자의 첫 번째 줄에 반드시 작성해야하며, 작성해주지 않아도 자동으로 최상단 부모클래스의 생성자까지 생성하여 돌아옵니다. 단, 이는 생성자의 매개변수가 없을 때만 자동으로 처리되는 것이므로, 생성자의 매개변수가 있을 경우에는 super()를 사용하여 부모의 생성자를 호출해주어야합니다.

class Animal(){
    int a = 10;
    public Animal(int a){
        a = 20;
    }
}

 class Cat extends Animal{
    int b = 20;
    public Cat(){
        super(10);
    }
 }

상속의 특징

  1. 이미 검정된 속성과 동작을 이어받을 수 있으므로 신뢰성 있는 소프트웨어 개발이 가능합니다.
  2. 코드 중복을 줄일 수 있어서 전체적으로 코드의 크기가 작아집니다.
  3. 자식 클래스를 변경해도 부모클래스에 영향을 끼치지 않으므로 손쉽게 유지 및 보수를 할 수 있게 됩니다.
  4. 단, 클래스는 단 하나의 클래스만 상속받을 수 있습니다.(다중상속 불가)

Object클래스

Object클래스는 모든 클래스의 루트클래스입니다. 이는 다음 포스팅으로 작성하겠습니다.

반응형