[JAVA]추상클래스에 대하여 알아보자

Inung_92·2023년 2월 22일
2

JAVA

목록 보기
8/15
post-thumbnail

추상 클래스(Abstract Class)란?

📖하나 이상의 추상 메소드를 포함하는 클래스

일반적으로 우리가 사용하는 클래스는 구체적(concrete)으로 데이터를 담아 인스턴스화하는 클래스이다. 그와 반대로 추상 클래스는 특정 개발 시점에 내용을 확정지으면 안되거나 계획(틀)만을 세울 때 추상적인(abstract) 데이터를 담고 있는 클래스이다. 또한, 하나 이상의 추상 메소드를 보유함으로써 클래스를 불완전한 상태로 선언하여 서브 클래스로 하여금 메소드 오버라이드를 통해 추상 메소드를 완성하도록 구현을 강제한다.

그렇다면 어떤 특징이 있는지 알아보자.

⚡️ 추상 클래스의 특징

  • 추상 메소드와 일반적인 메소드를 선언할 수 있다.
  • 추상 클래스를 상속받는 모든 서브 클래스들은 추상 메소드를 반드시 재정의(강제구현)해야한다.
  • new 연산자 사용을 통한 인스턴스화가 불가능하다.
  • 추상 클래스를 선언 할 때에는 abstract 키워드를 사용해야한다.

아래는 위의 특징들을 설명한 코드이다.

//abstract 키워드 사용
public abstract class Test{
	/*
     -추상 메소드(abstract 키워드 생략가능)
     -{}블록이 없기 때문에 상속받은 서브클래스에서 재정의(강제구현)
    */
    public abstract void testMethod();
    //일반 메소드
    public void testMethod2(){
    	실행문 작성...
    };
}

⚡️ 추상 클래스와 추상화

추상 클래스의 특징도 중요하지만 추상 클래스를 사용할 때 달성할 수 있는 추상화에 대한 이해도 중요하다.
우리는 현실 세계에서 다양한 추상화 경험을 하게된다. 예를 들어 우리가 운전을 할 때 자동차의 핸들을 돌리고 있지만 핸들이 돌아갈 때 자동차 내부의 구성품들이 어떻게 상호작용을 하고 그 원리가 무엇인지에 대해서는 거의 고려하지 않는다. 이렇게 우리가 구체적 동작원리는 이해하거나 알지 못하지만 사용하는 것이 추상적인 것이라고 할 수 있다.

정리를 해보자면 추상 클래스는 우리가 현실세계에서도 자주접하는 추상화를 클래스에 접목시킨 것이라고 할 수 있다.즉, 추상 클래스는 일반 클래스보다 구조적이게 객체를 설계하고, 그만큼 프로그램의 유지보수성을 향상시키는 효과가 있다.


추상 클래스의 사용

⚡️ 추상 메소드

추상 클래스에 대한 사용을 알아보기 이전에 추상 메소드를 간단하게 짚어보겠다.

추상 메소드는 작동 로직은 없고 실행부만 존재하는 껍데기만 있는 메소드라고 생각하면 편하다. 즉, 메소드의 구현부가 미완성인 채로 남겨지기 때문에 이를 오버라이드하는 서브 클래스에서 실행부에 세부적인 로직을 구현해야한다.

//추상 메소드
public void abstractMethod();

이러한 특징 때문에 추상 메소드를 오버라이드할 때에는 선언부에 대한 변경은 불가능하지만 예외에 대해서는 제약없이 처리가 가능하다는 점을 기억하면 좋을 듯 하다.

⚡️ 기본 문법

위에서 설명한 추상 메소드가 하나 이상 클래스내에 존재한다면 해당 클래스는 추상 클래스로 선언하여야하며, 선언하는 방식은 다음과 같다.

🖥️ 추상 클래스 선언

public abstract class Test{}

여기서 abstract 키워드를 사용하는 것에 대해 생각해보면 내부에 추상 메소드가 적어도 하나 이상 존재하니 해당 메소드를 재정의해서 사용하라고 알려주는 것과 같다. 즉, 추상 메소드를 오버라이드하여 사용하라는 강제 구현을 강요하는 것이라고도 할 수 있다.

🖥️ 추상 클래스의 멤버

추상 클래스는 사실 추상 메소드를 보유하고 있는 것 외에는 일반 클래스와 크게 다르지 않다고 볼 수도 있다. 아래는 멤버를 보유한 추상 클래스를 선언한 코드이다.

//추상 클래스 선언
public abstract class Pet{
	//추상 메소드
	public abstract void walk();
    //abstract 키워드 생략
    public void eat();
    
    //인스턴스 멤버
    public int age;
    public void run(){
    	System.out.printn("run");
    }
}

이렇게 추상 메소드와 일반적인 멤버 변수 및 메소드를 포함하여 선언이 가능하다. 그렇다면 위와 같은 코드의 클래스를 상속받은 서브 클래스는 어떤지 살펴보자.

🖥️ 서브 클래스

public Dog extends Pet{
	//슈퍼 클래스가 보유한 추상 메소드 재정의(강제구현)
    @Override
    public void walk(){ //중괄호를 붙인 것만으로도 강제구현이 적용
    };
    @Override
    public void eat(){
    	System.out.println("얌얌");
    }
    
    //멤버 변수 및 메소드 생략...
}

여기서 인터페이스와의 차이가 나타난다고도 볼 수 있다. 아직 인터페이스가 무엇인지 모른다면 여기를 클릭해서 알아보자.

인터페이스는 추상메소드와 상수를 보유한 일종의 추상 클래스를 의미하는데 추상 클래스와의 가장 큰 차이는 다중상속이 불가능한 단점을 보완할 수 있다는 것이다. 즉 하나의 클래스는 여러가지의 인터페이스를 구현할 수 있다. 무슨 이야기인지 조금만 더 알아보면 추상 클래스는 해당 클래스내에 선언된 모든 추상 메소드를 서브 클래스가 강제구현해야한다. 즉 추상 클래스의 멤버만 보유하고 싶다고 하더라도 우선은 추상 메소드를 {}만 작성해서라도 오버라이드 해야한다는 뜻이다.
그에 비해 인터페이스는 다중구현이 가능하기 때문에 추상 메소드의 기능 또는 특징별로 인터페이스를 나누면 된다. 그렇게 나눠진 인터페이스를 필요한 클래스에서 복합적으로 구현하면 되기 때문이다.

어쨋든 갑자기 인터페이스가 튀어나왔지만 추상 클래스와 인터페이스의 차이에 대해서는 알아두자.

⚡️ 추상 클래스의 생성자

추상 클래스는 기본적으로 new 연산자를 통한 인스턴스화가 불가능하다. 그렇다면 생성자를 아예 사용하지 못하는 것일까? 그렇지는 않다. 추상 클래스내에 생성자 메소드를 선언하고 해당 클래스를 상속받은 서브 클래스에서 super키워드를 통해 생성자 메소드를 호출할 수 있다.

🖥️ 추상 클래스의 생성자

//추상 클래스 선언
public abstract class Pet{
	//멤버변수 선언
	public int age;

	//생성자 메소드
	public Pet(int age){
    	this.age = age;
    }
    
    //추상 메소드
    public void walk();
}

//서브 클래스 선언
public class Dog extends Pet{
	//Dog클래스만의 멤버변수 선언
	public String name;
    
    public Dog(int age, String name){
    	super(age); //추상클래스의 생성자메소드 접근
        this.name = name;
    }
    
    //추상 메소드 구현
    @Override
    public void walk(){...};
}

위 코드와 같이 서브 클래스의 인스턴스가 생성될 때 부모 클래스의 생성자 실행을 선행하여 인자를 제어해 줄 수도 있다는 것이다.


마무리

이번 글에서는 추상 클래스에 대해서 알아보았다. 인터페이스와의 헷갈릴 수 있으며, 사용하는 방식에 따라 일반 클래스와 크게 다르지 않다고 생각할 수도 있다.
하지만 객체지향 프로그래밍의 특징 중 하나인 다형성을 고려해보면 구현되어 있지 않은 기능을 다양한 클래스들이 상속받아 각 클래스 별로 개성있는 방식으로 구현하고, 하나의 자료형으로 상황에 따라 인스턴스를 다양하게 생성하여 사용할 수 있다는 측면에서 추상 클래스의 역할은 굉장히 크다고 볼 수 있다.

추상 클래스에 대한 이해가 아직은 전반적으로 부족하고, 오히려 인터페이스를 더 많이 사용하지만 많은 경험을 하다보면 클래스와 인터페이스의 근본적인 차이를 기반으로 추상 클래스를 효과적으로 활용할 수 있는 날이 올 것이라고 생각한다.

그럼 이만.👊🏽

profile
서핑하는 개발자🏄🏽

1개의 댓글

comment-user-thumbnail
2023년 12월 14일

정리하신 글 너무 잘 봤습니다!! 감사합니다!!
하지만 글을 읽다보니 헷갈리는 부분이 생겨서 댓글을 남깁니다!!

추상 클래스의 멤버라는 작은 주제 안에 아래와 같은 예시가 있더군요
여기서 eat() 메소드에서 abstract 키워드를 생략하셨는데, 이후에 Dog 클래스에서 상속받아 구현하셨던데
제가 알기론 추상 클래스에서 추상 메소드는 abstract를 명시적으로 선언해줘야 일반 메소드와 컴파일러 입장에서 혼동이 없는걸로 알고있습니다. 현재 자바 17버전 기준으로도 컴파일 오류가 발생도 하더군요 혹시 이 부분이 정상적으로 동작했다면 어떻게 해결하면 되는지 알려주시면 감사하겠습니다!!

//추상 클래스 선언
public abstract class Pet{
	//추상 메소드
	public abstract void walk();
    //abstract 키워드 생략
    public void eat();
    
    //인스턴스 멤버
    public int age;
    public void run(){
    	System.out.printn("run");
    }
}
답글 달기