남궁성님의 Java의 정석(3rd Edition)을 보고 정리한 글입니다.
추상클래스와 인터페이스를 알아보기 전에 객체지향의 핵심 원리인 다형성에 대해서 정리해보자.
1. 다형성(polymorphism)이란?
- 부모 타입의 참조변수로 자식타입의 객체를 다룰 수 있는 것
- 자식타입의 참조변수로는 부모타입의 인스턴스를 참조할 수 없다.
- 다형성을 사용하면 유지보수에 큰 이점을 가져올 수 있으면 객체지향의 핵심 원리이다.
public class Main {
public static void main(String[] args) {
Parent parent = new Child(); // => 다형성
Child child = new Parent(); // 에러. 자식은 부모의 모든 멤버를 가지지만, 부모는 자식의 멤버를 모두 가지지 않는다
}
}
class Parent {
int age;
void parentMethod() {
System.out.println("부모 클래스");
}
}
class Child extends Parent {
void ChildMethod() {
System.out.println("자식 클래스");
}
}
2. instanceof 연산자
- 참조변수가 참조하는 인스턴스의 타입을 체크하는데 사용하는 연산자
- 연산 결과는 true, false
- 연산결과가 true이면 해당 타입으로 형변환이 가능
public class Main {
public static void main(String[] args) {
Parent parent = new Child();
if(parent instanceof Parent) {
System.out.println("parent는 Parent 타입입니다.");
} else {
System.out.println("parent는 Parent 타입이 아닙니다.");
}
if(parent instanceof Child) {
System.out.println("parent는 Child 타입입니다.");
} else {
System.out.println("parent는 Child 타입이 아닙니다.");
}
}
}
class Parent {
// ...
}
class Child extends Parent {
// ...
}
실행결과
parent는 Parent 타입입니다.
parent는 Child 타입입니다.
3. 추상클래스(abstract class)란?
- 미완성 설계도
- 추상클래스는 하나 이상의 추상메서드를 포함하고 있는 클래스
- 추상메서드는 선언만 하고 메서드 바디가 없는 메서드
abstract class Parent { // 추상 클래스
int age; // 필드
void parentMethod() { // 일반 메서드
...
}
abstract void setAge(); // 추상 메서드
}
a. 추상클래스 예제
abstract class Parent { // 추상 클래스
int age; // 필드
void parentMethod() { // 일반 메서드
// ...
}
abstract void setAge(int age); // 추상 메서드
}
class Child extends Parent {
void ChildMethod() {
System.out.println("자식 클래스");
}
@Override
void setAge(int age) {
super.age = age;
}
}
class Exam {
public static void main(String[] args) {
Parent parent = new Child(); // 다형성을 지원한다.
// Parent parent = new Parent(); // 에러. 추상클래스는 인스턴스화를 금지한다.
}
}
- 다형성을 지원한다.
- 추상클래스를 상속받는 자식클래스는 반드시 추상 메서드를 오버라이딩 해야한다.
- 추상클래스는 인스턴스화를 금지한다.
4. 인터페이스(interface)란?
- 추상 클래스보다 추상화 정도가 높다.
- 실제 구현된 것이 전혀 없는 기본 설계도
- 추상메서드와 상수만을 멤버로 가진다.
- 인스턴스를 생성할 수 없다.
- 자바에서는 인터페이스를 통해 다중 상속을 지원한다.
a. 인터페이스 예시
interface Lendable {
public static final int a = 0; // public static final 생략 가능
// public abstract 생략 가능
public abstract void checkOut(String borrower, String date);
public abstract void checkIn();
}
b. 인터페이스 상속
interface Moveable {
void move(int x, int y);
}
interface Attackable {
void attack(Object o);
}
interface Figtable extends Moveable, Attackable {
void time(int t);
}
- 인터페이스를 통해 다중 상속을 지원한다.
- 인터페이스가 인터페이스를 상속받을 때 extends 키워드를 사용한다.
c. 인터페이스 구현
class people implements Figtable {
@Override
public void move(int x, int y) {
// ...
}
@Override
public void attack(Object o) {
// ...
}
@Override
public void time(int t) {
// ...
}
}
interface Moveable {
void move(int x, int y);
}
interface Attackable {
void attack(Object o);
}
interface Figtable extends Moveable, Attackable {
void time(int t);
}
- 클래스가 인터페이스를 상속받을 때 implements 키워드를 사용한다.
- 모든 추상메서드를 오버라이딩 해야한다.
d. 인터페이스를 이용한 다형성
- 클래스간의 상속관계와 마찬가지로 다형성을 지원한다.
public class Main {
public static void main(String[] args) {
MyInterface myInterface = new People();
People people = new MyInterface(); // 에러
}
}
class People implements MyInterface {
}
interface MyInterface {
}
e. Default 메서드
- JDK1.8부터 추가되었다.
- 인터페이스의 구현체(클래스)는 모든 메서드를 오버라이딩 해야했다.
- Default 키워들 사용하면 필요할 때만 오버라이딩 해서 사용하면 된다.
- 메서드 바디를 가지고 있다.
class People implements MyInterface {
@Override
public void method(int t) {
// ...
}
@Override
public void newMethod() {
// ...
}
}
interface MyInterface {
void method(int t);
default void newMethod(){}
}
f. 인터페이스 장점
- 개발 시간 단축
- 인터페이스를 사용하면 다른 개발자들이 각각의 부분을 완성할 때 까지 기다리지 않고 서로 규약만 정해두어 각자의 부분만 따로 나눠서 작성할 수 있다.
- 표준화
- 틀을 제공해주므로 정형화된 개발을 할 수 있다.
- 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.
- 아무런 관계가 없는 클래스들에게 인터페이스를 상속 받으므로 관계를 맺을 수 있다.
- 독립적인 프로그래밍이 가능
- 클래스간 결합도를 낮출 수 있고, 코드의 종속성을 줄이고 유지보수성을 높인다.
'Programming > Java' 카테고리의 다른 글
[Java] try-catch 예외처리 (0) | 2023.10.16 |
---|---|
[Java] 내부 클래스(inner class)란? (0) | 2023.10.16 |
[Java] 자바의 제어자 정리 (0) | 2023.10.16 |
[Java] package와 import (0) | 2023.10.16 |
[Java] 상속관계와 포함관계 (0) | 2023.10.13 |