추상(abstract)은 '미완성 딱지'와 같다고 보면 된다.
1) '미완성 딱지'가 붙은 클래스(abstract class) 는 '객체 생성'을 하지 못한다.
2) '미완성 딱지'가 붙은 메서드(abstract method) 를 가지고 있는 클래스는"반드시" 미완성 딱지(abstract)를 붙인다.
3) 미완성 메서드(abstract method)의 선언에는, 중괄호{ } 대신에 세미콜론(;)을 쓴다.
abstract 클래스나 메소드를 사용하기 위해서는 반드시 상속해서 사용하도록 강제하는 것이 abstract 이다.
즉 추상클래스는 상속을 강제하기 위한 것이며 부모클래스에서는 메소드의 틀만 정해놓고 그 메소드의 실제 동작방법은 상속받은 하위 클래스의 책임으로 위임하고 있다.
다음을 보면 추상(abstract)에 대해 간략히 알아 볼 수있다.
abstract class A {
public abstract int b();
public abstract int c(){sysout("Hello World")} // 에러 ①
public int d(){return 2;} // 추상 메소드가 아닌 메소드가 존재할 수 있음. ②
}
① 본체가 있는 메소드는 abstract 키워드를 가질 수 없다.
② 추상 클래스 내에는 추상 메소드가 아닌 메소드가 존재할 수 있다.
그리고 다음 코드를 보자.
abstract class A {
public abstract int b();
// public abstract int c(){sysout("Hello World")} // 에러
public int d(){return 2;} // 추상 메소드가 아닌 메소드가 존재할 수 있음.
}
class B extends A { // 추상클래스 A를 상속 ①
public int b() { // 추상메서드 b를 오버라이딩 ②
return 1;
}
}
① 추상클래스는 반드시 자식 클래스를 생성해 주어야 하므로 추상클래스 A를 상속받는 자식클래스 B를 생성해주었다.
② 추상메서드는 상속받은 클래스에서 오버라이딩을 해주어야 사용 가능하므로 추상클래스 A를 상속받는 자식클래스 B내의 메서드 b를 추상클래스 A내의 메서드 b로부터 오버라이딩 해주었다.
Ex 예제 1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package day4;
abstract class A5 {
void m1() { System.out.println("m1"); }
abstract void m2();
abstract void m3();
}
abstract class B5 extends A5 { // 추상클래스 A5을 상속하는 추상클래스 B5 생성
void m2() { System.out.println("m2"); } // A5의 추상메서드 m2를 오버라이딩
}
class C5 extends B5 { // 추상클래스 B5을 상속하는 추상클래스 C5 생성
void m3() { System.out.println("m3"); } // A5의 추상메서드 m3를 오버라이딩
}
public class Ex404 {
public static void main(String[] args) {
A5 obj = new C5(); // 다형성을 이용, 인스턴스 C5를 클래스 A5타입의 변수 obj에 대입
obj.m1();
obj.m2();
obj.m3();
}
}
|
cs |
결과
m1
m2
m3
줄8에서 추상클래스 A5를 상속하는 추상클래스 B5를 생성, 줄9에서 B5의 부모클래스인 추상클래스 A5의 추상메서드 m2()를 오버라이딩하였다.
줄11에서 추상클래스 B2를 상속하는 클래스 C5를 생성, 줄12에서 부모클래스인 추상클래스 B5의 부모클래스인 A5의 추상메서드 m3()를 오버라이딩하였다.
그리고 줄16에서 디형성을 이용해 C5인스턴스를 추상클래스 A5의 타입을 갖는 obj를 통해 생성해 주었고,
줄17~19에서 m1, m2, m3를 호출해주었다.
C5의 인스턴스이지만 타입을 상위클래스인 A5으로 하기에 m2, m3가 모두 호출되며, m2와 m3가 A5클래스 내에서 메서드의 정의를 제대로 해주지 않았지만 B5, C5에서 각각 m2와 m3를 오버라이딩 해주었기 때문에 우선순위에 의해 각각 B5, C5에서 메서드를 호출해주게 된다.
Ex 예제 2.
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
|
package abst;
abstract class Bank{
int balance; // 줄10에서 넘어온 balance값이 저장됨.
abstract int getBalance();
}
class ChildBank extends Bank {
ChildBank(int balance){ // 인스턴스객체에서 받아온 매개변수 값
this.balance = balance; // 줄4의 balance에 매개변수 값 저장
}
int getBalance() {
return balance;
}
}
public class Abstract_Bank {
public static void main(String[] args) {
Bank b1 = new ChildBank(100); // 매개변수 balance에 100이 담김.
Bank b2 = new ChildBank(150); // 매개변수 balance에 150이 담김.
System.out.println("잔액이 "+b1.getBalance()+"만원");
System.out.println("잔액이 "+b2.getBalance()+"만원");
}
}
|
cs |
결과
잔액이 100만원
잔액이 150만원
줄 20, 21에서 ChildBank 인스턴스를 추상클래스이자 부모클래스인 Bank타입으로 참조변수 b1 b2를 통해 선언해 주었고, 각 인스턴스의 매개변수를 입력해주었다.
줄20, 21에서 입력된 매개변수 값은 줄9의 int balance 값으로 받게되고, 해당 값은 줄10의 우항인 balance로 내려와 좌항인 this.balance를 통해 줄 4로 올라가 Bank 클래스의 변수 balance에 저장되게 된다.
따라서 줄22,23에서 b1의 getBanlce와 b2의 getBalance를 호출할 경우 각각 100. 150이 호출된다.
Ex 예제 3.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package abst;
abstract class Unit{ // 추상클래스이자 부모클래스 Unit
int x,y;
abstract void move(int x, int y);
abstract void stop();
}
class Marine extends Unit{ // 보병
void stimPack() {
System.out.println("stimpack.");
}void move(int x, int y){
System.out.println("보병이 이동함.");
System.out.println("가로로 "+ x + " 세로로 " + y + "이동.");
}void stop(){
System.out.println("보병이 멈춤.");
}
}
class Tank extends Unit{ // 탱크
void changeMode() {
System.out.println("changemode.");
}void move(int x, int y){
System.out.println("탱크가 이동함.");
System.out.println("가로로 "+ x + " 세로로 " + y + "이동.");
}void stop(){
System.out.println("탱크가 멈춤.");
}
}
class Dropship extends Unit { // 수송선
void load() {
System.out.println("load");
}void unload(){
System.out.println("unload");
}void move(int x, int y) {
System.out.println("수송선 이동함.");
System.out.println("가로로 "+ x + " 세로로 " + y + "이동.");
}void stop() {
System.out.println("수송선 멈춤.");
}
}
public class Abstract_Unit {
public static void main(String[] args) {
Marine obj1 = new Marine();
Tank obj2 = new Tank();
Dropship obj3 = new Dropship(); // 인스턴스 객체 생성
obj1.stimPack(); // Marin
obj1.move(10, 20);
obj1.stop();
System.out.println(); // 줄바꿈
obj2.changeMode(); // Tank
obj2.move(20, 20);
obj2.stop();
System.out.println(); // 줄바꿈
obj3.load(); // Dropship
obj3.unload();
obj3.move(40, 30);
obj3.stop();
}
}
|
cs |
결과
stimpack.
보병이 이동함.
가로로 10 세로로 20이동.
보병이 멈춤.
changemode.
탱크가 이동함.
가로로 20 세로로 20이동.
탱크가 멈춤.
load
unload
수송선 이동함.
가로로 40 세로로 30이동.
수송선 멈춤.
줄 9, 20, 31을 보면 추상클래스 Unit의 하위클래스인 Marine, Tank, Dropship을 각각 선언해주었고,
Unit의 추상메소드인 move와 stop을 각 클래스 내에서 오버라이딩 해주었다.
그리고 줄46~48에서 하위클래스의 인스턴스를 생성해주었고 줄50으로 내려가면 Marin 인스턴스 obj1의 메서드 stimPack을 호출하여 줄10으로 가 "stimpack"이 출력되었다.
줄51의 obj1의 move메서드에서는 매개변수로 각각 10, 20이 입력되었으며 이는 줄12로 가서 "보병이 이동함."이 출력된 후 가로 x와 세로 y 가 값으로 들어가 출력되었다.
줄52의 obj1의 stop메서드에서는 "보병이 멈춤."이 출력되었다.
줄56~58과 줄62~65의 인스턴스 obj2와 obj3 또한 같은 과정을 통해 결과가 출력되었다.
'Java > Java 기초문법' 카테고리의 다른 글
[JAVA 기초] 자바 추상클래스와 인터페이스의 차이점 (0) | 2021.04.09 |
---|---|
[JAVA 기초] 자바 인터페이스 (interface) (0) | 2021.04.09 |
[JAVA 기초] 자바 다형성(polymorphism) (0) | 2021.03.12 |
[JAVA 기초] 자바 제어자 (0) | 2021.03.12 |
[JAVA 기초] 자바 package와 import (0) | 2021.03.11 |
댓글