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

kai6666·2022년 5월 16일
6

TIL. Java

목록 보기
12/21
post-custom-banner

이미지출처

추상화

추상화는 클래스들의 공통적인 요소를 뽑아서 상위 클래스를 만들어내는 것이다. 반드시 상위 클래스일 필요는 없어서, 공통적인 속성과 기능을 정의한 하위 클래스를 생성할 수도 있다. 한 마디로 추상화는 공통적인 속성과 기능을 정의함으로써 코드의 중복을 줄이고, 클래스 간 관계를 효과적으로 설정하고, 유지/보수를 용이하게 하는 것이다. 자바에서는 추상 클래스 인터페이스라는 문법 요소를 통해 추상화를 구현한다.

💁‍♀️ abstract 제어자
abstract는 주로 클래스와 메서드에 붙이는 키워드인데, 이것을 붙이면 자동으로 '추상 클래스'와 '추상 메서드'가 된다. abstract는 '추상적인'이라는 사전적인 의미가 있지만, 핵심은 '미완성'이라는 개념에 있다. abstract class 클래스명 { ... }와 같이 클래스 선언부가 작성되어 있으면 이것은 미완성된 추상 클래스이므로 상속을 통해 내부의 추상 메서드를 구현해줘야한다는 점을 알 수 있다.
(추상 메서드가 없더라도 키워드를 붙여서 추상 클래스로 지정할 수 있다. 다만 메서드 바디가 완성 되기 전까지는 이를 기반으로 한 인스턴스 생성이 불가하다.)

추상 클래스 (abstract class)

추상 클래스는 한 마디로 미완성 설계도이다. 미완성이기 때문에 이를 기반으로 인스턴스를 생성할 수 없다. 오직 상속을 통해 하위 클래스에서만 완성될 수 있다. 클래스 역할을 못하는 추상 클래스가 필요한 이유는 이것이 새로운 클래스를 작성하는데 유용한 바탕이 되어주기 때문이다. 무에서부터 클래스를 만드는 것보다는, 추상 클래스라는 최소한의 틀에서 확장시키는 것이 편리하기도 하고 설계에 있어 유연함을 가져다준다.


추상 메서드 (abstract method)

추상 메서드는 구현부가 없이 선언부만 있는 메서드이다. 추상 클래스와 마찬가지로 설계만 하고 구체적인 내용을 작성하지 않아 미완성 메서드이다.

abstract class Dog {
	abstract void sleep(); // 추상 메서드 
    abstract void bark(); // 추상 메서드
}
class Poodle extends Dog {
	void sleep(){...}; // 추상 메서드 구현
}
abstract class Pome extends Dog {
	void bark(){...}; // 추상 메서드 구현
}

추상 클래스 속 추상 메서드의 예시이다. 추상 메서드는 구현부가 없으므로 {} 대신 끝을 표시해주는 의미로 ;를 적어준다. 추상 메서드의 구현은 하위 클래스로 상속하여 실행할 수 있는데, 이때 사용하게 되는 것이 '오버라이딩'이다. 오버라이딩을 통해 메서드를 완성시키고, 이렇게 완성된 클래스로 해당 인스턴스를 생성할 수 있다.

인터페이스 (Interface)

인터페이스는 일종의 추상 클래스이다. 추상 클래스와 다른 점이 있다면 더 높은 추상화 정도를 가지고 있어서 바디가 있는 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다는 점이다.

public interface Dog {
	public static final int age = 5;
    final int weight = 10; // public static 생략
    static int registernum = 49; // public & final 생략
    
    public abstract String getDogInfo();
    	void info()
 }

인터페이스는 interface 키워드를 사용해 만든다. 또한 예시를 보면 알 수 있듯이 구현부가 완성되지 않은 추상 메서드와 상수로만 이루어져있다. 일반 클래스와 다르게 내부의 필드가 public static final로 정의되어있다. 이러한 요소가 인터페이스의 필드와 메서드에 내포되어 있기 때문에 생략해도 괜찮다. 다만 상수로 정의하는 경우네는 public static final로, 메서드로 정의할 때는 public abstract로 정의해야지만 일부 또는 전부 생략할 수 있다.

💁‍♀️ final 키워드
'최종'이라는 뜻을 가진 final 키워드는 필드, 지역 변수, 클래스 앞에 위치할 수 있다. 클래스 앞에 있을 때는 변경∙확장∙상속 불가, 메서드 앞에 있을 때는 오버라이딩 불가, 변수 앞에 있을 때는 값 변경이 불가하다.

final class Final {
	final int a = 100;
   
   final void run() {
   	final int localVar = x;
       return x;
    }
}

코드로 살펴보면 위와 같다. Final 클래스는 변경∙확장∙상속이 안 되고, int a는 변경할 수 없고, run() 메서드는 오버라이딩이 불가하다.

interface Dog { ... }
interface Cat { ... }
interface FurryAnimals extends Dog, Cat { ... }

다시 인터페이스로 돌아와서, 인터페이스는 인터페이스로부터만 상속 받을 수 있다. 자바에서 불가한 다중상속이 인터페이스에서는 가능해서 여러 개의 인터페이스로부터 상속 받는 것도 가능하다. 참고로 Object 클래스와 같은 최고 클래스는 없다. 클래스 상속처럼 하위 인터페이스는 상속 받은 상위 인터페이스의 멤버를 모두 상속 받는다.

class 클래스명 implements 인터페이스명 { 추상메서드 구현 }

인터페이스는 구현시 implements 키워드를 사용한다. 만약 구현하는 인터페이스 메서드 중 일부만 구현한다면, abstract를 붙여서 추상클래스로 선언해야 한다.

abstract class 클래스명 implements 인터페이스명 { (메서드) { ... } }

인터페이스 활용 코드

인터페이스와 다형성을 활용해서 선생님이 학생들에게 각자 다른 숙제를 내주는 상황을 코드로 짜보았다.

public interface Student {
    String getHomeWork();
}

class StudentA implements Student {
    public String getHomeWork() {
        return "two pages of essay";
    }
}
class StudentB implements Student {
    public String getHomeWork() {
        return "ten math questions";
    }
}

먼저 Student라는 인터페이스를 만들어 임의의 학생 두 명을 위한 클래스를 Student로부터 implements했다.

public class Teacher {
    public void giveHomeWork(Student student) {
        System.out.println("Assignment of the day : " + student.getHomeWork());
    }
}

이후 Teacher 클래스를 작성해 매개변수로 Student 타입이 입력될 수 있게끔 만들어주었다.

public class InterfacePractice {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Student studentA = new StudentA();
        Student studentB = new StudentB();

        teacher.giveHomeWork(studentA);
        teacher.giveHomeWork(studentB);

    }
}
// 출력:
// Assignment of the day : two pages of essay
//Assignment of the day : ten math questions

마지막으로 InterfacePractice 클래스에서 테스트를 해보면 선생님이 두 학생에게 각자 다른 숙제를 내주는 출력값이 나오는 것을 확인할 수 있었다.


profile
성장 아카이브
post-custom-banner

0개의 댓글