java 상속과 추상, 인터페이스 그리고 final

최준호·2021년 7월 6일
0

java

목록 보기
9/25

상속이란

상속이란 부모가 보유하는 것을 자식이 물려 받는 것을 의미한다. java에서도 같은 의미인데 이는 확정성과 직결되는 의미를 지닌다.

java는 단일 상속

java는 단일 상속만을 지원하며 다중 상속은 지원하지 않는다. 다른 언어들은 다중 상속이 지원하는 경우가 있지만 java는 완전한 객체지향 개념에는 다중 상속이 필요치 않다고 보고 있다. 또한 다중 상속을 지원하게 되면 생성되는 객체의 명확성이 떨어지게 된다. 그래서 자바에서 상속은 특정 클래스가 가지는 일부 속성과 기능을 다른 새로운 클래스에 제공하기 위해 맺는 클래스간의 관계를 말한다. 또한 클래스간의 상속이란 extends 예약어를 통해 부모클래스(super class)를 자식 클래스(sub class)로 관계를 맺는 것인데 만약 상속을 받지 않았다면 java 최상위 클래스인 object를 묵시적으로 상속받는다.

클래스 상속의 장점

클래스 상속은 객체의 재사용과 코드의 간결성을 제공한다.

class Good{
    long id;
    String name;
    int price;

    public void setName(String name){
        this.name = name;
    }
    public void setPrice(int price){
        this.price = price;
    }
    public long getId(){
        return this.id;
    }
    public String getName(){
        return this.name;
    }
    public int getPrice(){
        return this.price;
    }
}

다음과 같이 상품에 대한 클래스가 있을때

class Book extends Good{
    String author

    public Book(String name, int price, String author){
        ...
    }
}

다음과 같이 자식 클래스인 Book이 부모 클래스의 Good을 상속받아 필요 멤버들을 사용할 수 있게 되었다. 이렇게 상속 받은 자식 클래스는 부모 클래스의 멤버와 메서드를 상속받아 사용하므로 코드의 재사용성이 증가되고 또한 부모 클래스의 정의된 코드들을 또 사용하지 않으므로 코드 또한 간결해지는 장점이 있다.

오버라이딩

오버라이딩의 대한 개념은 이미 알고 있다. 메서드의 재정이라 불리며 super 클래스가 가지는 메서드를 sub 클래스에서 똑같이 새롭게 만들게 되면 더 이상 super 클래스에서 이름이 같은 메서드를 호출할 수 없다. 이를 오버라이딩이라 부르고 상속 관계에서는 '멤버 은폐'라고도 한다.

super, super()

super는 앞서 배운 this를 떠올리면 쉽게 이해할 수 있다. this는 해당 객체를 참조하는 참조변수다. super라는 참조변수는 현재 객체의 바로 위의 부모 클래스를 참조하는 참조변수인 것이다.

super()란 그럼 무엇일까? super는 위에서 말한것 처럼 부모 클래스를 의미하고 super()는 부모 클래스의 생성자를 의미한다.

class Parent{
    public Parent(int n){
        System.out.println("부모 클래스 "+n);
    }
}
class SubClass extends Parent{
    public SubClass(){
        super(3);
        System.out.println("자식 클래스");
    }

    public static void main(String[] args){
        SubClass sub = new SubClass();
    }
}

위 코드를 실행하면

다음과 같은 결과를 확인할 수 있으며 super()가 부모 클래스의 생성자임을 확인할 수 있다.

final 이란

final은 더 이상 확장이 불가능함을 알리는 예약어이다. 적용할 수 있는 범위는 변수, 메서드, 클래스이다.

변수에서 final

변수에 final을 적용시키면 프로그램이 종료되어질 때까지 값을 변경하지 못하는 상수화가 된다. 그리고 static 예약어와 함께 정적화하여 특정 클래스의 객체가 여러개 생성되는 것을 방지하는 것이 보통이다. 또한 상수화가 되므로 변수의 이름은 대문자로 하는것도 관례이다.

  • 하지만 웹에서 개발을 할때 싱글톤으로 개발하기 위해 변수명에 final을 붙여 생성자를 생성하는 경우가 있다. 그때는 static이나 대문자로 표시하지 않고 'private final 변수명'으로 생성하는 경우도 있다.

메서드 final

메서드의 final은 더이상 오버라이드를 하지 못하게 하는 기능을 수행한다.

class final

class의 final은 더이상 상속받지 못하게 하는 기능을 수행한다.

추상화

  • 추상화란

      pulbic abstract int getA();

    이렇게 추상 메서드의 경우 {}를 생략하여 미완성된 메서드로 생성한다.추상 클래스의 경우 하나 이상의 추상 메서드를 가진 클래스를 의미한다.

  • pulbic abstract class TestClass{}

  • 추상화라는 것은 일반적으로 사용할 수 있는 단계가 아닌 미완성적인 개념을 가진다. java에서는 추상화를 method와 class에 적용시킬 수 있는데. method에 적용시키면 추상(abstract) method, class에 적용시키면 추상(abstract) class가 된다. 이때 추상 메서드를 하나라도 가지게 되는 클래스가 바로 추상 클래스이며 추상 메서드를 하나 이상 가지게된 클래스에는 abstract를 항상 명시해야 한다.

  • 추상 클래스의 상속 관계

  • 추상 클래스의 상속에 대해서 알아보면 추상 클래스를 일반 클래스에서 상속했을 경우 미완성된 추상 메서드에 대해 오버라이드 해야하는 의무를 가진다. 또한 추상 클래스에서 추상 클래스로 상속이 가능한데. 이때 추상 메서드에 대해서 오버라이드를 하지 않아도 된다.

  • 추상 클래스의 활용예를 들어 우리가 스타크래프트를 만든다는 가정을 해보자위와 같이 Unit class에서 이름과 에너지 그리고 공격했을때의 메서드를 각각 만들었다. hasAttack의 메서드를 왜 추상 메서드로 만들었냐면 스타크래프트의 각 종족마다 공격했을때 상대방 에너지를 줄이는 양이 다르기 때문이다.

      class Zerg extends Unit{
          public Zerg(Strng name){
              this.name = name;
              energy = 100;
          }
          public void hasAttack(){
              energy -= 10;
          }
      }
      class Protoss extends Unit{
          public Protoss(Strng name){
              this.name = name;
              energy = 100;
          }
          public void hasAttack(){
              energy -= 8;
          }
      }

    다음과 같이 세 종족에 대한 정의를 했는데 공격을 했을때 hasAttack에 대한 메서드를 각각 정의할 수 있었고 추상 클래스를 상속받은 일반 클래스는 추상 메서드에 대해 정의할 의무를 가지기 때문에 내가 아닌 다른 개발자가 종족을 늘리거나 새로 변경하려고 할때 컴파일러에서 오류를 내주므로 알아보기 쉽게 코딩할 수 있다.이런 추상 클래스가 필요한 이유는 여러개의 클래스들이 공통된 점을 그대로 상속받고 각자 정의 해야하는 부분에 대해서는 개별적으로 따로 작성할 수 있도록 하는 것이 효율적이기 때문이다.

  • 정리해보면 추상 클래스라는 것은 공통된 부분들만 구현하고, 공통으로 정의하지 않는 부분들에 abstract라는 예약어를 사용한 미완성 클래스이다. 클래스의 객체를 자체적으로 생성할 수 없으며 다른 클래스로 상속되어 미완성된 부분들을 반드시 재정의 해줘야한다.

class Terran extends Unit{
	public Terran(Strng name){ 
		this.name = name; energy = 100; 
	} 
    
	public void hasAttack(){
		energy -= 6; 
	} 
}
abstract class Unit{
    String name;
    int energy;
    public abstract void hasAttack(); 
}
  • 지금까지 추상화에 대해 학습했는데 도대체 어떻게 써야하며 왜 미완성의 메서드를 만들어내는지 이해할 수 없을 수도 있다. 추상화는 특정 클래스에서 일부 기능은 공통되지만 또 일부의 기능은 클래스 마다 특징적인 변화가 있을 때 상속에 의해 다른 부분만 오버라이딩하여 사용하기 위해서 이다.

인터페이스

  • 인터페이스란또한 인터페이스에서의 변수와 메서드 선언은 변수의 경우 자동으로 상수로 static final로 설정되며 메서드의 경우도 자동적으로 추상 메서드로 정의된다.
  • 인터페이스는 항상 추상화와 상속들과 연관되어 헷갈리는 존재다. 하지만 인터페이스는 인터페이스만의 특징이 존재하는데. 그것은 서비스 요청에 따른 중계자 역할을 한다는 것이다. 개발자들은 이를 음식점의 메뉴판에 많이 비유한다. 음식점에 갔을때 손님은 음식점 자체에서 메뉴를 시키는 것이 아니라 메뉴판을 보고 메뉴를 정해서 시킨다. 또한 음식점은 자신이 메뉴판에 적은 메뉴는 모두 손님에게 제공할 수 있어야한다.
  • 인터페이스의 상속또한 일반 클래스에서 인터페이스를 사용할때 상속(extends)가 아닌 구현력(implements)를 사용하여 인터페이스를 사용할 수 있는데와 같이 사용한다. 이렇게 했을때 인터페이스에 선언되어 있는 모든 추상 메서드들을 구현받은 클래스에서 모두 오버라이딩 해야한다. 그리고 위에서 인터페이스들 끼리의 상속은 가능하다고 말했었는데. 만약 일반 클래스가 상속받은 인터페이스를 구현받았을 경우 일반 클래스가 구현 받은 인터페이스의 부모 클래스에 존재하는 추상 메서드들까지 모두 구현해야한다.
  • public class TestClass implements InterfaceClass{}
  • 인터페이스는 인터페이스끼리만 상속이 가능하다. 또한 java에서의 상속은 단일 상속만 알고 있는데. 인터페이스의 경우 다중 상속도 제공한다. 하지만 인터페이스는 실제 구현력이 없으므로 상속을 받았다고 해서 인터페이스 자체에서 메서드들을 구현하진 않는다.

인터페이스는 다른 여러 객체들의 공통된 점들을 제안하고 이를 공유하여 인터페이스에 정의된 추상 메서들를 각 객체에 맞도록 재정의하여 사용하는 것이다. 그리고 인터페이스간의 상속은 다중 상속이 허용되어 여러개의 인터페이스를 구현하는 클래스에서 다형성을 함께 제공하며 객체 자체가 여러가지 타입을 가질 수 있게 해준다.

  • instance of

      객체 instance of 클래스명

    과 같이 사용할 수 있는데. 생성된 객체가 오른쪽 클래스로부터 생성되었는지에 대해 true false로 반환해준다.

  • instance of 예약어는 클래스의 형식을 비교하는 연산자이다.

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글