추상클래스
추상클래스(abstract class)는 1개 이상의 추상메소드를 멤버로 가지고 있는 클래스를 말한다. 추상클래스는 추상메소드를 포함하고 있다는 점을 제외하면 일반 클래스와 모든 점이 동일하며 생성자와 필드, 메소드도 포함할 수 있다.[1] 추상클래스 중에서 오직 추상메소드와 상수만을 멤버로 가지고 있는 것을 인터페이스(Interface)라고 한다.
목차
개요
추상클래스는 실체클래스의 공통적인 부분을 추출해서 선언한 클래스이며 실체성이 없고 구체적이지 않기 때문에 객체를 생성할 수 없다. 그러므로 실체클래스와의 상속관계를 통해 사용할 수 있다.[2] 클래스를 설계도라고 했다면 추상클래스는 미완성 설계도라고 할 수 있다. 클래스가 미완성이라는 것은 미완성 메소드를 포함하고 있다는 의미로 온전한 객체를 생성할 수 없다.[3]
목적
추상클래스의 목적은 공통적인 기능을 하는 객체들의 추상화로 객체를 생성하는 것이 아닌 상속을 위한 슈퍼 클래스로 활용하는 것이다.[4] 추상클래스는 추상메소드를 통해 추상클래스를 상속받는 서브 클래스가 구현할 메소드의 원형을 알려주는 인터페이스의 역할을 하고 서브 클래스의 다형성을 실현한다.
소스 수정시 다른 소스의 영향도를 적게 가져가면서 변화에는 유연하게 만들기 위해 추상클래스를 사용한다. 규격에 맞게 소스가 구현되어 있기 때문에 해당 규격에 대한 구현부만 수저하면 손 쉽게 수정이 가능하기 때문이다.[2]
통일 목적
추상클래스에서 미리 정의한 필드와 메소드가 있으면 실체클래스에서는 추상클래스의 필드와 메소드명을 변경할 수 없고 무조건 해당 명명으로 구현해야한다. 이로인해 필드와 메소드 이름을 통일하여 유지보성을 높이고 통일성을 유지할 수 있다. 예를들어 A자동차를 만드는데 각기 다른 실체클래스를 사용한다면 이후에 자동차를 교체하거나 업그레이드할 때 수정하거나 교체하는데 상당히 무리가 있다. 그렇기 때문에 새로 개발을 해야하는 상황이 올 수 있지만 추상클래스를 사용해 미리 필드와 메소드를 정의한다면 유지보수가 쉬워진다.[2]
시간 절약
기존에 작성된 추상클래스를 통해 주어지는 필드와 메소드를 가지고 구현만 하면 되기 때문에 설계 시간이 절약되고 구현에 집중할 수 있기 때문에 사용한다. 예를들어 자동차 클래스를 구현하는데 바퀴, 기어, 핸들 등의 필드와 메소드를 추상클래스에서 가져와 오버라이딩하면 되기 때문에 구현에 있어서 시간이 절약되고 편해진다.[2]
규격
규격에 맞는 실체 클래스를 구현 할 수 있다. 대부분의 구현은 혼자만 하는 것이 아니기 때문에 규격 안에서 구현을 해야한다. 모두가 약속한 필드와 메소드, 설계 규칙에 맞게 클래스를 구현해야 유지보수가 쉬워진다.[2]
생성 및 구현
추상메소드를 가진 클래스로써 abstract로 선언하여 생성하고 추상클래스의 구현은 서브 클래스에서 슈퍼 클래스의 모든 추상메소드를 오버라이딩하여 실행 가능한 코드로 구현하는 것이다.[5] 문법은 간단하게 클래스 앞에 abstract 키워드를 붙여주면 추상클래스가 만들어진다.
//추상클래스 생성 abstract class A{ abstract public int add(int a, int b); }
//추상클래스 구현 class B extends A{ @Override public int add(int a, int b){ return a+b; } }
추상메소드 또한 메소드 리턴 타입 앞에 abstract 키워드를 붙이면 된다.[2]
[public | protected] abstract 리턴타입 메소드명(매개변수1, 매개변수2, ...);
예시로 Animal이라는 추상클래스를 구현해 사용해 보겠다.[2]
public abstract class Animal { public String type; public void breath(){ System.out.println("breathing!!."); } //추상메소드 public abstract void sound(); }
Animal 클래스 앞에 abstract 키워드가 있기 때문에 해당 클래스는 추상 클래스이다. 필드에는 type와 breath() 일반 메소드와 sound() 추상메소드가 있다. 이 추상 클래스를 상속 받는 실체 클래스들은 반드시 추상메소드를 상속받아 오버라이딩해야 한다.[2]
public class Dog extends Animal{ public Dog(){ this.type = "mammalia"; } @Override public void sound() { // TODO Auto-generated method stub System.out.println("bau! bau!"); } }
extends를 사용해 animal 추상 클래스를 상속받은 Dog 실체 클래스는 sound() 추상 메소드를 오버라이딩해 구현했다. 이 때 다른 실체 클래스에서 animal 추상클래스를 상속 받은 실체 클래스는 자신에게 맞게끔 추상 메소드를 변형 시킬 수 있으며, 다형성이 발생된다.[2]
특징
추상 클래스는 자체적으로 객체 생성이 불가능하여 상속을 통해 자식 클래스의 인스턴스를 생성해야한다. 즉, 서브 클래스가 상속을 통해 객체를 생성해야 하는 것이다.[6] 그리고 추상 클래스를 상속받은 클래스는 추상 메소드를 반드시 오버라이딩 해야한다. 오버라이딩 할 때 abstract를 제외한 시그니처를 클래스에서 동일하게 적어줘야한다.
기능
추상 클래스 자체만으로는 클래스로서의 역할을 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 부모클래스로서 중요한 의미를 갖는다. 예를들어 볼펜에는 다양한 볼펜이 있는데 이들 모두 조금씩 모양이나 특징이 다르다. 하지만 이 볼펜들의 설계도는 많은 부분에서 동일한 부분이 나온다. 서로 다른 설계도를 만드는 것보다 이들의 공통점을 모아서 미완성된 설계도를 만들어두면 완제품을 만드는데 효과적이다.[3] 추상 클래스도 미완성 설계도와 같은 역할을 한다. 비슷한 객체를 생성할 때 추상 클래스로부터 상속을 받아 만든다면 더욱 효과적으로 생성할 수 있는 것이다.
구성
추상 클래스는 추상 메소드, 일반 메소드, 필드, 생성자로 구성된다. 기본 클래스와 구성은 비슷하지만 추상 메소드와 같이 추상적으로 생성한다는 차이가 있다.
public abstract class 클래스명 { //필드 //생성자 //메소드 }
추상메소드
추상메소드(abstract method)는 선언부만 있고 구현부가 없는 메소드로 꼭 필요하지만 자식마다 다르게 구현될 것으로 예상되는 경우에만 사용한다. 추상 클래스를 상속받은 자식 클래스에서는 추상 메소드의 구현부를 완성해야한다. 만약에 자식 클래스에서 추상 메소드의 구현부를 다 정의하지 않는다면 abstract를 붙여주어 사용해야한다.[7]
public abstract class Animal { public String type; public void breath(){ System.out.println("breathing!!."); } //추상메소드 구현과 위치 public abstract void sound(); }
일반 메소드
메소드(method) 또는 멤버 함수(member function)는 객체 지향 프로그래밍에서 객체와 관련된 서브 루틴 (또는 함수)이며 데이터와 멤버 변수에 대한 접근 권한을 갖는다. 클래스 기반 언어에서 클래스 내부에 정의되어 있다. 메소드는 프로그램이 실행되고있을때 클래스에서 생성된 인스턴스와 관련된 동작을 정의한다. 메소드는 런타임 중에 클래스 인스턴스에 저장되어 있는 데이터에 접근할 수 있는 특수 속성을 가지고 있다. 바인딩은 클래스와 메소드 간의 연관관계를 말한다.[8]
public abstract class Animal { public String type; //일반 메소드 구현과 위치 public void breath(){ System.out.println("breathing!!."); } public abstract void sound(); }
필드
필드는 클래스에 포함된 변수를 의미하는데 클래스 내부에 선언되지만 생성자와 메소드 밖에 생성되는 변수이다.[9]
public abstract class Animal { //필드 구현과 위치 public String type; public void breath(){ System.out.println("breathing!!."); } public abstract void sound(); }
생성자
생성자는 new 연산자를 통해 객체를 생성할 때 반드시 호출이 되고 제일 먼저 실행되는 일종의 메소드이다. 생성자는 멤버 변수를 초기화하는 역할을 한다. 하지만 추상클래스는 객체를 생성할 수 없다. 그런데도 생성자를 가질 수 있다. 추상 클래스에서 사용하는 생성자는 클래스에 필요한 어떠한 제약을 줄 때 사용한다.[10]
추상클래스와 상속
객체를 생성할 수 없는 추상 클래스는 상속과 결합하여 사용해야한다. 추상 클래스를 상속 받는 자식 클래스는 추상 클래스의 추상 메소드를 오버라이딩해야하며, 만약 부모인 추상 클래스의 추상메소드를 오버라이딩하지 않는다면 자식 클래스는 객체를 생성할 수 없게 된다. 즉, 추상 클래스를 부모 클래스로 지정한 자식 클래스는 부모의 모든 추상 메소드를 오버라이딩 해야 객체를 생성할 수 있다는 것이다.[11]
class dog extends Animal { public void sound() { //위 추상 메소드 활용 System.out.println("컹컹"); } }
인터페이스와 추상 클래스
인터페이스는 일종의 추상클래스로 추상클래스보다 추상화 정도가 높다. 실제 구현된 것이 전혀 없는 기본 설계도라고 볼 수 있다. 또한 인스턴스를 생성할 수 없고, 클래스 작성에 도움을 줄 목적으로 사용된다.
공통점
추상 클래스와 인터페이스는 선언만 있구 구현 내용이 없는 클래스이다. 그래서 자신이 new를 통해 객체를 생성할 수 없으며, 추상클래스를 extends 받거나, interface를 implements한 객체를 생성할 수 있다. 상속받은 자식이 구현을 반드시 하도록 해야할 때 사용한다.
자바에서는 타입이 지정되있기 때문에 선언된 타입과 자식의 타입이 같아야한다.
차이점
추상클래스는 말 그대로 클래스이고, 인터페이스는 구현하기 전에 메소드에 대해 명세된 것이다. 그래서 상속을 받음에도 클래스는 상속이라 하지만 인터페이스의 경우 구현이라고 한다.
추상클래스는 abstract 메소드가 하나라도 존재하는 클래스를 일컫는다. 때문에 일부는 구현된 메소드도 있으며, abstract라고 붙어있는 메소드는 구현이 안되어있다. 그리고 추상클래스를 상속받는 클래스는 반드시 추상 메소드를 구현해야한다. 그래서 필수적으로 구현해야 할 메소드가 있을 때 추상 클래스를 사용하게 된다.
인터페이스는 구현체 없이 메소드에 대한 명세만 되어있다. 인터페이스를 상속받는 클래스에서는 반드시 인터페이스에 있는 메소드를 전부 구현해야한다.
자바는 단일 상속을 지원하기 때문에 추상클래스는 단일 상속이지만, 인터페이스를 사용하게 되면, implements 부분에서 extends 또한 사용하기 때문에 다중 상속이 가능해진다.[12]
차이점[13] 인터페이스 추상 클래스 클래스가 아니다 클래스다 클래스와 관련이 없다 클래스와 관련이 있다. (주로 베이스 클래스로 사용)
한 개의 클래스에 여러 개를 사용할 수 있다. 한 개의 클래스에 여러 개를 사용할 수 없다. 구현 객체의 같은 동작을 보장하기 위한 목적 상속을 받아서 기능을 확장시키는데 목적
활용
추상 클래스를 사용하는 이유는 자식 클래스에서 추상메소드를 반드시 구현하도록 강요하기 위해서이다. 상속받은 자식 클래스에서는 메소드들이 완전히 구현된 것으로 인식하고 오버라이딩하지 않을 수 있기 때문이다.[14] 그래서 추상 클래스로 객체를 생성하려면 자식 클래스를 작성해야 하며 추상메소드들을 오버라이딩해야 한다. 이는 추상 클래스를 사용해 유지보수의 편의성을 높이기 위함이고 최소한의 수정으로 원하는 객체를 사용할 수 있게 되어 유지보수성이 좋아진다.
용도
동물들을 이용해 코드를 작성했을 때,
class Tiger { private String name; public void eat() { System.out.println("냠냠"); } } class Rabbit { private String name; public void eat() { System.out.println("냠냠"); } } class Lion { private String name; public void eat() { System.out.println("냠냠"); } } class Giraffe { private String name; public void eat() { System.out.println("냠냠"); } }
위와 같이 코드가 중복 될 수 있다. 하지만 이 내용을 상속을 통해서 최소화 시킬 수 있다. 그리고 호랑이, 토끼, 사자, 기린은 실제로 존재하는 동물이고 동물 자체는 실제 존재하는 것이 아니라 추상적인 의미라고 할 수 있다. animal이라는 추상 클래스를 생성했을 때 우리가 알고있는 동물이라는 추상적인 단어와 같이 선언 할 수 있는 것이다.[15]
각주
- ↑ TCPSCHOOL, <추상클래스>, <<TCPSHOOL>>
- ↑ 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 Limky Lim-ky", 〈자바 추상클래스란?〉, 《개인블로그》, 2019-05-08
- ↑ 3.0 3.1 lshjh4848, 〈추상클래스와 인터페이스〉, 《개인블로그》, 2019-11-04
- ↑ 피누, <인터페이스와 추상클래스>, <<litien.log>>, 2019-11-17
- ↑ 황기태, <JAVA ESSENTIAL>, <<생능출판사>>, 2018-08-10
- ↑ JOKER, <추상 클래스(abstract class), 추상 메소드)>, <<JOKER`s ROOM>>, 2017-03-21
- ↑ 김현17, <추상클래스, 인터페이스, 내부클래스>, 《개인블로그》, 2017-08-15
- ↑ 위키백과, <메소드 (컴퓨터 프로그래밍)>, 《위키피디아》
- ↑ TCPschool, <필드의 구분>, 《TCPschool》
- ↑ 10106men, <추상 클래스에서 생성자가 있을 수 있습니까?>, 《개인블로그》, 2020-02-04
- ↑ Dev Cristoval, <추상 클래스(Abstract Class)>, 《개인블로그》, 2019-08-12
- ↑ 신매력, <추상화클래스와 인터페이스의 용도, 차이점, 공통점>, 《Take Action》
- ↑ loustler 블로그, <인터페이스(interface)와 추상 클래스(abstract class)>, 《개인 블로그》
- ↑ 글쓰는 개발자 _Jbee, <추상클래스와 추상메서드>, 《개인 블로그》, 2016-06-27
- ↑ 클라우드스터딩, <추상클래스>, 《클라우드 스터딩》
참고자료
- TCPSCHOOL, 〈추상클래스〉, 《TCPSCHOOL》
- Limky Lim-ky", 〈자바 추상클래스란?〉, 《개인블로그》, 2019-05-08
- lshjh4848, 〈추상클래스와 인터페이스〉, 《개인블로그》, 2019-11-04
- 피누, 〈인터페이스와 추상클래스〉, 《litien.log》, 2019-11-17
- 황기태, 〈JAVA ESSENTIAL〉, 《생능출판사》, 2018-08-10
- JOKER, 〈추상 클래스(abstract class), 추상 메소드)〉, 《JOKER's ROOM》, 2017-03-21
- 김현17, <추상클래스, 인터페이스, 내부클래스>, 《개인 블로그》, 2017-08-15
- 위키백과, <메소드 (컴퓨터 프로그래밍)>, 《위키피디아》
- TCPschool, <필드의 구분>, 《TCPschool》
- 10106men, <추상 클래스에서 생성자가 있을 수 있습니까?>, 《개인블로그》, 2020-02-04
- 신매력, <추상화클래스와 인터페이스의 용도, 차이점, 공통점>, 《Take Action》
- loustler 블로그, <인터페이스(interface)와 추상 클래스(abstract class)>, 《개인 블로그》
- 글쓰는 개발자 _Jbee, <추상클래스와 추상메서드>, 《개인 블로그》, 2016-06-27
- 클라우드스터딩, <추상클래스>, 《클라우드 스터딩》
- Dev Cristoval, <추상 클래스(Abstract Class)>, 《개인블로그》, 2019-08-12
같이 보기