객체 지향 프로그래밍(OOP)의 특성 중 하나인 상속
은 상위 클라스의 기능을 하위 클라스 에서도 가능하도록 부여받는 것으로
확장성, 유연성, 재사용성의 기능을 높여준다.
상속을 공부한다면 추상화
를 볼 수 있을 것이고 인터페이스
를 공부하게 될 것이고
오버라이딩
, 오버로딩
까지 같이 공부하게 된다.
나는 두 기초적인 지식에서 정리가 되지 않았고 이번 기회로 정리하고자 한다.
추상 클래스를 알기 전에 추상화
에 대한 오해를 풀고 가자
JAVA에서 추상화
는 특별한 용어는 아니다.
그저 국어 표현에서 말하는 추상
은 실체 간에 공통되는 특성을 추출한 것
으로 정리되는 할 수 있는데
개발자가 어떤 객체의 공통되는 특성을 뽑아내어 하나의 공통 객체로 만들어 내는 과정을 추상화
라고 하는 것이다.
즉, 추상화는 사물에서 보이는 요소를 추출하는 행위 인것이다.
class Dog {
int age;
int name;
String sound;
}
class Cat {
int age;
int name;
String sound;
}
추상 클래스
는 실체 클래스가 공통적으로 가져야할 필드와 메소드 들을 정리해 놓은 클래스이며
실체클래스의 멤버(필드, 메소드)를 통일화 하는데 목적이 있다.
추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들어냈기 때문에 객체를 식접 호출(new()
)하는 것이 아닌
extends
를 사용하여 호출해야 한다.
만일 고양이와 강아지의 요소를 추상화 동물
이라는 추상 클래스를 만들었다고 하면
sound()
메소드를 어떻게 구현해야할까?
고양이과 강아지는 울음소리가 다르기 때문에 추상 클래스
에서 구현을 해서는 안된다.
JAVA 에서는 이를 추상 클래스
에서는 해당 클래스가 아닌 하위 클래스에서 구현하도록 제약을 걸었다.
때문에 우리는 추상 클래스
에서 메소드 만을 선언하고 실행 내용은 쓸 수 없는 것이다.
마지막으로 추상 클래스
에서는 추상 메소드
만 만들 수 있다.
class Dog {
int age;
int name;
String sound;
}
class Cat {
int age;
int name;
String sound;
}
위 코드를 상속 받기위한 상위 클라스로 분리
하고 추상 클라스
까지 만들어 본다면 다음과 같이 구현할 수 있다.
abstract class AnimalSound {
public abstract void sound(String sound);
}
class Animal extends AnimalSound {
int age;
int name;
//TODO: AnimalSound 추상클래스에서 @Override 하여 함수를 구체화 함
@Override
public void sound(String sound) {
System.out.println(sound);
}
}
class Dog extends Animal{
}
class Cat extends Animal{
}
class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.sound("멍멍");
cat.sound("야옹");
}
}
추상 클래스
와 상속
은 어떻게 다른가?사실 상속은 상위 클래스의 기능을 하위 클래스 까지 확장하는 개념으로
추상 클래스
또한 상속의 일종이라고 할 수 있다.즉, 상속은 넓은 개념이며 내부에는
추상화
가 있고 더 나아가인터페이스
또한 상속 개념에 포함되어 있는 것이다.
인터페이스는 기존 다중상속
의 문제를 해결하기 위해 등장한 개념이며 이에 따라 실체 클라스
혹은 추상 클래스
로 다중 상속은 할 수 없다.
추상 혹은 실체 클래스는 extend
키워드를 사용하는 반면 인터페이스는 implement
키워드를 사용한다.
참조 메소드를 가지는 참조클래스와 같이 인터페이스 또한 상수
와 메소드
만 가질 수 있다.
사실 인터페이스는 코드를 수정하지 않고, 사용하는 객체를 변경할 수 있도록 하기 위해서이며 또한 추상 클래스의 단일 상속의 문제를 극복하기 위해 존재한다.
인터페이스는 할 수 있다.
라는 개념으로 접근해야한다.
해석하면: 어떤 클래스가 ~행위를 할 수 있다. 라는 개념으로 말이다.
때문에 객체의 특징을 확장하는 개념의 extend
(확장하다)와 달리
행위를 구현하는 implement
(구현하다) 라는 단어를 사용하는 것이다.
추상 클래스를 여러개 만들어서 하나의 클래스에 구현한다면 어떻게 될까?
스프링 입문교재에서 재미있는 예시를 가져왔다.
사람과 물고기 클래스를 상속받은 인어는
수영하다()
명령문에 팔로 수영해야할까 꼬리로 수영해야할까?
이것이 다중상속의 문제점이다.
C++
을 계승한 자바에서는 이를 문제로 인지하여 다중상속 기능을 구현하지 않았지만 Interface
기능을 도입하여 문제를 개선 하였다.
interface 헤엄칠수있는 {
void swim();
}
interface 날수있는 {
void fly();
}
class 동물 {
String myClass;
동물() {
myClass = "동물";
}
}
class 조류 extends 동물 {
조류() {
myClass = "조류";
}
}
//TODO: 다중상속의 문제점을 인터페이스로 극복할 수 있다.
class 오리 extends 조류 implements 날수있는, 헤엄칠수있는 {
오리() {
myClass = "오리";
}
@Override
public void fly() {
System.out.println(myClass + " 날다!");
}
@Override
public void swim() {
System.out.println(myClass + " 수영하다!");
}
}
class Driver {
public static void main(String[] args) {
오리 청둥오리 = new 오리();
청둥오리.fly();
청둥오리.swim();
}
}
추상 클래스
와 인터페이스
두가지 모두 상속의 개념에서의 한 분야이며 상속의 장점을 모두 가져간다.
극명한 차이라면 다중상속
의 극복에 있으며 추상 클래스가 a kind of
의 개념이라면, 인터페이스는 be able to
에 있으며
추상클래스의 추상메소드를 통해 자체적 행위 구현은 불가는 하기에 하위 클래스에서 @Override
해야한다.
그렇다고 인터페이스에서 추상 메소드는 @Override
를 사용할 수 없는 것은 아니다.
쉽게 추상 메소드
는 오버라이드
할 것 으로 이해하면 편할 것이다.
인터페이스은 다중상속
과 기능구현
이 가능하기에 이후 Spring Framework 에서 여러 DB를 연결할 수 있었고
더 나아가 JPA
를 구현할 수 있는 기반이 되어준다.