# 추상 클래스 - 구체적이지 않은 클래스 - 미완성 설계도 - '추상화'를 클래스에 접목시켜, 추상화의 기능을 강제하는 클래스 - 특징 - 공통 멤버의 통합으로 중복 제거 - 구현의 강제성을 통한 기능 보장 - 설계와 구현의 분리 ## 추상 클래스 기본 문법 ![](https://i.imgur.com/svVKU1K.png) - 자바에서는 `abstract` 키워드를 클래스명과 메서드명 옆에 붙임으로서 컴파일러에게 추상 클래스와 추상 메서드임을 알려주게 된다. - 추상 메서드 : 구현 내용은 없고 이름만 껍데기만 있는 메서드라고 - 일반적으로 하나 이상의 추상 메소드를 포함하는 클래스를 가리켜 추상 클래스라고 정의하곤 한다. - 추상 클래스 안의 메서드를 미완성으로 남겨놓는 이유는 추상 클래스를 상속받는 자식 클래스의 주제에 따라서 상속 받는 메서드의 내용이 달라질 수 있기 때문 - 상속을 통해서 자식 클래스에서 완성하도록 유도 ## 추상 클래스 생성자 - 추상 클래스는 클래스의 일종이라고 하지만 new 생성자를 통해 인스턴스 객체로 직접 만들 수 없다 > ```java > abstract class Animal { ... } > > Animal a = new Animal(); // ERROR !! - 추상 클래스는 인스턴스를 직접 바로 생성할 수 없음.**** > ``` - 하지만, 추상 클래스의 생성자를 전혀 이용 못하는 것은 아니다. 직접적인 인스턴스화가 불가능 하다 뿐이지, super() 메소드를 이용해 추상 클래스 생성자 호출이 가능하다. > ```java > // 추상 클래스 > abstract class Shape { > public String type; > > // 추상 클래스 생성자 > public Shape(String type) { > this.type = type; > } > > // 추상 메서드 > public abstract void draw(); > } > > class Figure extends Shape { > public String name; > > public Figure(String type1, String type2) { > super(type1); // 부모 추상 클래스 생성자 호출 > name = type2; > } > > @Override > public void draw() { ... } // 추상 메서드 구현 > } > > public class main { > public static void main(String[] args) { > Figure f = new Figure("polygon", "square"); > f.name; // "square" > f.type; // "polygon" - 부모(추상) 클래스의 멤버를 추상 클래스 생성자를 호출하는 super()을 통해 초기화 > } > } > ``` --- # 인터페이스 - 구현이 어떻든 깊이 학습할 필요없이 원하는 기능을 수행하고 결과 값을 제대로 받게 해주는 간편한 상호작용 기능 - 프레임워크의 내부 구성 학습 없이, 그저 지원해주는 메서드를 이용하여 간편하게 프로젝트를 개발할 수 있게 해준다 ## 일상 생활에서 인터페이스 - 문 손잡이: 문을 쉽게 열고 닫을 수 있게 해주는 인터페이스 - 전등 스위치: 조명을 켜고 끌 수 있게 해주는 인터페이스 - 자동차 대시보드: 차량의 속도, 연료 및 기타 중요한 데이터에 대한 정보를 표시하는 복잡한 인터페이스 - 스마트폰 화면: 터치 스크린은 다양한 앱과 기능에 액세스할 수 있는 직관적인 인터페이스 - 키보드/마우스: 컴퓨터와 상호작용을 하기 위한 인터페이스 - 텔레비전 리모콘: 채널을 변경하고 볼륨을 조절하고 텔레비전의 다른 기능을 제어할 수 있게 해주는 인터페이스 ## 자바에서의 인터페이스 ![](https://i.imgur.com/WdLvdAe.png) - 자바에서 클래스들이 구현해야하는 동작을 지정하는 용도로 사용되는 추상 자료형 - 자바에서 다중상속을 간접적으로 가능하게 해준다 - 자바에서는 기본적으로는 다중상속을 지원하지 않는다 - 인터페이스는 클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용하는 것에 초점이 맞춰져있다. - 상속받은 인터페이스의 추상 메서드를 구현하지 않으면 컴파일 오류 발생 - 추상 클래스 상속과 전혀 다르지 않다 - 미구현으로 인한 컴파일 오류를 발생시켜 실수를 방지해준다 - 메서드 이름 오타 or 부모클래스의 메서드 이름만 바꾸고 자식 클래스는 손대지 않는 경우 - Java에서는 `@Override`라는 어노테이션을 제공한다 - 이 어노테이션을 메서드 위에 사용하면 상속받은 메서드를 구현하겠다는 의미 - 만약 부모 클래스에 같은 이름의 메서드가 없으면 오류 발생 - 인터페이스는 `public` 메서드만 가능 - 누구라도 보고 명령할 수 있는 동작 - 인터페이스는 다중 상속이 가능 (클래스 다중상속은 불가능) - 메서드가 중복되더라도 오버라이딩되지 않기 때문에 실체가 겹칠 위험이 없음 - 아무리 복잡하게 상속 구조를 해도 구현은 하나 뿐 - 인터페이스는 두 실체가 중복되어도 상속받은 클래스가 구현만 제공하면 됨 - 단 반환형만 다르면 컴파일 오류가 난다 - 두 함수를 다 구현할 방법이 없기 때문에 - 반환형만 다른 경우는 올바른 함수 오버로딩이 아님 - **인터페이스는 다중 상속의 해결법** > 인터페이스는 특수한 형태의 클래스다 > - 어떤 상태도 없음 > - 동작의 구현도 없음 > - 동작의 시그내처만 있음 > - 이런 특징 때문에 클래스와는 약간 다른 규칙을 따른다 ### 인터페이스 문법 ![](https://i.imgur.com/jc9fZ1M.png) - 인터페이스를 작성하는 것은 추상 클래스를 작성하는 것과 같다고 보면 된다. (추상 메서드 집합) - `class` 대신 `interface`라는 키워드를 이용하여 선언할 수 있으며 메소드 시그니처와 상수선언만을 포함할 수 있다 - 인터페이스의 모든 상수는 `public static final`이며, 모든 메서드는 `public abstract` 이다. - 인터페이스에 선언 시 편의상 생략이 가능하다. - `default` 키워드를 사용하여 구현부가 있는 메서드를 만들어줄 수 있다. - 구현체에게 수정 없이 광역으로 함수를 만들어주고 싶을 때 사용된다 - `default` 메서드가 다중 상속 문제로 인해 충돌 되는 경우 오버라이딩을 해야 한다 ### 인터페이스 사용 예시 ```java interface Animal { void walk(); void run(); void breed(); default void eat() { ... } } // Animal 인터페이스를 일부만 구현하는 포유류 추상 클래스 abstract class Mammalia implements Animal { public void walk() { ... } public void run() { ... } // public void breed() 는 자식 클래스에서 구체적으로 구현하도록 일부로 구현하지 않음 (추상 메서드로 처리) } class Lion extends Mammalia { @Override public void breed() { ... } } ``` --- ### 인터페이스 다중 상속의 예시 > ![](https://i.imgur.com/Mwb2dHz.png) --- > ![](https://i.imgur.com/55ILYaV.png) --- ### 자바 버전별 인터페이스 기능 ![](https://i.imgur.com/3aozynW.png) --- ### 컬렉션에서의 인터페이스 활용 예시 ![](https://i.imgur.com/unnp6Lz.png) # 추상클래스 vs 인터페이스 - 인터페이스나 추상클래스나 둘이 똑같이 추상 메소드를 통해 상속/구현을 통한 메소드 강제 구현 규칙을 가지는 추상화 클래스이다. - 다만 이 둘은 각각 고유의 몇몇 특징들을 가지고 있는데, 이러한 특징으로 인해 각각 사용처가 갈리게 된다. 또한 기능적인 부분 뿐만 아니라 인터페이스와 추상클래스가 내포하고있는 논리적인 의미로서도 사용처가 나뉜다. ## 추상클래스를 사용하는 경우 - 상속 받을 클래스들이 공통으로 가지는 메소드와 필드가 많아 **중복 멤버 통합**을 할때 - 멤버에 public 이외의 접근자(protected, private) 선언이 필요한 경우 - non-static, non-final 필드 선언이 필요한 경우 (각 인스턴스에서 상태 변경을 위한 메소드가 필요한 경우) - 요구사항과 함께 구현 세부 정보의 일부 기능만 지정했을 때 - 하위 클래스가 오버라이드하여 재정의하는 기능들을 공유하기 위한 상속 개념을 사용할 때 - 추상 클래스는 이를 상속할 각 객체들의 공통점을 찾아 추상화시켜 놓은 것으로, 상속 관계를 타고 올라갔을 때 같은 부모 클래스를 상속하며 부모 클래스가 가진 기능들을 구현해야할 경우 사용한다. ## 인터페이스를 사용하는 경우 - 어플리케이션의 기능을 정의해야 하지만 그 구현 방식이나 대상에 대해 추상화 할 때 - **서로 관련성이 없는 클래스**들을 묶어 주고 싶을때 (형제 관계) - **다중 상속**을 통한 추상화 설계를 해야할때 - 특정 데이터 타입의 행동을 명시하고 싶은데, 어디서 그 행동이 구현되는지는 신경쓰지 않는 경우 - 클래스와 별도로 **구현 객체가 같은 동작을 한다는 것을 보장**하기 위해 사용 ## 인터페이스 + 추상클래스를 사용하는 경우 ![](https://i.imgur.com/yFvpNQo.png) - 추상 클래스의 중복 멤버 통합과 인터페이스의 다중 상속 기능을 동시에 사용하기 위해서 종종 같이 사용되곤 한다 --- ### 구체클래스 vs 인터페이스 | 구체 클래스 | 인터페이스 | | -------------------------------- | --------------------------------- | | 상태와 동작을 모두 포함 | 동작에 대한 설명만 포함 | | 동작에 다양한 접근권한 부여 가능 | 모든 동작은 public | | 구체클래스로부터 개체 생성 가능 | 인터페이스로부터 개체 생성 불가능 | | 다중 상속의 부모가 될 수 없음 | 다중 상속의 부모가 될 수 있음 | --- ## 과제 **클래스 구조 설계해보기** - `Human`, `Lion`, `Elephant`, `Dolphin`, `Turtle` 5개의 클래스를 만들려고 한다. - 5개 클래스는 모두 `age`, `weight` 정보를 가지고 있다. - 5개 클래스는 모두 `grow()` 메서드를 가지고 있으며, 해당 메서드를 호출 시 `age`가 `1` 증가한다. - 5개 클래스는 모두 `eat()` 메서드를 가지고 있으며, 해당 메서드를 호출 시 `weight`가 `1` 증가한다. - `Human`, `Lion`, `Elephant` 클래스는 `walk()` 메서드를 가지고 있다. - `walk()` 메서드는 `두 발로 걷는다` 또는 `네 발로 걷는다` 라는 메시지를 출력한다. - `Dolphin`, `Turtle` 클래스는 `swim()` 메서드를 가지고 있다. `swim()`메서드를 호출 시 `헤엄!`이라는 메시지를 출력한다. --- ###### tags: `과외(하희영)`