자바 프로그래밍 언어에서 추상클래스는 객체 지향 프로그래밍의 핵심 개념 중 하나입니다. 이는 클래스 계층구조에서 상위 클래스의 역할을 하며, 다른 클래스들이 상속받아 구체화할 수 있는 '틀'을 제공합니다. 이 글에서는 추상클래스의 정의부터 사용법, 그리고 실제 예시코드를 통해 이해를 돕고자 합니다.
추상클래스의 정의와 목적
추상클래스는 하나 이상의 추상 메서드(abstract method)를 포함하거나, 단순히 상속을 위해 설계된 클래스입니다. 추상 메서드는 선언만 있고 구현부가 없는 메서드로, 이를 상속받는 하위 클래스가 구체적으로 구현해야 합니다. 공통의 프로토콜을 정의하고, 하위 클래스가 이를 따르도록 강제하는 것입니다.
추상클래스를 사용하는 주된 목적은 공통된 기능을 가진 클래스들 사이의 일관성을 유지하는 것입니다. 이를 통해 코드의 재사용성을 높이고, 유지보수를 용이하게 합니다. 추상클래스는 다른 클래스가 상속받아 사용할 수 있는 '기본 틀'을 제공하며, 각각의 자식 클래스는 추상클래스에 정의된 추상 메서드들을 자신의 필요에 맞게 구체화하여 사용합니다. 이러한 특성 때문에 추상클래스는 디자인 패턴에서도 자주 활용되는 중요한 요소입니다.
사용법과 예시
자바에서 추상클래스를 선언하기 위해서는 `abstract` 키워드를 클래스 선언 앞에 붙입니다. 추상클래스 자체로는 인스턴스를 생성할 수 없으며, 이를 상속받는 하위 클래스를 통해 인스턴스화해야 합니다.
예를 들어, 동물을 나타내는 추상클래스 `Animal`이 있고, 이를 상속받는 `Dog`와 `Cat` 클래스가 있다면, `Dog`와 `Cat`은 `Animal`의 추상 메소드를 구현하여 각각의 특성에 맞는 행동을 정의할 수 있습니다.
다음의 예시에서 Animal을 'abstract'키워드가 있기 때문에 추상클래스입니다. 추상클래스에 추상메소드를 선언할 수 있고, 추상메서드에도 'abstract' 키워드가 붙습니다. 아래 코드에서 `Animal` 추상 클래스는 `sound`라는 추상 메소드를 포함하고 있습니다.
abstract class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void move() {
System.out.println("이동한다");
}
public void eat() {
System.out.println("먹는다");
}
// 추상 메소드 선언
public abstract void sound();
}
다음의 `Dog`와 `Cat` 클래스는 추상 클래스인 Animal을 상속받아 추상메서드 sound()를 구현하여 각각의 동물 소리를 출력합니다. 이를 통해 다양한 동물 클래스를 생성하면서도, 공통된 행동을 추상클래스에서 관리할 수 있습니다.
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
// 추상 메소드 구현
@Override
public void sound() {
System.out.println("멍멍!!");
}
}
class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
// 추상 메소드 구현
@Override
public void sound() {
System.out.println("야옹~~");
}
}
주의사항
추상 클래스를 사용할 때는 다음과 같은 주의사항을 염두에 두어야 합니다:
1. 인스턴스화 불가능
인스턴스화 할 수 없습니다. 즉, 추상 클래스의 객체를 직접 생성할 수 없습니다. 추상 클래스는 상속을 통해 자식 클래스에서 구현되어야 합니다. 다음 예시를 살펴보겠습니다.
abstract class AbstractClass {
// 추상 메소드
abstract void abstractMethod();
}
class ChildClass extends AbstractClass {
// 추상 클래스의 추상 메소드를 구현
void abstractMethod() {
System.out.println("추상 메소드가 구현되었습니다.");
}
}
public class Main {
public static void main(String[] args) {
// 추상 클래스의 인스턴스를 직접 생성하려고 하면 컴파일 오류가 발생합니다.
// AbstractClass ac = new AbstractClass(); // 컴파일 오류
// 추상 클래스를 상속받은 자식 클래스의 인스턴스는 생성할 수 있습니다.
ChildClass cc = new ChildClass();
// 자식 클래스에서 구현된 추상 메소드를 호출할 수 있습니다.
cc.abstractMethod(); // 출력: "추상 메소드가 구현되었습니다."
}
}
위의 예시에서 AbstractClass는 추상 클래스로, 메인 클래스에서 AbstractClass의 인스턴스를 직접 생성하려고 하면 컴파일 오류가 발생합니다. ChildClass와 같이 추상 클래스를 상속받은 자식 클래스의 인스턴스는 생성할 수 있습니다. 이렇게 추상 클래스는 자식 클래스에서 구현되어야 하며, 이를 통해 다형성을 구현할 수 있습니다. 이러한 특성은 추상 클래스를 설계하고 사용할 때 반드시 고려해야 합니다.
2. 추상 메소드 구현
추상 클래스에서 선언된 모든 추상 메서드는 반드시 자식 클래스에서 구현되어야 합니다. 만약 모든 추상 메서드를 구현하지 않는다면, 해당 클래스도 추상 클래스로 선언해야 합니다.
3. 추상 클래스와 메소드 접근 제한자
메소드는메서드는 public, protected 접근 제한자를 가질 수 있습니다. private 접근 제한자를 가진 메서드는 상속받은 클래스에서 접근할 수 없으므로 추상 메서드로 선언할 수 없습니다.
4. 추상 클래스의 활용
공통적인 기능을 가진 클래스들의 공통적인 부분을 추상화하여 코드의 중복을 줄이는데 유용합니다. 따라서, 상속 계층에서 상위에 위치하는 클래스를 설계할 때 주로 사용됩니다.
5. 생성자와 소멸자
추상 클래스는 생성자와 소멸자를 가질 수 있습니다. 이들은 직접 호출될 수 없고, 자식 클래스의 생성자와 소멸자에서 호출됩니다. 생성자(Constructor)에 대해서 좀 더 살펴보겠습니다. 생성자는 객체가 생성될 때 호출되며, 객체를 초기화하는 작업을 담당합니다. 추상 클래스도 생성자를 가질 수는 있지만 인스턴스화할 수 없기 때문에 추상 클래스의 생성자는 직접 호출될 수 없습니다. 대신에 자식 클래스의 생성자에서 super()를 통해 호출됩니다.
생성자에 대한 예시를 살펴 보면 다음과 같습니다. 추상클래스인 AbstractClass에서 생성자를 선언만 하고 자식클래스인 ChildClass에서 super()를 통해서 호출하고 있습니다.
abstract class AbstractClass {
int x;
// 추상 클래스의 생성자
public AbstractClass() {
x = 10;
}
}
class ChildClass extends AbstractClass {
// 자식 클래스의 생성자에서 추상 클래스의 생성자 호출
public ChildClass() {
super();
}
}
public class Main {
public static void main(String[] args) {
ChildClass myObj = new ChildClass(); // 추상 클래스의 생성자 호출
System.out.println(myObj.x); // 출력: 10
}
}
결론
추상클래스는 자바에서 객체 지향의 다형성을 실현하는 데 중요한 역할을 합니다. 이를 통해 개발자는 보다 유연하고 확장 가능한 코드를 작성할 수 있으며, 프로그램의 복잡성을 관리할 수 있습니다. 또한, 코드의 재사용성을 높이고, 유지보수를 용이하게 하는 등 다양한 이점을 제공합니다. 하지만, 본문에서 살펴본 주의사항을 지키지 않으면 예상치 못한 오류를 발생시킬 수 있으므로 반드시 지켜야 합니다.
2024.05.21 - [Java] - 자바(Java) 인터페이스(Interface) 개념, 사용법, 장점, 실용 예제
자바(Java) 인터페이스(Interface) 개념, 사용법, 장점, 실용 예제
자바 프로그래밍에서 인터페이스는 매우 중요하기 때문에 반드시 기억해야 하는 개념인데요. 인터페이스는 객체지향 프로그래밍의 핵심 원칙인 다형성(polymorphism)을 구현하는 데 큰 역할을 합
it-learner.tistory.com