추상클래스
활용
- '나는 적용법을 제공하고 싶지 않고 대신 알고리즘을 제공하겠다' 하는 경우
- '이건 하위 클래스들이 해결해야 하는 문제다' 하는 경우
특징
- 추상클래스는 다른 추상클래스를 상속할 수 있다
abstract class B extends A
- 추상클래스는 정의된 변수들을 가질 수 있고 정의된 메소드도 가질 수 있다.
인터페이스
추상클래스와 인터페이스는 아주 다른 개념이다.
인터페이스는 선언을 제공할 뿐 정의를 내리는 게 아니다.
인터페이스에 대해 사고하는 방법
게이밍 콘솔이라고 생각한다. 어떤 게임을 하든지 버튼은 그 게임에서 정의된 역할을 한다.
public interface GamingConsole { // GamingConsole 인터페이스 선언
public void up();
public void down();
public void right();
public void left();
}
public class MarioGame implements GamingConsole { // GamingConsole 인터페이스를 구현한 MarioGame 클래스 선언. 이후 저장하려고 하면 오류가 뜨는데, 자동으로 부족한 부분 생성하는 버튼을 누르면 아래와 같이 override와 함께 메서드가 생성된다.
@Override
public void up() {
System.out.println("Jump");
}
@Override
public void down() {
System.out.println("Goes into a hole");
}
@Override
public void right() {
System.out.println("Go Forward");
}
@Override
public void left() {
System.out.println("Go Back");
}
}
public class GameRunner {
public static void main(String[] args) {
MarioGame game = new MarioGame();
// ChessGame game = new ChessGame();
// 마리오 게임이랑 비슷하게 체스게임도 정의해준다면, 카트리지 바꿔끼는 느낌이 될 수 있다.
// (현재 인스턴스 이름이 game으로 동일하기에 주석처리)
// GamingConsole game = new MarioGame(); // 이것 역시 가능하다
game.up();
game.down();
game.left();
game.right();
}
}
인터페이스를 활용하면 실제로 구현되지 않은 것도 사용할 수 있다
인터페이스는 외부 인터페이스가 실제로 사용 가능하지 않은 상태라도(구현되지 않은 상태라도) 작업을 계속 진행할 수 있게 해준다.
예를 들어서 우리가 어떤 프로젝트를 진행중인데, 외부 팀에게 복잡한 부분의 코딩을 외주를 맡기는 상황이라고 하자. 이렇게 아직 복잡한 부분이 완성되지 않은 상황에서 우리가 할 수 있는 일은? 그 복잡한 부분을 인터페이스로 만드는 것이다.
public interface ComplexAlgorithm { // 복잡한 부분을 인터페이스로 만들었다
int complexAlgorithm(int number1, int number2); // 구현되지 않은 메서드
}
ComplexAlgorithm 라는 인터페이스로 복잡한 부분을 정의해주었다. 그리고 미구현된 메서드도 넣어주었다. 외주팀에게 이런 메서드가 있고, 이런 인터페이스가 있다는 걸 전달하는 의사소통의 기능을 하는 것이 인터페이스의 장점이다.
그러면 이제 작업을 계속하기 위해, 위의 ComplexAlgorithm 을 implements한 임시 클래스 DummyAlgorithm을 만들어준다.
public class DummyAlgorithm implements ComplexAlgorithm { // 위의 복잡한 부분을 구현한 더미 알고리즘 클래스
// 이 아래 내용을 쓰지 않고 그냥 저장하려 하면 미구현된 것을 구현하라는 오류가 뜬다.
@Override
public int complexAlgorithm(int number1, int number2) {
return number1 + number2; // 더미니까 대충 구현한다
}
}
이렇게 우리의 프로젝트는 이 임시 클래스로 작업을 이어갈 수 있게 된다. 이처럼 인터페이스를 활용하면 복잡한 코드를 실제로 구현하지 않고도 작업이 가능한 것이다.
public class Project { // Project 클래스 선언
public static void main(String[] args) {
ComplexAlgorithm algorithm = new DummyAlgorithm(); //더미로 작업 진행중인 모습
System.out.println(algorithm.complexAlgorithm(10, 20));
}
}
외주팀이 실제로 구현된 코드(RealAlgorithm)를 제공하는 경우, 이 코드를 인터페이스에 implements 한다.
public class RealAlgorithm implements ComplexAlgorithm {
// 외주팀이 제공해준 엄청 복잡한 알고리즘을 구현하는 1000줄의 코드라고 치자
@Override
public int complexAlgorithm(int number1, int number2) {
return number1 + number2;
}
}
그리고 임시로 사용하던 DummyAlgorithm을 → 외주팀에게 받은 RealAlgorithm로 바꿔주기만 하면 된다.
public class Project {
public static void main(String[] args) {
ComplexAlgorithm algorithm = new RealAlgorithm(); //더미알고리즘을 리얼알고리즘으로 수정한 것.
System.out.println(algorithm.complexAlgorithm(10, 20));
}
}
이처럼 인터페이스는 모조 구현을 제공하며, 우리는 실제로 구현되지 않은 것이라도 그것을 사용할 수 있는 것이다.
Interface is Contract.
인터페이스는 소통하는 두 클래스간의 계약이다.
특정 클래스가 확실히 구현할 메소드들이 무엇인지 알 수 있게 해준다.
인터페이스의 특징
- 인터페이스는 또 다른 인터페이스를 상속받을 수 있다.
- 그러나 다른 인터페이스를 구현implements할 수는 없다.
- 인터페이스에서 implements받은 건 전부 구현을 해야한다.
- 그러나 전부 구현하고 싶지 않은 경우 → 추상클래스로 만들면 된다
abstract class ImplementationAbstract implements Interface2
Interface2
클래스를 implements한 추상클래스ImplementationAbstract
- 추상 클래스는 인터페이스에 정의되어 있는 메소드들의 일부만 구현할 수 있다.
- 이 추상 클래스를 상속extends하는 구상concrete 클래스는 당연히 모든 것을 구현해야 한다.
- 구상concrete 클래스란 모든 메소드가 모두 구현(implements)되어있는 클래스를 뜻한다. 일반적으로 new 해서 만드는 것.
- 그러나 전부 구현하고 싶지 않은 경우 → 추상클래스로 만들면 된다
- 인터페이스 내에서 변수 생성은 허용되지 않는다.
int test;
→ 컴파일 실패 : 변수라서int test = 5
→ 컴파일 성공 : 이건 변수가 아니라 상수. 상수만 만들 수 있으며 상수의 값은 바뀔 수 없다.
default
로 디폴트 (구현된) 메소드를 제공할 수 있다.- 용도 : 인터페이스를 extends할 때 쓰인다. 그냥 구현된 메소드를 추가하면 컴파일 오류가 발생하기 때문. (인터페이스 기본적으로 미구현 메소드만 가질 수 있다)
추상 클래스와 인터페이스의 관계
사실 문법이 비슷할 뿐이고 둘의 비슷한 점은 별로 없다.
추상 클래스의 용도
- 높은 단계의 기본 조를 만들어서 모든 하위 클래스들이 이 구조와 합치하게 만들고 싶을 때
- 구현의 세세한 부분들은 하위 클래스에 맡기고 싶을 때
인터페이스의 용도
- 두 시스템/클래스/요소들이 서로 소통하길 바랄 때
- 메소드를 정의하고, 이 둘은 앞으로 이렇게 소통할 것이라는 소통방식을 정하는 것
- 그럼 인터페이스 쪽에서는 구현을 제공하고 구현하는 쪽에서는 인터페이스를 사용한다.
대표적인 차이
관계
- 추상클래스를 사용하려면 상속을 사용해야 한다.
- 이런 종류의 관계는 인터페이스에는 존재하지 않는다.
접근 제한자
- 추상클래스에서는 private를 넣을 수 있다.
- 인터페이스에서는 private로 선언이 불가능하다. 모든 건 public이다.
변수
- 추상클래스는 변수를 가질 수 있다. 그냥 클래스라서 그렇다. 일부 메소드가 구현되지 않은 것 뿐인 클래스이다.
- 인터페이스에는 변수를 넣지 못한다.
클래스
- 클래스는 다중으로 인터페이스를 구현 할 수 있다. 클래스 implements A, B, C 가 가능하다.
- 클래스는 다중 상속multiple inheritance을 지원하지 않는다. (C++에서는 다중상속을 지원한다고 한다.)