[Chap 9] 추상 클래스
추상 클래스
여태까지 사용했던 클래스들은 concrete class 였다. 추상 클래스는 항상 추상 매서드를 포함한다. 추상 매서드란 { } 가 없는 함수를 말한다. 즉 선언만 하며, abstract 예약어를 사용한다. 추상 클래스, 추상 매서드는 기울임꼴로 표시합니다.
추상 클래스 사용 방법
1 2 3 4 5 6 7 8 9 10 11 | public abstract class Cumputer { public abstract void display(); public abstract void typing(); public void turnOn() { System.out.println("전원을 켭니다."); } public void tunOff() { System.out.println("전원을 끕니다."); } } | cs |
위와 같이 클래스와 매서드 모두 abstract
예약어를 사용해서 추상 클래스 안의 추상 매서드를 만들어 줍니다. 그래서 구현 매서드인 turnOn
과 turnOff
는 Computer 클래스를 상속 받는 하위 클래스에서는 굳이 구현을 해주지 않아도 된다. 하지만 추상 클래스인 display
와 typing
은 하위 클래스에서 따로 구현을 해주어야 한다. 이것이 구현 매서드와 추상 매서드의 차이점이다.
추상 클래스를 상속받는 하위 클래스는 구체적인 클래스이다.
추상 클래스를 상속받는 하위 클래스인 경우, 추상 매서드를 상속받는 것이므로(구현 매서드는 상속받음) 하위 클래스 역시 추상 클래스로 만들어 주든지 아니면 추상 매서드를 구체적으로 구현하면 된다. 그래서 8장에서 배웠던 오버 라이딩이 사용되는 것이다. 8장에서는 상위 클래스에서 구현한 구현 매서드를 다시 오버 라이딩 한 것이다. 이 경우는 필요에 따라 오버 라이딩을 한 것이지, 하지 않더라도 에러가 뜨지는 않았다. 하지만 추상 매서드인 경우, 매서드를 선언만 한 것이므로 이를 상속받은 하위 클래스는 무조건 이를 오버라이딩 하여 구현해주어야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | //DeskTop.java -> 추상 매서드 2가지 모두 오버라이딩함 public class DeskTop extends Computer { @Override public void display() { System.out.println("DeskTop display()"); } @Override public void typing() { System.out.println("DeskTop typing()"); } } | cs |
1 2 3 4 5 6 7 8 | //NoteBook.java -> 2가지 추상 매서드 중 하나만 구현시킴. 추상 매서드를 하나 가지고 있는 것이므로 이 클래스는 추상 클래스가 되어야 함. public abstract class NoteBook extends Computer { @Override public void display() { System.out.println("NoteBook display()"); } } | cs |
1 2 3 4 5 6 7 | public class MyNoteBook extends NoteBook{ @Override public void typing() { System.out.println("MyNoteBook typing()"); } } | cs |
상위 추상 클래스를 상속받은 하위 추상 클래스를 상속받은 MyNoteBook.java
추상 클래스를 만드는 이유
추상 클래스는 인스턴스를 만들 수 없다. 선언만 된 함수를 가지고 있는 추상 클래스르 어떻게 인스턴스를 만들 수 없기 때문이다. 추상 클래스는 무조건 상속을 하기 위해서 만들어진 클래스이다. 그렇다면 상위 클래스 내에서 어떤 경우 추상 매서드를 만들고, 어떤 경우에 구현 매서드를 만들까? 추상 매서드는 위의 예시에서도 보았던 것 처럼 무조건 하위 클래서에서 구현이 필요하다. 이처럼 하위 클래스에서 오버라이드가 필요한 매서드를 추상 매서드로 만들어 버리는 것이다. 반대로 모든 하위 클래스들이 공통으로 사용할 매서드들을 구현 매서드로 만들어 버리면 된다.
템플릿 매서드
final 예약어를 통해서 함수가 정의되며, 이 순서에 맞게 알아서 메서드들이 작동하는 것 같음(아직 자세히 나오지는 않음)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //상위 클래스 public abstract class Car { public abstract void drive(); public abstract void stop(); public void startCar() { System.out.println("시동을 켭니다."); } public void turnOff() { System.out.println("시동을 끕니다."); } //템플릿 메서드 final public void run() { startCar(); drive(); stop(); turnOff(); } } | cs |
상위 클래스에서 추상 메서드인 drive
와 stop
는 하위 클래스에서 구현해주어야 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //하위 클래스 1. AICar.java public class AICar extends Car { @Override public void drive() { System.out.println("자율 주행합니다."); System.out.println("자동차가 알아서 방향을 전환합니다."); } @Override public void stop() { System.out.println("스스로 정지합니다."); } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //하위 클래스 2. ManualCar.java public class ManualCar extends Car { @Override public void drive() { System.out.println("사람이 운전합니다."); System.out.println("사람이 핸들을 조작합니다."); } @Override public void stop() { System.out.println("브레이크로 정지합니다."); } } | cs |
템플릿 메서드를 활용한 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public class CarTest { public static void main(String[] args) { System.out.println("===자율 주행하는 자동차==="); Car myCar = new AICar(); myCar.run(); System.out.println("===사람이 운전하는 자동차==="); Car hisCar = new ManualCar(); hisCar.run(); } } /* 출력 결과 ===자율 주행하는 자동차=== 시동을 켭니다. 자율 주행합니다. 자동차가 알아서 방향을 전환합니다. 스스로 정지합니다. 시동을 끕니다. ===사람이 운전하는 자동차=== 시동을 켭니다. 사람이 운전합니다. 사람이 핸들을 조작합니다. 브레이크로 정지합니다. 시동을 끕니다. */ | cs |
여기서 알 수 있는 것처럼 final 예약어를 사용한 템플릿 메서드는 실행 순서를 정의한 메서드라고 할 수 있다. 그렇기 때문에 상위 클래스에서 정의를 해야되며, 하위 클래스에서는 오버라이딩을 할 수 없는 메서드이다.
final 예약어
final 변수
보통 final 변수 같은 경우는 일반 변수와 구별을 하기 위해서 모두 대문자로 표현해주는 경우가 많다. final 변수의 역할은 다른 값을 대입할 수 없다는 것이다. C언어에서 const 같은 역할을 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Constant { int num = 10; final int NUM = 100; public static void main(String[] args) { Constant cons = new Constant(); cons.num = 50; //cons.NUM = 200; -> fianl 변수에 값을 대입하여 에러 System.out.println(cons.num); System.out.println(cons.NUM); } } | cs |
final 클래스
final 클래스는 상속할 수 없는 클래스이다. 주로 재정의할 메서드가 없는 경우, 오버라이드를 막기 위해서 사용한다.
댓글남기기