본문 바로가기
  • 비둘기다
  • 비둘기다
  • 비둘기다
코딩/JAVA Basics

[자바 JAVA] 추상클래스와 인터페이스

by parzival56 2022. 12. 6.

차례

1. 추상 클래스

2. 인터페이스의 개념

3. 인터페이스의 구조

4. 인터페이스의 특징들

 

추상 클래스

'추상적이다'라는 것은 구체성이 없이 사실이나 현실에서 멀어져 막연하고 일반적인 것들을 뜻합니다. 이를 자바 언어의 관점에서 해석을 해보자면 그냥 이름만 있는 빈 껍데기만 존재한다는 것입니다. 용어들을 대입해 더욱 자세하게 가보자면 무언가의 역할을 할 클래스를 선언만 하고 그 내부는 실체 없이 비어있다는 것이죠.

 

예를 들어 창업을 하려는 친구가 찾아와서 "야, 나 회사 차릴 거야."라고 말합니다. 그랬더니 내가 "무슨 회사?"라고 물어봅니다. 그러니 친구가 하는 말이 "그건 모르겠고 어쨌든 할 거야."라고 합니다.

추상 클래스란 이러한 상황입니다. 창업하려는 회사가 IT에 대한 건지, 무역에 관한 건지 등 어떠한 구체성도 제시하지 않고 막연히 회사라는 껍데기만 던져준 것이죠. 말 그대로 추상적 abstract 한 상황인 것입니다.

위와 같은 상황을 코드로 나타내본다면 이와 같습니다. 

class 창업한다는 친구 {
	void 창업할 회사 {
    	// 구체성이 드러나지 않아 채울 내용이 없음
    }
}

그러니 이 뜻은 위의 코드에서 메서드에 들어갈 내용을 누군가가 채워줘야 의미가 생긴다는 것입니다. 물론 그냥 이렇게만 써도 컴파일은 되겠지만 클래스가 하는 게 없는데 굳이 쓸 필요가 없는 것이죠. 

그러면 그 누군가는 이 추상 클래스를 상속받아 빈 메서드에 들어갈 내용을 채워줘야합니다. 

 

결과적으로 추상클래스는 실현되기 위해서는 반드시 실체 클래스의 부모 클래스가 되어야 합니다. 즉, 무조건 상속을 받아야 합니다. 이 추상 클래스를 상속받는 자식 클래스들은 반드시 필드와 메서드들을 생성해야 합니다.

 

추상 클래스를 사용하는 이유는 상속 계층에서 자식 멤버의 이름을 통일하기 위하여 사용합니다. 만약, 실체 클래스 설계자가 여러 사람일 경우, 실체 클래스마다 필드와 메서드가 제각기 다른 이름을 가질 수 있기 때문입니다. 

그리고 실체 클래스 설계 규격을 만들고자 할 때 사용합니다. 실체 클래스가 가져야 할 필드와 메서드를 추상 클래스에 미리 정의가 되어야 하고, 실체 클래스는 추상 클래스를 무조건 상속받아 작성해야 하기에 뭔가를 늘리거나 줄일 수 없게 됩니다. 

 

추상의 개념은 클래스에도 적용할 수 있지만 메서드에도 적용할 수 있습니다. 

abstract class 클래스 이름 {
	abstract 반환타입 메서드이름();
}

추상 클래스와 메서드는 위와 같이 선언합니다. 클래스의 경우에는 앞에 abstract만 붙이면 되지만 메서드의 경우는 조금 다릅니다. 추상 메서드는 본체가 없기 때문에 바로 세미콜론을 찍어 끝냅니다. 

추상 클래스는 당연히 다른 패키지들에서도 사용할 수 있기 때문에 public으로 지정할 수 있습니다. 추상 메서드는 public이나 protected로 지정할  수 있습니다. 

추상 클래스는 자식 객체가 부모 생성자 super()를 호출할 수 있으므로 생성자도 포함 가능합니다. 

뭐니 뭐니 해도 가장 중요한 것은 추상 메서드가 존재한다면 이 메서드가 존재하는 클래스를 상속받은 자식은 반드시 이 추상 메서드를 구현해야 합니다. 추상이 아닌 다른 메서드는 안 건드려도 추상 메서드는 반드시 구현해야 합니다.

 

 ※주의※ 추상 클래스 안에는 일반 메서드도 들어갈 수 있지만 일반 클래스에 추상 메서드가 들어갈 수는 없습니다. 

abstract class animal {
    abstract void sound();
    public void move();
}

class dog extends animal {
    @Override 
    void sound() {
    	머시기머시기
    }
    // move 메서드는 추상이 아니니까 채우는건 본인 마음
}

위 코드는 추상 메서드를 오버 라이딩하는 과정입니다. 밑에 dog에서 보여드린 경우가 바로 일반 메서드와 추상 메서드의 차이라고 할 수 있습니다. 

 

인터페이스

인터페이스를 추상 클래스 다음으로 설명하는 이유는 결이 비슷한 개념이기 때문입니다. 

인터페이스 또한 뭔가를 추상화시킨다는 개념을 일맥상통하지만 추상 클래스에서는 일부 원하는 메서드만 추상화를 시켰다면 인터페이스는 안에 넣을 모든 멤버를 추상화시켜야 합니다. 

모든 멤버를 초기화시키는 것이 귀찮지 않냐고 생각하실 수 있지만, 이는 장점이 많은 기능입니다. 

인터페이스는 모든 멤버들을 추상화시키기 때문에 모든 멤버를 다 구현해야 합니다. 그렇기 때문에 인터페이스를 사용하게 되면 통합을 신경 쓰지 않고 다양한 형태의 새로운 클래스를 많이 만들 수 있습니다. 

그리고 자바의 클래스는 다중 상속을 지원하지 않지만 인터페이스는 간접적으로 다중 상속을 구현할 수 있기 때문에 가능한 조합이 훨씬 많습니다. 

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

인터페이스는 파일을 만드실 때 생성하는 곳이 따로 있습니다. 일반적으로 클래스에 들어가서 할 수도 있지만 좀 더 독립적으로 다루고 싶으면 바로 인터페이스를 클릭하셔서 생성하셔도 무관합니다. 

interface 이름 {
    // 상수 필드 -> 모든 멤버 변수는 public static final이며 생략 가능
    
    // abstract 메서드 -> 모든 메소드는 public abstract이며 생략 가능
    
    // default 메서드 
    // static 메서드
    // 디폴트 메소드는 오버라이딩 가능, 정적 메소드는 오버라이딩 불가능
}

인터페이스는 모든 멤버가 추상화되기 때문에 변수의 경우에는 public static final을 메서드는 public abstract를 생략하여 생성됩니다.

주의할 점은 상수 필드는 public static final을 생략하여 선언되기 때문에 반드시 초기값을 대입해줘야 합니다.

static과 final이 모두 들어가기 때문에 더 이상 변경이 불가하기 때문입니다. 그리고 인터페이스는 객체 생성이 불가능하기 때문에 생성자를 가질 필요가 없습니다. 

위에 나오는 메서드 중 default 메서드는 말 그대로 default입니다. abstract나 static이 아니기 때문에 굳이 자식에게서 구현할 필요도 오버 라이딩이 금지되지도 않습니다. 그렇기에 필요시에는 오버 라이딩으로 구현하면 됩니다. 

 

인터페이스는 특이한 상속 키워드를 사용합니다. 클래스끼리는 extends를 사용하였으나 클래스에서 인터페이스를 상속받을 때는 implements를 사용합니다. 단, 인터페이스끼리 상속받을 경우에는 extends를 사용합니다. 

class a extends alphabet{} // alphabet은 클래스
class a implements alphabet{} // alphabet은 인터페이스
interface a extends alphabet{} // alphabet은 인터페이스

아까 말씀드렸다시피 인터페이스는 다중 상속이 가능합니다.

interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 {}

위와 같은 형식으로 쉼표를 이용하여 여러 인터페이스들을 다중 상속받을 수 있습니다. 다만, 클래스는 불가능하죠.

그리고 인터페이스는 객체를 생성할 필요가 없기 때문에 main함수에서 사용하실 때 그냥 인터페이스 이름.멤버 이름으로 사용하시면 됩니다. 

 

Comparable 인터페이스

앞선 단원들에서 compareTo라는 키워드를 보신 적 있으실 텐데 아마 배열끼리 사전 비교를 하여 상수를 반환하는 친구였던 것으로 기억하는데 여기에서는 객체를 비교하기 위한 규격으로 사용되는 인터페이스입니다. 

public interface Comparable{
    int compareTo(Object other);
}
class Circle implements Comparable {
    double radius;
    public Circle(double radius) {
        this.radius = raidus;
    }
    public int compareTo(Object o) {
        Circle c = (Circle) o;
        if (this.raidus > c.radius)
            return 1;
        else if (this.radius == c.radius)
            return 0;
        else
            return -1;
    }
}
public class CircleDemo {
    public static void main(String[] args) {
        Circle c1 = new Circle(5.0);
        Circle c2 = new Circle(6.0);
        if (c1.compareTo(c2) > 0)
            System.out.println(”첫 번째 원이 두 번째 원보다 크다.”);
        else if (c1.compareTo(c2) == 0)
            System.out.println(”두 원의 크기가 같다.”);
        else
            System.out.println(”첫 번째 원이 두 번째 원보다 작다.”);
    }
}

Comparable 또한 인터페이스이긴 하지만 compareTo라는 메서드를 통해 실행되기 때문에 compareTo를 구현해줘야 합니다. compareTo의 역할이라고 한다면 다른 객체보다 크면 양수, 같으면 0, 작으면 음수를 반환하기 때문에 이를 이유로 1, 0, -1로 반환 값을 설정한 것입니다. 

 

인터페이스와 다형성

interface Animal {
    void sound();
}
class Dog implements Animal {
    public void sound() {
        System.out.println(”멍멍~~”);
    }
}
class Cuckoo implements Animal {
    public void sound() {
        System.out.println(”뻐꾹~~”);
    }
}
public class AnimalDemo {
    public static void main(String[] args) {
        Dog d = new Dog();
        Cuckoo c = new Cuckoo();
        makeSound(d);
        makeSound(c);
    }
    static void makeSound(Animal a) {
        a.sound();
    }
}

가장 밑 줄이 중요하다고 할 수 있습니다. Dog와 Cuckoo는 인터페이스를 상속받긴 했지만 클래스입니다. 그러나 마지막 정적 메서드에서 makesound에서 인터페이스를 매개변수로 두어 클래스의 객체인 d와 c가 자동으로 인터페이스로 타입 변환된 것을 확인할 수 있습니다. 

 

이렇게 자바의 새로운 개념 중 하나인 인터페이스와 기초가 되는 추상 클래스에 대해 알아봤습니다. 

'코딩 > JAVA Basics' 카테고리의 다른 글

[자바 JAVA] 자바의 람다식  (0) 2022.12.06
[자바 JAVA] 중첩 클래스  (0) 2022.12.06
[자바 JAVA] 다형성  (0) 2022.12.05
[자바 JAVA] 상속  (0) 2022.12.05
[자바 JAVA] 클래스와 객체  (2) 2022.12.05

댓글