
추상이라는 용어의 사전적 의미는 “사물이나 표상을 어떤 성질, 공통성, 본질에 착안해 그것을 추출하여 파악하는 것”이라고 정의되어 있다. 즉, Java에서의 추상화는 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 말한다.
추상화를 쓰는 이유는 공통적인 속성과 기능을 정의하여 코드 중복을 줄이고, 클래스 간의 관계를 효과적으로 설정하고, 유지/보수를 용이하게 하는 것이다.
상속도 이 같은 이점을 가지지만, 상속은 상속한 클래스에서 더 나아가서 기능을 추가하고 싶을 때, 자식 클래스를 만든 후에 상위 클래스를 상속하지만, 추상화는 클래스들의 공통적인 요소를 뽑아 상위 클래스를 만들어 내는 것도 가능하다. 반드시 상위 클래스일 필요는 없고 공통적인 속성과 기능을 정의한 하위 클래스를 생성할 수도 있다.
자바에서는 인터페이스(interface)와 추상 클래스(abstract class) 문법을 통해 추상화를 구현할 수 있다.
추상 클래스는 미완성 설계도이다. 미완성이기 때문에 추상 클래스를 통해 인스턴스를 생성할 수 없다.
상속을 통해 하위 클래스에서 완성한 후에 인스턴스를 생성할 수 있다. 자체적으로 인스턴스화가 되지 않는 추상 클래스를 쓰는 이유는 새로운 클래스를 작성할 때, 중복되는 코드를 처음부터 끝까지 작성할 필요가 없기 때문이다. 이를 통해 유연하게 코드를 작성할 수 있게 된다.
추상 메서드는 구현부가 없이 선언부만 있는 메서드이다. 즉, 미완성 메서드이므로 사용할 수 없다.
추상 클래스를 만들고, 필수로 구현하는 기능들을 모두 구현한다. 그리고 하위 클래스들에게 직접 지정해주고 싶은 클래스들을 추상 메서드로 선언한다. 이후, 이 추상 클래스를 상속받는 하위 클래스들은 추상 클래스에 존재하는 모든 추상 메서드를 구현한 후, 인스턴스화 시켜 사용한다.
// 추상 클래스
public abstract class Parent_Abstract {
public void run() {
System.out.println("달리다.");
}
// 추상 메서드
abstract public void work();
}
// 구현체
public class Child extends Parent_Abstract {
@Override
public void work() {
System.out.println("일하다.");
}
}
// Main
public class Main {
public static void main(String[] args) {
Parent_Abstract child = new Child();
child.run();
// 달리다
child.work();
// 일하다
}
}
위처럼 공통되는 메서드는 상위 클래스에서 정의하고 기능을 정의하고 싶은 메서드만 추상 메서드를 이용해 설계하면 된다.
인터페이스는 일종의 추상 클래스라고도 할 수 있는데 모든 메서드가 추상 메서드인 것과 동일하다. 또한, 추상 클래스와는 다르게 인터페이스에서는 필드를 가질 수 없다. 메서드만 존재한다.
public interface Parent_Interface {
public void work();
}
인터페이스는 위처럼 정의한다. 따로 abstract를 붙일 필요는 없고 클래스 자체를 interface로 생성하는 순간 모든 메서드는 구현부가 존재하지 않는다.
public class Child_A implements Parent_Interface {
@Override
public void work() {
System.out.println("Child_A가 일을 합니다.");
}
}
public class Child_B implements Parent_Interface {
@Override
public void work() {
System.out.println("Child_B가 일을 합니다.");
}
}
Parent_Interface 인터페이스를 구현하는 두개의 구현체를 만든다.
public class Main {
public static void main(String[] args) {
Parent_Interface instance;
instance = new Child_A();
instance.work();
// Child_A가 일을 합니다.
instance = new Child_B();
instance.work();
// Child_B가 일을 합니다.
}
}
같은 인터페이스 타입으로 두개의 구현체의 인스턴스를 넣어 결과를 봤을 때, 서로 다른 결과값을 보여주는 것을 알 수 있다. 이처럼, Interface는 높은 추상화 차원에서 모든 메서드를 구현하도록 지정하고 싶을 때 사용한다.
추상화(Abstration)
https://www.codestates.com/blog/content/객체-지향-프로그래밍-특징
[Java] 추상화 (추상 클래스와 인터페이스)
https://velog.io/@kai6666/Java-추상화-추상-클래스와-인터페이스
[Java] Interface vs Abstract Class 정리
https://velog.io/@gillog/Java-Interface-vs-Abstract-Class-정리