JAVA
1. 추상 클래스와 추상 메서드
추상 메서드(Abstract Method)
다형성을 위해 메서드의 선언은 통일해야 하지만 실제로 구현하는 내용은 자식 클래스마다 달라야 할 때, 부모 클래스의
메서드는 비워두고 자식 클래스에서 오버라이딩하여 구현해낼 수 있습니다.
자바는 이와 같은 경우를 공식 지원하며 방법을 제공하고 있습니다. 선언부만 작성하고 구현부는 작성하지 않고 남겨둔
미완성 메서드를 '추상 메서드'라고 부릅니다.
추상 메서드를 선언할 때는 abstract 키워드를 함께 표기해야 합니다. 또한 메서드 구현부인 중괄호{ } 대추상 메서드를
선언하는 방법은 다음과 같습니다.
[접근 제한자] abstract 반환 타입 메서드 이름(매개변수1, 매개변수2...);
하지만 'abstract 메서드는 반드시 abstract class 안에 정의 되어야 한다'라는 오류가 발생합니다.
이렇게 추상 메서드의 형태를 갖추게 되면 따라야 하는 제약 조건이 있습니다.
- 추상메서드를 1개 이상 선언하면, 그 클래스는 추상 클래스로 선언되어야합니다.
추상 클래스(Abstract Class)
자바에서는 하나 이상의 추상 메서드를 포함하는 클래스를 가리켜 추상 클래스라고 합니다. 추상 클래스는 추상 메서드를
포함하고 있다는 것을 제외하고 일반 클래스와 다르지 않습니다. 추상 클래스에도 생성자가 있으며, 멤버변수와 메서드도
가질 수 있습니다. 추상 클래스를 선언하는 방법은 추상 메서드와 유사합니다.
[접근 제한자] abstract class 클래스이름{
// 필드
// 생성자
// 메서드(추상 메서드 포함)
}
추상 클래스로 선언되는 클래스는 다음과 같은 제약 조건을 가집니다.
- 일반 클래스처럼 독립적으로 생성자를 호출해 객체를 생성할 수 없습니다.
- 자식 클래스의 생성자에서 super()를 통해 추상 클래스의 생성자를 호출하여 부모 객체를 생성한 후 자식 객체를 생성합니다.
추상 메서드가 없는 추상 클래스는 사실 일반 클래스와 다를 것이 없어 보이지만, 직접 부모 클래스 객체를 생성하지 못한다는 큰 특징이 있습니다
추상 클래스가 반드시 추상 메서드를 가져야 하는 것은 아닙니다.
자식 클래스들이 반드시 구현해야 하는 메서드가 있다면, 추상 메서드로 해당 메서드를 부모 클래스(추상 클래스)에
선언해 둘 수 있습니다. 추상 메서드가 선언된 추상 클래스는 다음과 같은 힘을 가집니다.
추상 클래스를 상속받은 모든 자식 클래스는 반드시 추상 메서드를 오버라이딩 및 재정의하여 구현해야
합니다. ==> 그렇지 않ㄴ으면 컴파일 에러가 발생합니다.
추상 클래스와 추상 메서드의 용도
자식 클래스 간의 공통적인 필드와 메서드 이름을 통일할 수 있습니다.
반드시 구형해야 하는 메서드를 선언하므로써 공통 규격을 제공합니다.(실수를 줄임)
결과적으로 자식 클래스들의 규격과 내용을 통일하기 위함이며, 이는 곧 객체 지향 프로그래밍의 다형성을 구현하기
위한 탄탄한 기반이 될 것입니다.
실무에서는 이러한 용도가 업무 효율성에 큰 영향을 미칩니다. 간단하게는 같은 클래스를 상속받는 자식 클래스들을
각각 다른 개발자들이 구현한다고 가정할 때 공통된 규격을 제공하고 반드시 구현해야하는 메서드를 알게 함으로써 보다
통일감 있는 코드를 완성할 수 있습니다. 이는 곧 개발 시간을 단축시키는 방법이기도 하며, 객체를 변경해야 할 경우
큰 효율을 느낄 수 있습니다.
2. 인터페이스(Interface) 구현
모든 메서드가 추상 메서드인 일종의 추상 클래스를 '인터페이스'라고 부릅니다. 인터페이스는 추상 메서드와 상수로만
이루어져 있으며, 추상 클래스와 마찬가지로 스스로 객체를 생성할 수 없습니다. 언뜻 보면 인터페이스와 추상 클래스가
같은 역할을 하는 것처럼 느껴질 수 있지만, 취지는 완전히 다릅니다.
[추상 클래스]
클래스들의 공통 메서드를 추출해 선언하며, 자식 클래스들이 상송(extends)받아 구현하도록 합니다.
(자식 클래스들에게 기본 틀과 공통 기능을 제공)
[인터페이스]
구현 클래스들의 기본 틀을 제공하면서, 다른 클래스 코드들과 사이에서 중간 매개 역할을 합니다.
추상 클래스는 자식 클래스들의 공통적 특징을 추출하고 제공하는 거이 주된 역할이었다면,
인터페잇는 그뿐 아니라 다른 클래스들과의 중간 매개 역할을 하는 것을 중점으로 생각할 수 있습니다.
인터페이스 선언
인터페이스는 클래스가 아닙니다. 클래스는 객체를 만들기 위한 설계도 역할을 하는 코드의 블록을 클래스라고 부르기
때문입니다. 추상 클래스는 스스로 객체를 생성할 수는 없지만, 자식 클래스의 생성자를 통해서 객체를 생성해낼 수 있습니다. 하지만 인터페이스는 어떤 형태로도 객체를 만들 수 없기 때문에 클래스라고 부를 수 없습니다.
인터페이스는 객체의 매개체, 즉 객체를 사용하는 방법을 제공하는 새로운 블록이라고 할 수 있습니다.
인터페이스를 선언할 때는 interface 키워드를 함께 사용하며, 다은과 같이 선언합니다.
[접근 제한자] interface 인터페이스이름{
...
접근 제한자 abstract 메서드이름(매개변수1, 매개변수2,...)
...
}
인터페이스는 필드와 생성자를 가지지 않습니다. 이는 객체를 생성할 수 없기에, 필드에 값을 수정할 수도 없고 생성자도 필요 없기
때문입니다. 인터페이스는 오직 추상 메서드와 상수만을 포함할 수 있습니다.
인터페이스를 선언하는 방법은 클래스를 작성하는 방법과 동일하며 class 키워드 대신 interface를 작성합니다.
또한 인터페이스의 추상 메서드는 다른 클래스들과의 매개체 역할을 하므로 누구나 접근할 수 있어야 합니다.
따라서 항상 public으로 구현합니다.
만약 접근 제한자를 default로 구현했다면 자동으로 public으로 인식할 것입니다. 클래스와 달리 인터페이스의 모든
필드는 public / static / final이어야 하며, 모든 메서드는 public / abstract이어야 합니다.
이는 모든 인터페이스에 공통적으로 적용되는 사항이므로 생략할 수 있으며
생략된 제한자는 컴파일 시 자동으로 추가됩니다.
인터페이스는 추상 클래스와는 다른게 모든 메서드가 추상 메서드라는 점을 확인할 수 있고, 더 나아가 공통 구현부를
추출해 만들어 두는 것이 아닌 '공통 틀'만 제공한다는 것을 알 수 있습니다. 인터페이스의 추상 메서드가 호출되면,
그 추상 메서드를 직접 구현해 준 객체의 메서드가 호출됩니다.
interface 안에서 abstract 키워드는 생략할 수 있습니다.
interface라는 뜻이 내부 모든 메서드가 abstract라는 의미를 내포하고 있기 때문입니다.
상수 선언
인터페이스에서 필드 대신 상수를 선언할 수 있습니다. 단, 상수이기 때문에 인터페이스는 고정된 값만 선언할 수 있어
충분한 고민을 통해 선언해야 합니다. 상수 선언 방법은 다음과 같습니다.
[접근 제한자] interface 인터페이스이름{
public static final 자료형 상수명 = 값;
...
}
- public : 인터페이스는 다른 클래스들의 접근이 가능해야 하므로 public 을 작성합니다.
- static : 객체가 생성되지 않는 인터페이스이기 때문에, 내부 상수에 접근하려면 클래스 변수처럼 static으로 선언되어 메모리에 올라가 있어야 합니다.
- final : 상수를 뜻하는 키워드입니다.
메서드에 public을 명시하지 않아도 자동으로 public이 붙는 것처럼, 상수 역시 public static final을 명시하지 않아도 자동으로 작성됩니다.
상수 명명 규칙
- 영문 대문자로 작성해야 합니다.
- 2개 이상의 단어를 조합할 때는 언더바( _ )로 연결합니다.
3. 인터페이스(Interface) 사용
추상 클래스는 앞에서 확인한 것처럼 추상 메서드가 비어있기 때문에 객체 생성을 스스로 할 수 없었습니다. 대신 자식
클래스의 생성자의 힘을 빌려 객체 생성을 할 수 있었습니다. 추상 클래스와 마찬가지로, 인터페이스 역시 추상 메서드가
비어있기 때문에 객체 생성을 스스로 할 수 없었습니다. 따라서 인터페이스도 자신이 가지고 있는 추상 메서드를 구현해 줄 클래스를 작성해야만 합니다. 이렇게 인터페이스를 구현해 주는 클래스를 '구현 클래스'라고 합니다.
추상 클래스는 자식 클래스들이 상속받아 구현하지만, 인터페이스에서는 구현된 멤버들을 상속받는 의미가 아니기 때문에 상속이라는 단어를 사용하지 않습니다. 따라서 자식 / 부모 클래스라는 용어도 사용하지 않습니다.
구현 클래스는 인터페이스를 사용해 구현하겠다는 선언을 해야 합니다. 구현한다는 의미를 가지고 있는
implements 키워드를 사용하여 명시할 수 있으며, 선언 방법은 다음과 같습니다.
[접근 제한자] class 클래스이름 implements 인터페이스이름{
// 필드
// 생성자
// 구현 메서드(추상 메서드 오버라이딩)
}
인터페이스의 모든 추상 메서드를 오버라이딩하지 않거나, 추상 메서드를 오버라이딩한 메서드의 접근 제한자를
public으로 지정하지 않은면 에러가 발생합니다.
인터페이스를 사용함으로써 아래와 같은 장점을 발견할 수 있습니다.
- 실제 구현 클래스의 내용을 전혀 보지 않고도 개발 코드로 객체를 사용할 수 있습니다. ==> 정보 은닉
- 구현 클래스들이 독립적으로 구현되고 사용될 수 있습니다. 개발 코드에서 객체 변경이 필요할 때, 개발 코드의 수정을 최소화할 수 있습니다. ==> 모듈화
추상클래스와 인터페이스의 공통점
추상 클래스와 인터페이스는 각각의 장점을 가지고 있지만, 사실 서로의 장점을 공유하기도 합니다. 정보 은닉, 모듈화,
추상화 등은 추상 클래스와 인터페이스가 공통으로 가진 장점입니다.
하지만, 추상 클래스의 특징이 추상화와 모듈화에 중점을 맞췄다면, 인터페이스는 추상화의 특징도 가지고 있지만
정보 은닉과 모듈화에 좀 더 초점을 맞췄다고 할 수 있습니다.
또한, 추상 클래스와 인터페이스 모두 다형성을 구현할 수 있는 기반을 제공하며, 추상 메서드 구현에 대한 강제성을
반영하고 있습니다.
다중 인터페이스 구현
하나의 클래스로 여러 개의 인터페이스를 구현할 수 있습니다.
다중 인터페이스를 선언하는 방법은 간단합니다. implements 키워드 위에 인터페이스 이름을 기재할 때 콤마(,)를 이용해
여러 개를 붙여 선언합니다. 단, 선언한 모든 인터페이스에 대한 추성 메서드를 모두 구현해 줘야 합니다.
[접근 제한자] class 클래스이름 implements 인터페이스1, 인터페이스2,...{
// 필스
// 생성자
// 인터페이스1에 대한 구현 메서드(추상 메서드 오버라이딩)
// 인터페이스2에 대한 구현 메서드(추상 메서드 오버라이딩)
}
4. 인터페이스(interface) 상속
인터페이스 역시 인터페이스끼리 상속 관계를 만들 수 있습니다. 클래스의 상속과 마찬가지로 extends 키워드를 사용하며,
다중 상속이 가능하기 때문에 콤마(,)를 이용해서 다음과 같이 선언합니다.
[접근 제한자] interface 인터페이스이름 extends 인터페이스1, 인터페이스2,...{
...
// 추상 메서드
}
클래스의 상속과 마찬가지로 인터페이스 상속을 선언하면, 하위 클래스는 상위 클래스의 모든 멤버를 상속 받게 됩니다.
따라서 만약 하위 인터페이스를 구현하는 클래스가 있다며, 해당 클래스는 하위 인터페이스의 추상 메서드를 포함하여
상위 인터페이스의 추상 메서드까지 구현해야 합니다.
응용문제
1. 다음 빈칸에 알맞은 단어를 작성해 보세요.
- 구현 내용이 없이 비어있는 메서드를 ㅁㅁ ㅁㅁㅁ(이)라고 부릅니다.
- 위 메서드를 선언할 때는 ㅁㅁㅁㅁㅁㅁㅁ 키워드를 사용해야 합니다.
- 이러한 메서드를 1개 이상 가지고 있는 클래스를 ㅁㅁ 클래스라고 부릅니다.
정답 : 추상 메서드, abstract, 추상
2. 다음 코드는 컴파일 에러가 발생합니다. 컴파일 에러가 발생하는 곳을 모두 찾아 수정해 보세요.
package section12;
abstract class Bike{
int wheel;
Bike(int wheel){
this.wheel = wheel;
}
void info(){
System.out.println("이 자전거는 "+wheel+"발 자전거 입니다.");
}
}
class childBike extends Bike{
ChildBike(int wheel){
}
}
class PRACTICE_12_02{
public static void main(String[] args){
Bike b = new Bike(2);
ChildBike cb = new ChildBike(4);
cb.info();
}
}
16번 라인과 17번 라인) 자식 클래스에서 부모 클래스의 생성자를 호출해야하고
22번 라인) 추상 클래스는 직접 객체를 생성할 수 없음
package section12;
abstract class Bike{
int wheel;
Bike(int wheel){
this.wheel = wheel;
}
void info(){
System.out.println("이 자전거는 "+wheel+"발 자전거 입니다.");
}
}
class childBike extends Bike{
ChildBike(int wheel){
super(wheel); // 자식 클래스 생성자에서 super()를 통해 추상 클래스의
// 생성자를 호출하여 부모 객체를 생성한 후 자식 객체를 생성해야함
}
}
class PRACTICE_12_02{
public static void main(String[] args){
// Bike b = new Bike(2); - 추상 클래스는 직접 객체를 생성할 수 없음
ChildBike cb = new ChildBike(4);
cb.info();
}
}
3. 다음 문장이 맞으며 O표, 틀리면 X표 하세요.
- 추상 클래스는 자식 클래스들의 상속(extends)받아 구현합니다. ( )
- 인터페이스는 다른 클래스 코드들과의 사이에서 중간 매개체 역할을 합니다. ( )
- 인터페이스 안에서 상수를 선언할 때, final을 명시하지 않으면 syntax error가 발생합니다. ( )
- 추상 클래스와 인터페이스의 추상 메서드는 구현부가 있으면 안됩니다. ( )
- 클래스 간 다중 상속이 불가능한 것처럼 인터페이스도 다중 상속이 불가능합니다. ( )
정답 : O, O, X, X, X
4. 2번 예제 코드에서 Bike 클래스 안에 아래 메서드를 추가 했습니다. ChildBike 클래스를 어떻게 수정해야 할까요 ?
abstract int getWheel();
정답 : 자식 클래스에서 오버라딩을 필수로 해야됨
5. 인터페이스를 사용함으로써 다음과 같은 객체 지향의 특징을 가질 수 있습니다. 각 용어의 개념에 대해 이해하고 있는 것을 간략히 서술해 보세요.
- 정보 은닉 :
- 모듈화 :
정보 은닉 : 실제 구현 클래스의 내용을 전혀 보지 않고도 개발 코드로 객체를 사용할 수 있음
모듈화 : 구현 클래스들이 독립적으로 구현되고 사용될 수 있음, 개발 코드에서 객체 변경이 필요할 때
개발 코드의 수정을 최소화할 수 있음
'javaboiii의 JAVA > JAVA 요약정리(멘토씨리즈)' 카테고리의 다른 글
JAVA -14) 예외처리 (0) | 2024.07.25 |
---|---|
JAVA -13) 내부 클래스 (2) | 2024.07.24 |
JAVA -11) 다형성과 타입 변환 (0) | 2024.07.22 |
JAVA -10)상속 (0) | 2024.07.21 |
JAVA -9)생성자 (2) | 2024.07.20 |