Java - 추상화,final
2020. 6. 14. 16:32ㆍJava
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
public class Ex {
public static void main(String[] args) {
/*
* 추상메서드(abstract method)
* - 메서드 바디(= 구현부 {})가 없는 메서드
* - 메서드 리턴타입 앞에 abstract 키워드를 사용하며
* 구현부{} 대신 세미콜론(;)을 명시
* - 메서드의 실행할 코드 부분인 구현부가 없으므로 외부에서 호출되면 안되는 메서드
*
* < 추상메서드 정의 기본 문법 >
* [제한자] abstract 리턴타입 메서드명([파라미터...]);
*
* 추상클래스(abstract class)
* - 객체 생성이 불가능한 클래스(= 미완성 클래스)
* => 추상메서드가 호출되면 안되기 때문에 인스턴스 생성을 못하도록 차단
* - 추상메서드를 포함하는 클래스는 반드시 추상클래스로 정의되어야 함
* => 단, 모든 추상클래스가 추상메서드를 포함하는 것은 아니다!
* - 추상클래스는 추상메서드, 일반메서드, 생성자, 인스턴스 변수 등을 가질 수 있다.
* - 인스턴스 생성은 불가능하지만, 상속은 가능하며, 다형성 활용도 가능
* - 추상클래스를 상속받는 서브클래스에서는 반드시 추상클래스 내의
* 추상메서드에 대한 오버라이딩을 수행해야함 => 오버라이딩 하지 않을 경우 상속 불가
* => 이 때, 상속받은 서브클래스를 추상클래스로 정의하면 오버라이딩 생략 가능
* 단, 또 다른 서브클래스를 생성하여 언젠가는 오버라이딩을 해야한다!
* - 추상메서드에 대한 구현을 강제함으로써 코드의 강제성 및 통일성을 제공
*
* < 추상클래스 정의 기본 문법 >
* [제한자] abstract class 클래스명 {
* // 인스턴스 변수
* // 생성자
* // 추상메서드
* // 일반메서드
* }
*/
// 추상클래스는 인스턴스 생성이 불가능하므로 컴파일 에러 발생!
// AbstractClass ac = new AbstractClass();
// 추상클래스를 상속받아 정의한 서브클래스의 인스턴스를 생성하여 사용해야함
SubClass sc = new SubClass();
sc.normalMethod();
sc.abstractMethod();
// 추상클래스는 레퍼런스변수의 타입으로 사용할 수 있음 = 다형성 활용 가능
// => 업캐스팅 후 오버라이딩 된 추상메서드도 호출 가능함
AbstractClass ac = sc;
ac.normalMethod();
ac.abstractMethod();
}
}
abstract class AbstractClass {
int num; // 인스턴스 변수
public AbstractClass() { // 생성자
num = 0;
}
public void normalMethod() { // 일반 메서드
System.out.println("추상클래스의 일반 메서드!");
}
// 추상메서드 정의 => 이 메서드를 포함하는 클래스는 반드시 추상클래스로 정의해야한다!
public abstract void abstractMethod();
}
// AbstractClass 를 상속받는 SubClass 정의
class SubClass extends AbstractClass {
// 추상메서드가 포함된 추상클래스를 상속받는 서브클래스에서는
// 반드시 추상메서드를 오버라이딩하여 메서드 바디{} 를 구현해야한다!
// => 오버라이딩 하지 않을 경우 오류 발생하므로, 오버라이딩 하거나 추상클래스로 선언 필요
@Override
public void abstractMethod() {
System.out.println("서브클래스에서 오버라이딩 된 추상메서드!");
}
}
// 추상클래스를 상속받아 추상메서드를 오버라이딩하지 않는 서브클래스 정의
abstract class AbstractSubClass extends AbstractClass { // abstract 키워드 필요
}
// => 여전히 추상메서드가 존재하므로 인스턴스 생성이 불가능
// 따라서, AbstractSubClass 를 상속받는 다른 서브클래스를 정의하여 추상메서드 구현 필요
class ImplementsSubClass extends AbstractSubClass {
@Override
public void abstractMethod() {
// TODO Auto-generated method stub
}
}
public class Ex2 {
public static void main(String[] args) {
/*
* final 키워드
* - 변경의 마지막이라는 의미를 부여함
* - 클래스, 메서드, 변수에 사용 가능
*
* 1) final 변수 : 값 변경 금지 => 저장되어 있는 값만 사용 가능 = 상수
* => 일반 변수와 구별하기 위해 이름을 보통 대문자 사용(MAX_NUM)
* 2) final 메서드 : 메서드 변경 금지 = 메서드 오버라이딩 금지
* => 단, 상속받아 사용은 가능
* 3) final 클래스 : 클래스 변경 금지 = 상속 금지
* => 단, 인스턴스 생성을 통해 사용은 가능
* ex) String 클래스, Math 클래스(인스턴스 생성 불가) 등
*/
String str = new String(); // final 클래스인 String 클래스의 인스턴스 생성 가능
}
}
// 1. 변수에 final 키워드를 사용할 경우
class FinalVariable {
final int num = 10; // 상수 = 값 변경 불가
public void changeNum() {
// num = 99; // final 키워드가 붙은 변수(= 상수)는 값을 변경할 수 없다!
}
public void getNum() {
System.out.println(num); // 기존 값을 사용할 수는 있다!
}
}
// ------------------------------------------------------------
// 2. 메서드에 final 키워드를 사용할 경우
class FinalMethod {
public final void method() { // final 메서드 = 오버라이딩 불가
System.out.println("슈퍼클래스에서 정의한 메서드!");
}
public void method2() {} // 일반 메서드 = 오버라이딩 가능
}
class SubFinalMethod extends FinalMethod {
// final 메서드를 오버라이딩 할 수 없기 때문에 오류 발생!
// @Override
// public void method() {
// System.out.println("서브클래스에서 오버라이딩 된 메서드!");
// }
// 일반메서드는 오버라이딩이 가능하므로 오류 발생 X
@Override
public void method2() {}
}
// ------------------------------------------------------------
// 3. 클래스에 final 키워드를 사용할 경우
final class FinalClass { // final 클래스 = 상속 금지
int num = 10; // 상수가 아니므로 인스턴스 생성 후 값 변경은 가능하다!
public void method() {
System.out.println("슈퍼클래스에서 정의한 메서드!");
}
public void method2() {}
}
//class SubFinalClass extends FinalClass {} // final 클래스를 상속받을 경우 오류 발생!
class SubFinalClass {
FinalClass fc = new FinalClass(); // final 클래스의 인스턴스를 생성해서 사용할 수는 있다!
public void method() {
fc.num = 99; // final 클래스 내의 인스턴스 변수 값 변경은 가능
}
}
// -----------------
// final 클래스의 대표적인 예
//class A extends String {} // String 클래스는 final 클래스이므로 상속 불가
//
//class B extends Math {} // Math 클래스 역시 final 클래스이므로 상속 불가
public class Test {
public static void main(String[] args) {
// 슈퍼클래스인 Vehicle 타입 배열 선언 및 DieselSUV, ElectricCar, LpgCar 인스턴스 저장
Vehicle[] vehicles = {new DieselSUV(), new ElectricCar(), new LpgCar()}; // 업캐스팅
for(Vehicle v : vehicles) {
v.reportPosition();
v.addFuel();
}
}
}
// 상속 관계에서 서브클래스가 슈퍼클래스의 특정 메서드를 반드시 오버라이딩 하도록 강제하려면
// 슈퍼클래스에서 해당 메서드를 추상메서드로 정의해야한다. 또한 그 클래스는 추상클래스가 되어야함
abstract class Vehicle {
private int curX, curY;
public void reportPosition() {
System.out.println("현재 위치 : " + curX + ", " + curY);
}
public abstract void addFuel(); // 추상메서드
}
class DieselSUV extends Vehicle {
@Override
public void addFuel() {
System.out.println("주유소에서 디젤 연료 공급!");
}
}
class ElectricCar extends Vehicle {
@Override
public void addFuel() {
System.out.println("전기차 충전소에서 배터리 충전!");
}
}
class LpgCar extends Vehicle {
// // 오버라이딩을 하지 않은 채 별도의 메서드만 정의하면 컴파일에러가 발생하므로 실수 방지
// public void addLpg() {}
@Override
public void addFuel() {
System.out.println("LPG 충전소에서 LPG 가스 충전!");
}
}
// -------------------- 일반 클래스를 사용하여 상속할 경우의 문제점 ---------------
//class Vehicle {
// private int curX, curY;
//
// public void reportPosition() {
// System.out.println("현재 위치 : " + curX + ", " + curY);
// }
//
// public void addFuel() {
// System.out.println("연료 공급!");
// }
//}
//
//class DieselSUV extends Vehicle {
// // 상속받은 멤버 중 다른 기능을 수행하는 addFuel() 메서드 오버라이딩
// @Override
// public void addFuel() {
// System.out.println("주유소에서 디젤 연료 공급!");
// }
//}
//
//class ElectricCar extends Vehicle {
// // 상속받은 멤버 중 다른 기능을 수행하는 addFuel() 메서드 오버라이딩
// @Override
// public void addFuel() {
// System.out.println("전기차 충전소에서 배터리 충전!");
// }
//}
//class LpgCar extends Vehicle {
// // 슈퍼클래스 Vehicle 클래스를 상속받을 때 메서드 오버라이딩이 필수가 아니므로
// // addFuel() 메서드 오버라이딩을 수행하지 않고 다른 메서드만 정의해도 됨
// // => 단, 업캐스팅을 통해 Vehicle 타입으로 인스턴스를 관리할 경우
// // addFuel() 메서드가 호출되면 슈퍼클래스인 Vehicle 의 addFuel() 메서드가 호출되게 됨
// public void addLpg() {
// System.out.println("LPG 충전소에서 LPG 가스 충전!");
// }
//
//}
|
cs |
추상화라는 개념을 배워보았는데 객체지향 프로그램에서 상속에 이어 두 번째 큰 특성이었다. 클래스, 메서드를 추상화시켜 상속과 오버 라이딩에 강제성을 부여해 목적에 맞게 꼭 사용해야 하는 클래스나 메서드를 정의해서 사용을 강제하는 문법이었는데 마찬가지로 개념 자체는 어렵지 않았다. 메서드를 추상화시켜야 한다면 클래스도 마찬가지로 추상화를 시켜줘야 하고 상속을 받더라도 아무것도 정의하지 않고 다음 클래스에게 오버 라이딩을 떠넘길 수도 있고 여러 가지로 활용이 많이 되는 거 같아서 복습이 철저히 필요할 것 같다. 그리고 final 상수에 대해서도 배웠는데 클래스, 메서드, 변수에 final을 붙여주면 값을 변경하지 못하게 고정시켜주는 문법을 배웠다. 상속은 가능하게 가능성을 열어두지만 값 자체의 변경을 가하지는 못하고 그 값을 참조하여 사용이 가능하게 해주는 것이었는데 다른 곳에 의미 있게 쓰일 거 같으니 잊어 먹지 않게 계속 알아 둬봐야 하겠다.
'Java' 카테고리의 다른 글
Java - 인터페이스, 마커(Marker) (0) | 2020.06.14 |
---|---|
Java - 상수,인터페이스,implements (0) | 2020.06.14 |
Java - instanceof (0) | 2020.06.14 |
Java - super(),업캐스팅,다운캐스팅 (0) | 2020.06.14 |
Java - 상속에서의 생성자, 메서드오버라이딩,접근제한자 (0) | 2020.06.14 |