728x90
🤚 들어가기 전에!
추상 : 여러가지 사물이나 개념에 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용
추상화 : 클래스 간의 공통점을 찾아내서 공통의 부모를 설계하는 작업
구체화 : 상속을 통해 클래스를 설계, 확장하는 작업
추상 메서드 (abstract method)
// 일반 메서드
public void testMethod() { // 선언부
...
// 구현부
...
}
메서드(method)는 선언부와 구현부로 구성되어 있다
public void abstractMethod(); // 추상메서드
이 때 추상 메서드란 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨둔 것이다
실제 내용은 상속받는 클래스에서 구현하도록 비워둔 것이다
따라서 추상 메서드는 상속 받는 클래스에 따라 달라질 수 있다
추상 메서드 키워드 'abstract'를 앞에 붙여주고, 구현부가 위치할 {} 대신 마침을 의미하는 ; 를 작성한다
추상 메서드를 선언하는 이유
- 설계자가 특정 메서드를 각 클래스 별로 재구현을 원하지만 부모 클래스에서 일반 메서드로 구현하면 자식 클래스에서 구현을 하지 않는 경우가 발생할 수 있다
- 이런 메서드를 추상 메서드로 선언하면 자식 클래스는 재구현을 강요받는다
추상 클래스
- 클래스 내 추상 메서드가 하나 이상 포함되거나, 클래스 자체가 abstract로 정의된 경우
- 추상 메서드가 하나라도 포함되었다면 클래스 명 앞에 abstract를 붙여야 오류가 나지 않는다
- 추상 클래스 또한 클래스의 한 종류이기 때문에 자식 클래스에서 추상 클래스를 상속 받아 사용할 수 있고, 추상 클래스에서 추상 클래스를 상속 받아서도 사용할 수 있다
- 자식 클래스는 일반 혹은 추상 클래스 중 한 개만 상속이 가능하다 -> 다중 상속 X
- 추상 클래스를 상속받을 때는 extends 키워드를 사용한다
- 추상 클래스는 추상 메소드를 사용할 수 있고, 자식 클래스에서 추상 메서드의 구현을 강제하도록 한다
- 추상 클래스를 상속 받은 자식 클래스에서 추상 메서드 구현을 안하면 오류가 발생한다
- 따라서 추상 클래스를 '미완성 설계도'라고도 표현한다
- 추상 클래스는 구현이 되지 않은 불완전한 메서드가 포함되어 있기 때문에 객체로 생성되지 않는다
추상 클래스 규칙
abstract class 클래스이름 {
...
public abstract void 메서드이름();
}
- 추상 클래스는 키워드 abstract 를 붙여 표현한다
- 추상 클래스는 반드시 하나 이상의 추상 메서드를 가지며, new 키워드를 통한 객체 생성이 불가능하다
- 슈퍼 클래스(Super class)로 사용할 수 있으며, 추상 메서드를 사용하기 위해 반드시 해당 메서드를 재정의해야 한다
- 추상 메서드를 포함하지 않는 클래스에서도 abstract를 붙여서 추상 클래스로 지정할 수 있다
- 메소드에 abstract를 사용할 경우 interface의 메소드와 같이 구현 부분은 없다
- abstract로 선언한 메소드를 자식 클래스에서 반드시 구현해야 한다 (오버라이딩)
- 이는 자식 클래스에서 추상 메서드를 반드시 구현하도록 강제하는 것이다
- 추상 클래스를 상속하는 집합 간에는 연관관계가 있다
- 다중 상속이 불가능하다
public abstract class 클래스이름{
public abstract void 메서드이름();
}
추상 클래스는 기본적으로 위와 같이 작성한다
package interface_abstract;
public class main{
public static void main(String[] args) {
//만약 추상클래스를 new연산자로 생성하려면 에러가 발생
creature c = new creature();//Cannot instantiate the type creature 오류 발생
}
}
상속을 위한 클래스이기 때문에 필드에 따로 객체를 생성할 수 없다
package interface_abstract;
public abstract class creature {
private String name;
private String home;
public creature(String name, String home) {
this.name = name;
this.home = home;
}
public abstract void eat();//추상메서드
public abstract void walk();//추상메서드
@Override
public String toString() {
return this.name + "은(는) " + this.home + "에 삽니다.";
}
}
인터페이스(Interface)
- 인터페이스는 모든 메서드가 추상 메서드인 경우를 말한다
- 인터페이스는 추상 메서드보다 한 단계 더 추상화된 메서드라고 볼 수 있다
- 이는 추상 메서드와 상수로만 이루어져 있기 때문에 로직을 작성할 수 없다
- 인터페이스는 추상클래스와 달리 다중 상속(구현)이 가능하다
- 인터페이스를 상속받을 때는 implements 키워드를 사용한다
- 인터페이스에 적는 모든 메서드들은 추상 메서드로 간주되기 때문에 abstract를 적지 않는다
- 인터페이스는 추상 클래스보다 추상화 정도가 높아, 추상 클래스와 달리 몸통운 갖춘 일반 메서드, 멤버 변수를 구성원으로 가질 수 없다
- 따라서 추상 클래스가 '미완성 설계도'라면 인터페이스는 구현된 것이 아무것도 없는 밑그림만 그려진 '기본 설계도'이다
인터페이스 규칙
interface 인터페이스이름 {
public static final 상수이름 = 값;
public abstract void 메서드이름();
}
- 추상 클래스처럼 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는, 다른 클래스를 작성하는데 도움을 줄 목적으로 작성된다
- 일반 메서드 또는 멤버 변수를 구성원으로 가질 수 없다
- 모든 멤버 변수는 public static final이어야 하며, 이를 생략할 수 있다
- 모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있다
- 인터페이스는 구현 객체가 같은 동작을 보장한다는 것이 목적이다
- 단, JDK1.8(Java 8) 부터 static 메서드와 default 메서드를 사용할 수 있다
- 다중 상속이 가능하다
- 인터페이스를 상속하는 집합 간에는 연관관계가 없어도 가능하다
💡 public static final을 사용하는 이유
1. 구현 객체의 같은 동작을 보장하기 위한 목적
2. 인터페이스 변수는 스스로 초기화 될 권한이 없다
아무 인스턴스도 존재하지 않는 시점이기 때문이다
📌추상 클래스 vs 인터페이스
1. 사용의도 관점
- 추상 클래스는 "~이다.", "is kind of (~의 한 종류)"
- 인터페이스는 "~을 할 수 있는", "is able to (~할 수 있는)"
- 이는 다중 상속의 가능 여부에 따라 용도를 정한 것이다
- 즉, 인터페이스는 implements 키워드를 통해 인터페이스에 정의된 메소드를 각 클래스의 목적에 맞게 기능을 구현하는 느낌이고, 추상클래스는 extends 키워드를 통해 자신의 기능들을 하위 클래스로 확장시키는 느낌이다
2. 공통된 기능 사용 여부
- 만약 모든 클래스가 인터페이스를 사용해서 기본 틀을 구성한다면, 공통으로 필요한 기능들도 모든 클래스에서 오버라이딩하여 재정의해야 하는 번거로움이 있다
- 그러나 추상 클래스를 사용한다면 공통 기능을 추상 클래스 내에서 일반 메서드를 작성하여 자식 클래스에서 사용하면 된다
3. 속도
- 추상 클래스가 인터페이스보다 속도가 빠르다
- 인터페이스는 관련 메소드들을 찾기 위해 부가적인 일들을 더 처리하기 때문이다
🤔 보다 더 디테일한 차이점 정리
추상 클래스
- 추상 메소드가 반드시 한 개 이상 포함
- 일반 메소드, 일반 변수, 생성자 포함 가능
- 추상클래스 간 상속 가능 -> 오버라이딩하지 않고 그대로 둘 수 있다
- 인스턴스를 만들 수 없고 상속받은 클래스를 통해 인스턴스화 가능
- 접근 지정자는 어떤 것이든 가능
- extends를 통해 상속 -> 궁극적인 목적은 상속하기 위함이다
- 필요에 의해서 일반 메소드와 더불어 추상화를 하고자 할 때 사용
인터페이스
- 클래스가 아니다
- 비어있는 추상 메소드만 포함
- 메소드에 final을 붙일 수 없고, 변수는 모두 static이어야 함
- 일반 변수와 일반 메소드, 생성자 포함 불가능
- 인스턴스를 만들 수 없고, 상속받은 클래스를 통해 인스턴스화 가능
- 접근지정자는 없거나 public, abstract만 가능
- 인터페이스간 상속 가능 -> 내용이 없는 메소드를 상속받는 것이고, 구현이 아니므로 extends 사용!
- 클래스가 아니기 때문에 상속 시 implements를 통해 구현
- 인터페이스는 메소드들의 집합이다
- 변수 앞에 static final이나 메소드 앞에 abstract 명령어를 안써도 자동으로 인식한다
- 사실상 메소드 선언만 하는 빈껍데기라서 사용 빈도가 높다
💡 추상클래스와 인터페이스를 사용해야 할 상황
추상클래스
- 같은 조상(부모) 클래스를 상속하는데 기능까지 완벽히 똑같은 기능이 필요한 경우 (공통 기능)
- 다른 일반 메소드나 필드가 필요한 경우
- 같은 종류나 행동들을 구현할 것이 많은 경우
- 상속에 대한 계층구조를 명확히 표현하고자 하는 경우
- 관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우
- 추상클래스를 상속받을 클래스들이 공통으로 갖는 메소드/필드가 많은 경우
- public 이외의 접근자(protected, private) 선언이 필요한 경우
- non-static, non-final 필드 선언이 필요한 경우 (각 인스턴스에서 상태 변경을 위한 메소드가 필요한 경우)
인터페이스
- 다른 조상(부모) 클래스를 상속하는데 같은 기능이 필요한 경우
- 디자인을 구성하는 요소들이 자주 바뀌는 경우
- 클래스 전체가 아닌 메소드들만 쓰고 싶은 경우
- 서로 관련성이 없는 클래스들이 인터페이스를 구현하는 경우
- 특정 데이터 타입의 행동을 명시하고 싶은데, 어디서 그 행동이 구현되는지 신경쓰지 않는 경우
- 다중 상속을 허용하고 싶은 경우
💡 더 참고해보면 좋은 내용!
https://loosie.tistory.com/707
참고)
https://haenny.tistory.com/162
https://myjamong.tistory.com/150
https://devlog-wjdrbs96.tistory.com/370
https://jroomstudio.tistory.com/7
728x90
'야미스터디 > Java' 카테고리의 다른 글
[Java] Java 컴파일 과정 📌 (0) | 2022.09.04 |
---|---|
[Java] 스네이크, 카멜, 파스칼 케이스 📌 (0) | 2022.09.03 |
[Java] 오버라이딩 vs 오버로딩 📌 (0) | 2022.08.17 |
[Java] Mutable vs Immutable 📌 (0) | 2022.08.07 |
[Java] 접근 제한자 / 생성자 / SOLID 📌 (0) | 2022.08.06 |
댓글