티스토리 뷰
목차
EX3 ) 서브클래스에서 추상메서드의 오버라이딩 분할하기
📍 추상메서드 (Abstract Method)
– 메서드 바디(= 구현부 { })가 존재하지 않는 메서드 = 미완성 메서드
→ 실행 코드가 없으므로 실행 (호출)될 수 없는 메서드.
– 메서드 선언부 접근제한자 뒤에 abstract 키워드를 붙여서 선언.
→ 바디가 없으므로 메서드 마지막을 세미콜론(;)으로 마무리 함.
→ 메서드 실행 코드(바디)가 없으므로 외부에서 호출되면 안되는 메서드.
– 바디가 없을 뿐, 파라미터로 값 전달 받을 수 있음.
▸ 추상메서드 정의 기본 문법
[접근제한자] abstract 리턴타입 메서드명 ( [매개변수...] );
▸ 추상 메서드를 선언하는 이유
– 특정 메서드를 각 클래스 별로 재 구현 해야 하는데,
부모 클래스에서 일반 메서드로 구현하면 자식 클래스에서 구현을 하지 않는 경우가 발생할 수 있음.
→ 이런 메서드를 추상 메서드로 선언하면 자식 클래스는 무조건 재 구현을 해야 하는 강제성이 부여됨.
📍 추상클래스 (Abstract Class)
– 인스턴스를 생성할 수 없는 '미완성 클래스'.
→ 내부에 추상메서드를 가지고 있을 경우 추상메서드가 호출되면 안되므로 인스턴스 생성을 못하게 차단함.
– class 키워드 앞에 abstract 키워드를 붙여서 정의.
– 추상메서드 뿐만 아니라 일반메서드, 멤버변수, 생성자를 가질 수 있음.
→ 추상메서드가 없는 메서드도 추상클래스로 정의할 수 있음.
– 인스턴스 생성 불가지만 상속을 통한 슈퍼클래스로 사용하거나, 다형성 활용을 위한 참조변수 타입으로 사용 가능함.
– 추상메서드를 포함하는 추상클래스를 상속받는 서브클래스에서는
반드시 오버라이딩을 통해 추상메서드 바디{ }를 구현해야 함. 즉, 추상메서드 오버라이딩을 강제할 수 있음.
(what에 대한 강제, how는 서브클래스에게 위임)
– 추상메서드에 대한 구현을 강제함으로써 코드의 강제성 및 통일성 향상.
– 추상메서드를 갖는 클래스는 반드시 추상클래스로 선언되어야 함.
▸ 추상클래스 정의 기본 문법
[접근제한자] abstract class 클래스명 {
멤버변수
생성자
일반메서드
추상메서드
}
▸ 추상 클래스의 장점
1 ) 부모클래스에서 공통 부분의 구현과 설계가 완료되면, 자식 클래스에서 상속받아 기능을 확장할 시 이로움.
2 ) 자식 클래스에서 추상메서드를 반드시 구현하도록 강요하므로 프로그램의 표준화 정도를 높임.
3 ) 공통 사항이 한곳에서 관리되어 개발 및 유지보수에 용이함.
EX1 ) 기본 정의 및 사용 |
• 추상클래스 정의
abstract class AbstractClass { // public abstract void abstractMethod() {} public abstract void abstractMethod(); // 추상클래스가 추가로 가질 수 있는 것 public void normalMethod() {} // 일반 메서드 public AbstractClass() {} // 생성자 String member; // 멤버변수(=인스턴스 변수) }
코드 분석
3 | Abstract methods do not specify a body 에러. 추상메서드는 바디부분이 없어야 하므로 추상메서드 정의시 반드시 중괄호를 제거해야 함. |
4 | 추상메서드를 갖는 클래스는 반드시 추상클래스로 선언되어야 하므로 class 키워드 앞에 abstract 키워드 필수. |
• 추상클래스 AbstractClass를 상속받는 서브클래스 SubClass 정의
class SubClass extends AbstractClass{ @Override public void abstractMethod() { System.out.println("서브클래스에서 오버라이딩(구현) 된 추상메서드"); } public void subClassMethod() { System.out.println("서브클래스에서 정의한 메서드"); } }
– SubClass 유형은 상속된 추상 메서드를 구현해야 함.
→ 추상클래스를 상속받은 서브클래스는 반드시 추상메서드 오버라이딩 필수 !
→ 바디를 갖지 않는 추상메서드 바디를 구현(implement) 하는 작업.
• main 메서드에서 실행
// 추상클래스 AbstractClass 인스턴스 생성 // AbstractClass ac = new AbstractClass(); // 에러 발생 // 추상클래스를 상속받은 서브클래스 인스턴스 생성 SubClass sc = new SubClass(); sc.normalMethod(); sc.abstractMethod(); sc.subClassMethod(); // 모두 접근 가능 // 업캐스팅 AbstractClass ac = new SubClass(); ac.normalMethod(); // 공통(상속된) 메서드 ac.abstractMethod(); // 공통(상속된) 메서드 // → 오버라이딩 메서드 → 부모의 꿈을 자식이 이룸 // 호출 불가 //ac.subClassMethod();
코드 분석
2 | – 추상클래스는 인스턴스 생성 불가하므로 에러 발생. |
5~9 | – 추상클래스를 상속받은 서브클래스는 인스턴스 생성이 가능함. → 추상메서드를 반드시 오버라이딩하여 바디를 구현하기 때문에 메서드 호출이 가능하기 때문. – 상속관계이므로 추상클래스의 메서드와 자신의 메서드 모두 접근 가능함. |
14 | – 업캐스팅을 통한 다형성. – 추상클래스를 참조변수 타입으로 활용 가능. |
16 | – 공통 (상속된)메서드 → 오버라이딩 메서드 → 부모의 꿈을 자식이 이룸 → 추상클래스로 부터 상속 받은 추상메서드가 서브클래스에서 오버라이딩 하여 바디를 구현함. → 부모가 못 다 이룬 꿈 (추상메서드 바디구현)을 자식이 대신 (오버라이딩 하여) 이루어줌. |
20 | – 서브클래스에서 정의한 메서드 (멤버)이므로 업캐스팅 후 호출 불가. → 참조 영역 축소로 보이지 않는 메서드. → 접근하려면 다시 다운캐스팅 해야 함. |
EX2 ) 다형성 활용하기 |
• 슈퍼클래스 정의
– 슈퍼맨, 새, 비행기의 공통점 = 비행 가능.
– 공통점을 추출하여 상위클래스로 정의하되, 각 서브클래스에서 비행 기능을 반드시 구현하도록 강제성을 부여.
abstract class Flyer{ public abstract void takeOff(); public abstract void fly(); public abstract void land(); }
– 모든 날아다니는 것들에 대한 이름, 비행, 착륙 메서드 정의.
– 슈퍼클래스로 사용할 Flyer 클래스의 메서드들에는 실행할 코드가 불필요 (바디 불필요)하므로 추상메서드로 정의하고,
추상메서드를 포함하는 Flyer 클래스를 추상클래스로 정의.
• SuperMan 클래스 정의 — Flyer 상속
class SuperMan extends Flyer{ @Override public void takeOff() { System.out.println("SuperMan 이륙"); } @Override public void fly() { System.out.println("SuperMan 비행"); } @Override public void land() { System.out.println("SuperMan 착륙"); } }
– 슈퍼클래스 Flyer의 추상메서드 3개를 반드시 오버라이딩 해야 함.
→ 오버라이딩을 통해 실행 코드를 작성, 즉 바디를 구현함.
→ 이렇게 오버라이딩 된 메서드는 이제 호출 가능.
• Bird 클래스 정의 — Flyer 상속
class Bird extends Flyer{ @Override public void takeOff() { System.out.println("Bird 이륙"); } @Override public void fly() { System.out.println("Bird 비행"); } @Override public void land() { System.out.println("Bird 착륙"); } }
• AirPlane 클래스 정의 — Flyer 상속
class AirPlane extends Flyer{ @Override public void takeOff() { System.out.println("AirPlane 이륙"); } @Override public void fly() { System.out.println("AirPlane 비행"); } @Override public void land() { System.out.println("AirPlane 착륙"); } }
• 서브클래스의 인스턴스 생성
SuperMan s = new SuperMan(); s.takeOff(); s.fly(); s.land(); Bird b = new Bird(); b.takeOff(); b.fly(); b.land(); AirPlane a = new AirPlane(); a.takeOff(); a.fly(); a.land();
– Flyer 클래스 (추상 클래스)를 상속받은 서브클래스 SuperMan, Bird, AirPlane의 인스턴스를 생성함.
• 다형성 활용하기
– SuperMan, Bird, AirPlane → Flyer타입으로 업캐스팅하여 다형성 활용.
→ Flyer타입의 참조변수 (레퍼런스) 하나로 여러 개의 인스턴스를 모두 참조할 수 있음.
Flyer f; f = s; // Flyer f = new SuperMan();
– 슈퍼클래스의 참조변수를 먼저 선언하고,
부품을 갈아 끼워 넣듯이 서브클래스의 주소값 (인스턴스 & 참조변수)을 대입함.
→ 이미 위에서 SuperMan의 인스턴스를 생성했으므로 주소값을 가지고 있는 참조변수를 대입함.
f.takeOff(); f.fly(); f.land();
– SuperMan 클래스에서 오버라이딩 한 메서드들이 호출됨.
✓ 실행 결과
SuperMan 이륙
SuperMan 비행
SuperMan 착륙
f = b; f.takeOff(); f.fly(); f.land();
– 이번에는 슈퍼클래스의 참조변수에 Bird 클래스의 주소값 (인스턴스 & 참조변수)을 대입함.
– Bird 클래스에서 오버라이딩 한 메서드들이 호출됨.
✓ 실행 결과
Bird 이륙
Bird 비행
Bird 착륙
f = a; f.takeOff(); f.fly(); f.land();
– 같은 방식으로 슈퍼클래스의 참조변수에 AirPlane 클래스의 주소값 (인스턴스 & 참조변수)을 대입함.
– AirPlane 클래스에서 오버라이딩 한 메서드들이 호출됨.
✓ 실행 결과
AirPlane 이륙
AirPlane 비행
AirPlane 착륙
EX3 ) 서브클래스에서 추상메서드의 오버라이딩 분할하기 |
• 슈퍼클래스 정의
abstract class AbstractClass2{ // 추상메서드 정의 public abstract void method1(); public abstract void method2(); }
• 서브클래스 MiddleClass 정의
abstract class MiddleClass extends AbstractClass2{ @Override public void method1() { System.out.println("MiddleClass에서 구현한 method1()"); } }
– 추상메서드를 포함하는 추상클래스를 상속받는 서브클래스에서는 반드시 오버라이딩 해야 함.
– 상속받은 추상메서드 2개 중 하나만 구현한다면,
남은 하나의 추상메서드가 구현되지 않은 채 그대로 존재하므로 해당 서브클래스도 추상클래스로 선언해야 함.
• 서브클래스 SubClass2 정의
– 추상메서드를 모두 구현하지 않은 서브클래스 (추상클래스) MiddleClass를 상속받음.
class SubClass2 extends MiddleClass{ @Override public void method2() { System.out.println("SubClass2에서 구현한 method2()"); } }
– method1() 메서드는 MiddleClass에서 이미 구현되어 있으므로 오버라이딩 강제성이 없음.
– 여전히 강제성이 남아있는 method2() 메서드는 반드시 구현해야 함.
→ 할아버지가 못 이룬 꿈 아버지가 이루려고 했는데 다 못 이뤄서, 남은 꿈 내가 마저 이룸 ! ^.<—★
[ Test ] |
1. 전기차(ElectricCar)와 디젤차(DiselCar)의 공통적인 요소를 추상화하여 차량(Vehicle) 클래스에 정의.
2. 공통요소
– curX, curY : 현재 위치의 좌표를 저장하는 변수.
– reportPosition() : 연료공급지의 위치 출력.
– 출력형태 : "현재 위치" : curX, curY"
– addFuel() : 연료 공급 방법 출력.
ex ) 전기차 충전소에서 배터리 충전, 주요소에서 디젤 연료 공급.
• 슈퍼클래스 Vehicle 정의
abstract class Vehicle{ int curX, curY; public void reportPosition(int curX, int curY) { System.out.println("현재 위치 : " + curX + ", " + curY); } public abstract void addFuel(); }
– 차량마다 연료 공급 방법이 달라지므로 각 차량 클래스마다 오버라이딩 해야 함.
→ '무조건 오버라이딩' 해야 하므로 강제성 부여를 위해 추상메서드로 정의함.
– 해당 클래스는 추상메서드를 가지게 되었으므로 추상클래스가 되야 함.
• 서브클래스 ElectricCar 정의
class ElectricCar extends Vehicle{ @Override public void addFuel() { System.out.println("전기차 충전소에서 배터리 충전"); } }
• 서브클래스 DiselCar 정의
class DiselCar extends Vehicle{ int hi; @Override public void addFuel() { System.out.println("주유소에서 디젤 연료 공급"); } }
• 업캐스팅으로 다형성 활용하기
Vehicle vc = new ElectricCar(); vc.addFuel(); vc.reportPosition(3, 7); vc = new DiselCar(); vc.addFuel(); vc.reportPosition(10, 7); //vc.hi // 접근 불가 // 접근 가능 DiselCar d = (DiselCar) vc; d.addFuel(); d.hi = 0;
– 슈퍼클래스가 추상클래스이므로 인스턴스 생성 불가.
→ 서브클래스의 인스턴스를 생성하여 슈퍼클래스 타입으로 업캐스팅 후, 슈퍼클래스의 멤버에 접근하기.
→ 어떤 서브클래스의 인스턴스가 오냐에 따라 해당 서브클래스에서 오버라이딩 된 메서드가 호출됨.
– 업캐스팅으로 인해 서브클래스의 멤버에 접근 불가.
→ 다운캐스팅으로 DiselCar의 멤버에 접근 가능.
✓ 실행 결과
전기차 충전소에서 배터리 충전
현재 위치 : 3, 7
주유소에서 디젤 연료 공급
현재 위치 : 10, 7
주유소에서 디젤 연료 공급
'JAVA' 카테고리의 다른 글
인터페이스 (Interface) (0) | 2023.04.04 |
---|---|
상수 (Constant) (0) | 2023.04.04 |
동적 바인딩 / 다형성 (polymorphism) / 메서드에 다형성 활용 (0) | 2023.03.28 |
static 키워드 (static 멤버 / 메모리 할당 순서 / 싱글톤 디자인 패턴) (0) | 2023.03.14 |
this 키워드 (레퍼런스 / 생성자) (0) | 2023.03.12 |
- Total
- Today
- Yesterday
- 매개변수
- 원격저장소
- null
- 제어문
- 문자형
- 주석문
- 논리형
- DB
- 로컬저장소
- Method
- 출력문
- 다형성
- Git
- jsp
- github
- 오버라이딩
- mysql
- 단일행함수
- Dao
- javascript
- 데이터타입
- Object
- 숫자형
- 내장객체
- model2
- Java
- JSTL
- gitbash
- 인자
- 업캐스팅
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 28 | 29 | 30 |
31 |