[Java] 추상 클래스와 인터페이스

peace w·2023년 11월 28일
0

Java

목록 보기
6/6

추상 클래스와 인터페이스

개념적으로나 사용하는 목적에 있어서나 추상 클래스와 인터페이스는 비슷한 부분이 많다. 그러나 분명 차이점도 존재한다. 어떤 상황에 사용해야 적절한지 정확히 정리하고자 한다.

추상 클래스란?

추상 메서드를 선언해 놓고, 상속을 통해서 자식 클래스에서 메서드를 완성하도록 유도하는 클래스이다. 하나 이상의 추상 메서드를 가지며, 추상 메서드를 선언했다면 자식 클래스는 해당 메서드를 반드시 재정의해서 구현하도록 강제된다.

  • 상속받을 객체들의 공통적인 부분을 추출해 어느정도 규격을 잡아서 추상화시켜 놓은 것.
  • 추상 클래스는 상속을 위한 클래스이므로 객체를 생성할 수 없다.
  • JAVA는 다중 상속을 지원하지 않기 때문에 여러 개의 추상 클래스를 상속할 수 없다.
  • 클래스나 메서드 앞에 abstract 키워드를 붙여 해당 클래스와 메서드가 추상 클래스, 메서드임을 나타낸다.
  • extends 키워드를 사용하여 상속받게 된다. 자신의 기능들을 하위 클래스로 확장시키는 것과 비슷하다. -> 부모 클래스가 가진 기능들을 구현해야 할 경우 사용한다. (클래스끼리의 명확한 계층구조가 있다.)

추상 클래스의 사용 목적

  • 공통된 필드와 메서드를 통일할 목적
    추상클래스에서 미리 정의한 필드와 메서드가 있다면, 실체클래스는 추상클래스의 필드와 메서드명을 변경할 수 없고 무조건 해당 명명으로 구현해야한다. 따라서, 필드와 메서드 이름을 통일하여 유지보수성을 높이고 통일성을 유지할 수 있다.

추상 클래스 예시

abstract class Animal {
	abstract void cry();
}

Animal 추상 클래스를 선언했다. Animal 클래스는 cry() 추상 메서드를 가진다.

class Dog extends Animal {
	void cry() {
    	System.out.println("멍멍!");
    }
}

Animal 추상 클래스를 상속받은 Dog 클래스에서 cry() 메서드를 재정의한다.

class Cat extends Animal {
	void cry() {
    	System.out.println("야옹~~");
    }
}

Animal 추상 클래스를 상속받은 Cat 클래스에서 cry() 메서드를 재정의한다.

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        
        dog.cry(); // 멍멍!
        cat.cry(); // 야옹~~
    }
}

인터페이스란?

오직 추상 메서드와 상수(static final)만을 가지고 있는 것을 인터페이스라고 한다. 추상 클래스와 마찬가지로 인터페이스 또한 인터페이스에 선언되어있는 추상 메서드를 implements 하는 클래스에서 반드시 구현하도록 강제한다.

  • 인터페이스의 모든 멤버 변수는 public static final 이어야 하며, 이를 생략할 수 있다.
  • 인터페이스의 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다. (Java 8 부터는 staticdefault 메서드를 사용할 수 있다.)
  • interface 키워드를 사용하여 정의할 수 있다.
  • 추상 클래스와 마찬가지로 자신이 직접 객체를 생성할 수 없다.
  • 상속 키워드로는 implements를 사용한다.
  • 인터페이스의 경우, 모든 멤버 메서드가 추상 메서드이기 때문에 동일한 이름의 메서드가 있어도 상속받는 클래스에서 재정의(오버라이딩)해서 사용하기 때문에 같은 메서드 호출의 모호성을 방지할 수 있다. 때문에 다중 상속이 가능하다.
  • 인터페이스끼리도 상속을 통해서 확장시켜나갈 수 있다. 인터페이스끼리 상속을 할 때는 클래스와 마찬가지로 extends 키워드를 사용한다.

인터페이스의 사용 목적

  • 클래스 간의 결합도(코드 종속성을) 낮춘 효율적인 프로그래밍 작성 가능
    메서드 간의 결합도 = 코드 종속성.
    인터페이스를 활용하면 한 메서드를 수정했을 때, 다른 메서드도 수정해야하는 상황을 줄여줄 수 있다는 뜻이다. 인터페이스를 사용하면 많은 개발자가 함께 협업을 할 때 동일한 기능을 보장하도록 강제할 수 있다.

인터페이스 예시

public interface Animal {
    public static final String name = "동물";
    
    public abstract void move();
    public abstract void eat();
    public abstract void cry();
}

Animal 은 인터페이스므로 static final로 생성할 수 있는 상수와 abstract로 생성할 수 있는 추상 메서드만 가질 수 있다.

public class Dog implements Animal{
    
    @Override
    public void move() {
        System.out.println("슥슥~~");
    }
    
    @Override
    public void cry() {
        System.out.println("멍멍!");
    }
}

Animal 인터페이스를 implements 키워드로 구현한 Dog 클래스에서 인터페이스의 추상 메서드들을 모두 재정의한다.

public class Cat implements Animal{

    @Override
    public void move() {
        System.out.println("사뿐사뿐~~");
    }
    
    @Override
    public void cry() {
        System.out.println("야옹~~");
    }
}

Cat 클래스도 마찬가지로 인터페이스의 추상 메서드들을 모두 재정의한다.

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        
        dog.move(); // 슥슥~~
        dog.cry(); // 멍멍!
        
        cat.move(); // 사뿐사뿐~~
        cat.cry(); // 야옹~~
    }
}

추상 클래스와 인터페이스의 공통점

종합해보자면, 둘다 내용에 대한 구현이 없는 선언부만 가진 추상 메서드를 사용하며, 독립적으로 객체를 생성할 수 없다. 그리고, 상속(구현)하도록 강제하기 위한 기능을 한다는 점도 같다.

abstract class Animal {
	// 숨쉬기(일반 메서드(선언부 + 구현부 존재)
	void breath() {
		System.out.println("숨쉬기");
	}

	// 울음소리(추상 메서드(선언부만 존재)
	abstract void cry();
}

interface Flyable {
	// 날기(추상 메서드(선언부만 존재)
	void fly();
}
Animal animal = new Animal(); // ERROR, 'Animal' is abstract; cannot be instantiated
Flyable flyable = new Flyable(); // ERROR, 'Flyable' is abstract; cannot be instantiated
// 추상적이므로 인스턴스화 할 수 없다는 에러 발생

공통점

구분 추상 클래스와 인터페이스
객체 생성 객체를 생성(인스턴스화)할 수 없다.
추상 메서드 추상 메서드를 포함한다.
기능적 목적 상속받는 클래스에서는 추상 메서드를 반드시 재정의하여 구현해야 한다.

추상 클래스와 인터페이스의 차이점

추상 클래스는 extends, 인터페이스는 implements를 상속 키워드로 사용한다.
키워드의 뜻에서 볼 수 있는 차이점을 생각해보자면
추상 클래스는 자신의 기능들을 하위로 확장시키는 기능 확장 느낌에 가깝고,
인터페이스는 인터페이스에 정의된 메서드들을 각 클래스의 목적에 맞게 동일한 기능으로 구현, 즉 실행하는 기능 구현에 중점을 둔 느낌이다.

상속해준 부모클래스의 면에서 차이점을 생각해보자.

추상 클래스 : 자식 클래스 is kind of 부모 클래스 
인터페이스 : 자식 클래스 is able to 부모 인터페이스 

추상클래스는 상속할 객체들의 공통점을 찾아 추상화시켜놓은 것이기 때문에, 상속 관계를 타고 올라가면 같은 부모 클래스를 상속하게 된다. 즉, 부모 클래스가 가진 기능들을 구현해야 하는 경우에 사용한다.

반면 인터페이스는 상속 관계를 타고 올라갔을 때, 다른 부모 클래스를 상속하더라도 같은 기능이 필요한 경우에 사용된다.

차이점

구분 추상 클래스 인터페이스
개념적 목적 상속 받아서 기능을 확장시키는데 목적 구현 객체의 동일한 실행 기능을 보장하기 위한 목적
클래스 클래스다.(abstract class) 클래스가 아니다.(interface)
일반 메서드 일반 메서드 정의가 가능 일반 메서드 정의 불가능
(Java8 이후 static, default 메서드 정의 가능)
멤버 변수 클래스와 동일하게 변수 선언 및 사용 가능 상수만 사용 가능
상속 키워드 extends implements
다중 상속 불가능 가능

참고

[JAVA] 자바 추상클래스란?
[JAVA] 추상클래스와 인터페이스의 차이
[간단정리] JAVA - 추상클래스, 인터페이스 특징 및 차이점 확실히 기억하기

profile
더 성장하자.

0개의 댓글