추상클래스와 인터페이스(abstracts, interface)는 상속받는 클래스 혹은 구현하는 인터페이스 안에 있는 추상 메소드를 구현하도록 강제하는 것이다. 결국 둘 다 비슷한 일을 하는 것이라고 느껴진다. 하지만 서로 사용 목적이 다르기 때문에 아래글을 읽어보며 특징을 알아보자.
둘 다 자기 자신이 new를 통해 객체를 생성할 수 없고, 오로지 자식만이 객체를 생성할 수 있습니다.
둘 다 추상 메서드(abstract method)를 갖습니다.
둘 다 하위 클래스에서 추상 클래스를 모두 구현해야 합니다.
추상클래스(Abstract Class)
- 상속하여 공통된 기능을 만들고, 확장하기 위함
- 다중상속 불가능
- 생성자와 일반변수 모두 가질 수 있다.
- 메서드를 부분적으로 구현할 수 있다.
- extends 키워드를 사용한다.
인터페이스(Interface)
- 구현하는 객체들이 같은 동작을 보장하기 위함
- 다중상속 가능
- 생성자와 일반변수를 가질 수 없다.
- 메서드 선언만 가능하다.
- implements 키워드를 사용한다.
- 부모의 메소드를 반드시 모두 오버라이딩해야 한다.
아래와 같은 예시를 들어 이해하고 왜 사용해야 하는지 이해 해 봅시다.
추상클래스
는 공통점을 뽑아놓은 클래스라고 생각하시면 되겠습니다. 여러 자식들이 가지고 있는 공통된 속성들을 뽑아서 하나의 클래스를 만들어 놓은 것을 뜻합니다. 그래서 하위 클래스에서도 extends(상속)이라는 키워드를 사용하여 이 추상 클래스를 상속받아 객체를 구체화시켜갑니다. 이때 상속의 의미는 is a kind of (~의 한 종류)라는 의미를 가지게 됩니다. 예를 들자면 사자 is a kind of 동물이라는 의미를 말이죠. 추상 클래스는 클래스라는 이름에서 알 수 있듯 엄연한 객체입니다. 비록 단독으로 생성하지는 못하지만 객체이기에 생성자도 사용할 수 있죠. 인터페이스와는 완전히 다른 개념 입니다.
public class ExamAbstract {
/**
* 추상클래스 & 추상메서드 abstract 사용하기 추상클래스는
* 말그대로 약간 추상적인 의미를 가진 클래스여야 하며
* 비추상적인 클래스에서 이를 상속받아 사용합니다.
*/
public static void main(String [] ar){
Tiger tiger = new Tiger("Hodol");
tiger.cry();
tiger.behavior();
System.out.println("사자의 이름은 :" + tiger.animal_name);
Dog dog = new Dog("Mikey");
dog.cry();
dog.behavior();
System.out.println("개의 이름은 :" + dog.animal_name);
}
}
// 추상 클래스
abstract class Animal {
String animal_name;
Animal(String name) {
animal_name = name;
}
public abstract void cry();
public abstract void behavior();
}
class Tiger extends Animal {
public Tiger(String name) {
super(name);
}
@Override
public void cry() {
// TODO Auto-generated method stub
System.out.println("어흥");
}
@Override
public void behavior() {
// TODO Auto-generated method stub
System.out.println("우측으로 빠르게 움직인다.");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void cry() {
// TODO Auto-generated method stub
System.out.println("멍멍");
}
@Override
public void behavior() {
// TODO Auto-generated method stub
System.out.println("왼쪽으로 느리게 달린다");
}
}
인터페이스
는 객체가 아니라 추상 자료형입니다. 객체가 아니기에 생성자도 사용할 수 없습니다. 오로지 상수와 추상 메서드만 가질 수 있고 이것을 다른 객체가 구현합니다. 그래서 implement(구현하다)라는 키워드를 사용하는 것입니다. 이때 구현의 의미는 be able to(~할 수 있는)이라는 의미를 가집니다.
그런데, 추상클래스 하나를 두고, 각각 껍데기(추상 메소드)들만 두고 상속받는 객체에서 구현(오버라이드)하면 되는데 왜 인터페이스라는 개념을 사용할까?
답은 자바가 다중 상속을 지원하지 않기 때문이다.
다중 상속이라는 것은 super class(부모 클래스)를 2개 이상 두는 것이다. 예를 들어서
//다중 상속
class Futurecar extends Car, Plane {
@Override
public void move() {
super.drive();
}
}
위의코드에서 car, plane 클래스 모두 move()라는 메소드를 가지고 있다면, 어떤 메소드가 사용될 지 모호하다. 이 다중 상속의 모호성 때문에 자바에서는 다중 상속을 금지한다.
하지만, 인터페이스는 아래와 같이 여러개의 인터페이스를 구현할 수 있다.
public class ExamInterface {
/**
* 인터페이스는 추상클래스의 일종이지만 보다 더 극단적인경우입니다.
* 추상메서드로만 구성되며 abstract와다르게 메서드만 정의가 가능합니다.
* 공동 작업을 할때 메서드의 표준화를 시키기 위하여 많이 사용되며,
* 서로 다른 클래스를 연결할 때도 사용됩니다.
*/
public static void main(String[] ar) {
Door door = new Door();
door.open();
door.close();
door.Red();
door.Blue();
Bottle bottle = new Bottle();
bottle.open();
bottle.close();
}
}
interface OpenCloseIf {
public void open();
public void close();
}
interface PaintIf {
public void Red();
public void Blue();
}
/**
* Interface 는 implements 로 상속받으며
* extends 상속과는 다르게 다중 상속이 가능합니다.
*/
class Door implements OpenCloseIf , PaintIf {
@Override
public void open() {
// TODO Auto-generated method stub
System.out.println("Door Open");
}
@Override
public void close() {
// TODO Auto-generated method stub
System.out.println("Door Close");
}
@Override
public void Red() {
// TODO Auto-generated method stub
System.out.println("Paint the door red");
}
@Override
public void Blue() {
// TODO Auto-generated method stub
System.out.println("Paint the door blue");
}
}
class Bottle implements OpenCloseIf {
@Override
public void open() {
// TODO Auto-generated method stub
System.out.println("Bottle Open");
}
@Override
public void close() {
// TODO Auto-generated method stub
System.out.println("Bottle Close");
}
}
참고
[JAVA] 추상클래스와 인터페이스(abstract class & interface)
[JAVA] 추상클래스와 인터페이스의 공통점과 차이점
[JAVA] abstract와 interface의 차이점
[JAVA] Interface vs Abstract Class
[초급 JAVA]자바 interface 와 abstract 예제로 이해하기