본문 바로가기

Java

추상 메서드와 추상 클래스

훈수/저작권 관련 지적 환영합니다 - 댓글 또는 audgnssweet@naver.com

 

추상 메서드와 추상 클래스


추상 메서드란, 선언만 되어있고 구현은 되어있지 않은 메서드를 의미합니다.

 

    public abstract void doSomething();

위와 같은 형태로 접근 지정자 뒤, 반환형 앞에 abstract 예약어를 붙여 선언해줍니다.

 

추상 메서드는 추상 클래스 안에 선언되며, 해당 추상 클래스를 상속받은 클래스가 같은 추상 클래스가 아니라면,

반드시 해당 메서드를 구현해주어야 합니다.

 

추상 클래스란, 직접적으로 생성자를 호출하여 인스턴스를 생성할 수 없는 클래스를 의미합니다.

추상 클래스는 추상 메서드를 가질 수도, 가지지 않을 수도 있습니다.

 

public abstract class Person {
    public abstract void doSomething();
}
public abstract class Person {
    public void doSomething() {
        System.out.println("do something");
    }
}

위 두 클래스는 모두 추상 클래스입니다.

말씀드렸듯 추상 클래스는 추상 메서드를 가질 수도 있고 아지지 않을 수도 있습니다.

그러나 추상 메서드를 갖고 있다면 반드시 추상 클래스로 선언해주어야 합니다.


public abstract class Person {
    public abstract void doSomething();
}

class Professor extends Person {
    @Override
    public void doSomething() {
        System.out.println("do research & teaching");
    }
}

위처럼 추상 클래스를 상속받아 추상 메서드를 구현한 클래스를 concrete class라고 합니다.

 

그러나 상속 받는다고 해서 반드시 구현해야 하는 것은 아닙니다.

 

public abstract class Person {
    public abstract void doSomething();
}

abstract class Runner extends Person {
}

위 코드처럼 상속 받더라도 추상 클래스로 만들면 구현하지 않아도 됩니다.

그러나 Runner 클래스를 상속받은 다른 클래스는 구현을 꼭 해주어야겠죠?


그러면 추상 클래스는 언제 사용할까요?

 

- 추상 클래스에, 하위 클래스에서 공통적으로 쓰이는 기능이나 속성을 정의하고 상속받아 사용하도록 합니다.

- 추상 메서드는 서브 클래스에서 구체적으로 구현합니다. 각 서브클래스마다 목적과 기능을 달리 구현할 수 있습니다.

- 계층적 상속 구조를 만들 수 있습니다.

 

이전 게시글(메서드 오버라이딩과 다형성)에서 사용했던 클래스 구조입니다.

professor과 student, gamer은 각각 doSomething()을 했을 때, 자신만의 구체적인 행위를 하지만

person은 단순히 다형성을 위해 doSomething()을 구현했었고, person의 doSomething() 메서드를 직접적으로

사용할 일은 없습니다. 이럴 때 Person 클래스를 추상 클래스로 만들어주면 Person 객체가 독립적으로

생성되지 않음을 보장할 수 있으면서 동시에 다형성도 구현할 수 있습니다.

 

public abstract class Person {
    public abstract void doSomething();
}

class Professor extends Person {
    @Override
    public void doSomething() {
        System.out.println("do research & teaching");
    }
}

class Student extends Person {
    @Override
    public void doSomething() {
        System.out.println("do studying");
    }
}

class Gamer extends Person {
    @Override
    public void doSomething() {
        System.out.println("do gaming");
    }
}

위처럼 구현하면 됩니다.


마지막으로 추상 클래스가 인스턴스화되지 않는다는 것은, 엄밀히 말하면 틀린 표현입니다.

추상 클래스 독립적으로 인스턴스화할 수 없다는 말이 더 정확합니다.

 

위에서 Person 클래스는 new Person()을 통해서 독립적인 객체를 생성할 수는 없지만,

Person 클래스를 상속받은 구체 클래스들이 new Student() 등으로 인스턴스화 한다면

기존의 상속구조와 같이 메모리에 생성됩니다.

 

위 구조처럼 생성되는 것입니다.

 

추상 클래스의 추상 메서드를 오버 라이딩 함으로써 다형성을 구현할 수 있을 것입니다.


마지막으로 조금 디테일한 문법에 대해서 알아보겠습니다.

public abstract class Person {
    abstract void doSomething();
}

추상 클래스에서 추상 메서드를 선언 및 오버라이딩 할 때 주의할 점이 있습니다.

바로 접근 지정자입니다.

 

public abstract class Person {
    private abstract void doSomething();
}

우선 위와같은 추상메서드 선언은 불가능합니다.

추상메서드는 하위 클래스에서 구현해야 하는데 private 접근 지정자를 붙이면 오버라이딩을 할 수 없기 때문입니다.

 

public abstract class Person {
    abstract void doSomething();
}

그리고 접근 지정자 범위를 기억하시나요?

private -> default -> protected -> public 순이었습니다.

추상 메서드를 오버라이딩 할 때

선언된 추상 메서드보다 접근 지정자의 범위를 낮출 수는 없습니다.

 

아래 예시를 보면 더 확실하게 알 수 있습니다.

public abstract class Person {
    abstract void doSomething();
}

//불가능
class Professor extends Person {
    @Override
     private void doSomething() {
        System.out.println("do research & teaching");
    }
}

//가능
class Professor extends Person {
    @Override
     protected or public void doSomething() {
        System.out.println("do research & teaching");
    }
}

위의 예시에서는 추상 메서드가 default 접근 지정자로 선언되었으므로

구현하는 메서드는 default, protected, public만 가능합니다.

 

여기까지 추상 메서드와 추상 클래스에 대해서 알아보았습니다.