2020. 6. 14. 12:46ㆍ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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
|
public class Ex {
public static void main(String[] args) {
/*
* < 생성자 정의 기본 문법 >
* [접근제한자] 클래스명 () {}
* => 메서드와 달리 리턴타입이 없으며, 생성자의 이름은 클래스명과 동일하게 작성
*
* < 상속에서의 생성자 >
* - 생성자는 상속되지 않는다
* => 생성자의 이름은 클래스 이름을 사용하므로,
* 상속받은 생성자는 부모클래스의 이름이 되어 생성자 규칙에 위배됨
* - 서브클래스의 인스턴스를 생성할 때에는, 자동으로 슈퍼클래스의 인스턴스를
* 먼저 생성한 후 서브클래스의 인스턴스가 생성됨
* => 서브클래스의 인스턴스 생성 시점에서 생성자를 호출하게 되면
* 슈퍼클래스의 인스턴스를 생성하기 위해 자동으로 슈퍼클래스의 생성자를 호출하게 됨
* (기본적으로는 슈퍼클래스의 파라미터가 없는 기본 생성자를 호출)
*/
// Parent 클래스 내에는 파라미터가 없는 생성자와, 파라미터가 있는 생성자 모두 존재함
// Parent p = new Parent("홍길동"); // 파라미터 생성자 호출
// Child 클래스는 Parent 클래스를 상속받아 정의한 서브클래스이지만
// 생성자는 상속되지 않으므로, 파라미터 생성자는 호출 불가
// Child c = new Child("홍길동"); // 오류 발생!
Child c = new Child();
}
}
class Parent {
String name;
// 파라미터가 없는 기본 생성자 정의
public Parent() {
System.out.println("Parent() 생성자 호출됨!");
}
// String 타입 name 을 파라미터로 전달받는 생성자 정의
public Parent(String name) {
this.name = name;
}
}
class Child extends Parent {
public Child() {
// 서브클래스 생성자 내에서 자동으로 슈퍼클래스의 생성자를 먼저 호출하게 됨
// 따라서, 슈퍼클래스 인스턴스 생성 후 슈퍼클래스 생성자 내의 코드를 실행한 뒤
// 다시 서브클래스의 생성자로 돌아와서 서브클래스 생성자 내의 코드를 실행
System.out.println("Child() 생성자 호출됨!");
}
}
public class Ex2 {
public static void main(String[] args) {
// Employee 클래스의 파라미터 2개 생성자 호출하여 인스턴스 생성
Employee emp = new Employee("홍길동", 2000);
System.out.println(emp.getEmployee());
System.out.println("--------------------------");
// Manager 클래스의 파라미터 3개 생성자 호출하여 인스턴스 생성
Manager man = new Manager("이순신", 4000, "개발팀");
System.out.println(man.getManager());
System.out.println("-------------------------");
// Engineer 클래스의 파라미터 3개 생성자 호출하여 인스턴스 생성
Engineer eng = new Engineer("강감찬", 3000, "자바");
System.out.println(eng.getEngineer());
System.out.println(eng.getEmployee());
}
}
class Employee {
String name; // 사원 이름
int salary; // 연봉
public Employee() {}
public Employee(String name, int salary) {
super();
this.name = name;
this.salary = salary;
}
// 사원이름과 연봉을 문자열로 결합하여 리턴하는 메서드 getEmployee() 를 정의
public String getEmployee() {
return name + ", " + salary;
}
}
// Employee 클래스를 상속받는 Manager 클래스 정의
class Manager extends Employee {
String depart; // 부서명
// 파라미터 3개(name, salary, depart)를 전달받아 초기화하는 생성자 정의
// => 슈퍼클래스인 Employee 클래스에 기본 생성자 Employee() 정의 필수!
public Manager(String name, int salary, String depart) {
this.name = name;
this.salary = salary;
this.depart = depart;
}
// 사원명, 연봉, 부서명을 문자열로 결합하여 리턴하는 getManager() 메서드 정의
public String getManager() {
// 멤버변수 3개를 직접 결합하는 방법
// return name + ", " + salary + ", " + depart;
// 슈퍼클래스의 메서드 getEmployee() 를 호출하여 사원명, 연봉을 리턴받은 뒤
// Manager 클래스의 depart 변수를 결합하여 리턴하는 방법 => 중복 제거
return getEmployee() + ", " + depart;
}
}
/*
* Employee 클래스를 상속받는 Engineer 클래스 정의
* => 멤버변수 : 기술(skill, 문자열)
* => 생성자 : 사원명, 연봉, 기술을 전달받아 초기화
* => 메서드 : 사원명, 연봉, 기술을 문자열로 결합하여 리턴하는 메서드 getEngineer() 정의
*/
class Engineer extends Employee {
String skill;
public Engineer(String name, int salary, String skill) {
this.name = name;
this.salary = salary;
this.skill = skill;
}
public String getEngineer() {
// return name + ", " + salary + ", " + skill;
return getEmployee() + ", " + skill;
}
}
public class Ex3 {
public static void main(String[] args) {
/*
* 메서드 오버라이딩(Method Overriding) = 메서드 재정의
* - 슈퍼클래스로부터 상속받은 메서드를 서브클래스에서 새롭게 재정의 하는 것(덮어씀)
* - 기존 슈퍼클래스의 메서드와 동일하게 생긴 메서드를 정의하게 되므로
* 서브클래스에서는 더 이상 슈퍼클래스의 메서드가 보이지 않고
* 자신이 오버라이딩 한 메서드만 보이게 됨(즉, 슈퍼클래스의 메서드는 은닉됨)
* - 슈퍼클래스의 메서드에 기능을 추가하는 등 메서드 내용 변경이 필요할 때 사용
*
* < 오버라이딩 규칙 >
* 1. 상속 관계 필수
* 2. 메서드 시그니쳐(메서드명, 리턴타입, 파라미터)가 일치해야함
* => 리턴타입은 상속관계에 있는 서브클래스 타입으로 변경은 가능함
* 3. 접근제한자는 같거나 넓은 범위로만 변경 가능함(= 좁아질 수 없다)
* 4. 예외 클래스의 범위는 좁은 범위로만 변경 가능함
* 5. static, final, private 제한자가 지정된 메서드는 오버라이딩 불가
*/
Child3 c = new Child3();
c.childPrn();
c.parentPrn();
Parent3 p = new Parent3();
p.parentPrn();
System.out.println("-------------");
SpiderMan s = new SpiderMan();
s.jump(); // Person 클래스의 jump() 메서드가 아닌 SpiderMan 클래스의 jump() 메서드 호출
}
}
class Parent3 {
public void parentPrn() {
System.out.println("슈퍼클래스의 parentPrn()");
}
public Object parentPrn2() {
System.out.println("슈퍼클래스의 parentPrn()");
return null;
}
}
class Child3 extends Parent3 {
public void childPrn() {
System.out.println("서브클래스의 childPrn()");
}
// 슈퍼클래스 Parent3 로부터 상속받은 parentPrn() 메서드 오버라이딩
public void parentPrn() {
System.out.println("서브클래스에서 오버라이딩 된 parentPrn()");
}
// 슈퍼클래스의 메서드 리턴타입보다 하위 타입의 리턴타입을 명시할 수 있다!
// => Object 타입을 리턴하는 메서드를 오버라이딩 할 경우 String 타입 리턴으로 변경 가능
public String parentPrn2() {
System.out.println("슈퍼클래스의 parentPrn()");
return null;
}
}
// ---------------------------------------
class Person {
public void eat() {
System.out.println("먹기!");
}
public void jump() {
System.out.println("Person 의 점프!");
}
}
// SpiderMan 클래스 정의
// jump() 메서드 오버라이딩
class SpiderMan extends Person {
// 오버라이딩 단축키 : Alt + Shift + S -> V
@Override
public void jump() { // Person 클래스의 jump() 메서드는 더 이상 보이지 않는다!
System.out.println("SpiderMan 의 점프!");
}
}
package p1;
public class Ex {
public static void main(String[] args) {
/*
* 접근제한자
* - 특정 멤버에 대한 접근 범위를 제한하는 키워드
* - 클래스, 메서드, 멤버변수에 사용 가능
*
* 1. public : 모든 클래스에서 접근 가능
* 2. protected : 같은 패키지 또는 패키지가 달라도 상속 관계인 서브클래스에서 접근 가능
* 3. default : 같은 패키지 내에서 접근 가능
* 4. private : 자신의 클래스 내에서만 접근 가능(외부 클래스에서 접근 불가)
*/
}
}
// Parent 클래스와 같은 패키지이며, 상속관계가 없는 클래스
class SamePackageSomeClass {
public void accessMember() {
// 상속관계가 없는 Parent 클래스에 접근하기 위해 Parent 클래스의 인스턴스 생성 필요
Parent p = new Parent();
p.publicVar = 10; // public(O) - 누구나 접근 가능
p.protectedVar = 10; // protected(O) - 상속 관계는 아니지만, 같은 패키지이므로 접근 가능
p.defaultVar = 10; // default(O) - 같은 패키지이므로 접근 가능
// p.privateVar = 10; // private(X) - 외부 클래스에서 접근 불가
}
}
// Parent 클래스와 같은 패키지이며, 상속관계에 있는 서브클래스
class SamePackageChildClass extends Parent {
public void accessMember() {
// 상속 관계의 서브클래스에서는 슈퍼클래스의 멤버에 참조변수 없이 접근 가능
publicVar = 10; // public(O) - 누구나 접근 가능
protectedVar = 10; // protected(O) - 상속 관계이고, 같은 패키지이므로 접근 가능
defaultVar = 10; // default(O) - 같은 패키지이므로 접근 가능
// privateVar = 10; // private(X) - 외부 클래스에서 접근 불가(서브클래스도 X)
}
}
package p1;
public class Parent {
public int publicVar;
protected int protectedVar;
int defaultVar;
private int privateVar;
public void accessMember() {
// 자신의 클래스 내에서는 모든 접근제한자에 상관없이 접근 가능
publicVar = 10;
protectedVar = 10;
defaultVar = 10;
privateVar = 10;
}
}
package p2;
import p1.Parent;
// 패키지가 다르지만, 상속 관계에 있는 서브클래스
public class OtherPackageChildClass extends Parent {
public void accessMember() {
// 상속 관계에 있으므로 참조변수 없이 접근 가능
publicVar = 10; // public(O) - 누구나 접근 가능
protectedVar = 10; // protected(O) - 패키지는 다르지만, 상속 관계이므로 접근 가능
// defaultVar = 10; // default(X) - 다른 패키지이므로 접근 불가
// privateVar = 10; // private(X) - 외부 클래스에서 접근 불가
// 주의! 상속관계에 있더라도 인스턴스를 생성하여 접근하게 되면
// 상속관계의 접근이 아닌 일반 클래스 관계로 취급됨
Parent p = new Parent();
p.publicVar = 10; // public(O) - 누구나 접근 가능
// p.protectedVar = 10; // protected(X) - 상속관계가 적용되지 않으므로, 다른 패키지 접근 불가
// p.defaultVar = 10; // default(X) - 다른 패키지이므로 접근 불가
// p.privateVar = 10; // private(X) - 외부 클래스에서 접근 불가
}
}
// 상속 관계가 없는 다른 패키지의 클래스
class OtherPackageSomeClass {
public void accessMember() {
// 상속관계가 없는 Parent 클래스에 접근하기 위해 Parent 클래스의 인스턴스 생성 필요
Parent p = new Parent();
p.publicVar = 10; // public(O) - 누구나 접근 가능
// p.protectedVar = 10; // protected(X) - 상속관계가 아니고, 다른 패키지이므로 접근 불가
// p.defaultVar = 10; // default(X) - 같은 패키지이므로 접근 가능
// p.privateVar = 10; // private(X) - 외부 클래스에서 접근 불가
}
}
|
cs |
저번에 배웠던 생성자를 상속에서 활용하는 방법과 상속에서의 연산과정, 상속에서의 메서드 오버 라이딩의 정의와 오버 라이딩 연산과정, 그리고 접근 제한자의 종류와 활용방안에 대해서 배워보았다. 생성자는 저번에 배웠기에 익숙했는데 상속에서 활용하는 것도 비슷해 보였다. 그저 연산과정 자체가 순서가 있다는 것을 알게 되었고 상속의 관계에 대해서 좀 더 명확하게 알게 되었다. 그리고 상속에서의 메서드 오버 라이딩에 대해서 배워보았는데 오버 라이딩 자체는 슈퍼클래스의 메서드를 서브 메서드에서 그대로 사용하는 것이지만 슈퍼클래스의 메서드를 덮어쓰기 하는 용도라는 것을 알게 되었다. 중복적으로 활용해야 하는 상황에서 아주 유용할 것 같아서 좀 더 복습에 신경을 써야 할 것 같다. 오버 라이딩을 위한 단축키도 배웠는데 Alt + Shift + S = V 이것이었다. 역시나 단축키로 뚝딱 만드니 간편하게 만들어지긴 하지만 내가 확실히 개념을 이해할 때까지는 좀 스스로 써보는 연습을 해야 할 것 같다. 그리고 접근 제한자에 대해서 배우게 되었는데 종류가 public, private, protected, defaulte 가 있었다. public과 private는 저번에 배웠기에 쉽게 이해가 되었고 protected는 패키지가 달라고 상속관계이면 사용 가능한 범위이고 defaulte는 무조건 같은 패키지에서만 활용 가능하다는 걸 알게 되었다. 헷갈리지 않게 좀 더 신경 써서 복습을 해서 보자마자 직관적으로 알 수 있게 되어야 할 것 같다.
'Java' 카테고리의 다른 글
Java - instanceof (0) | 2020.06.14 |
---|---|
Java - super(),업캐스팅,다운캐스팅 (0) | 2020.06.14 |
Java - 상속(inheritance),패키지활용 (0) | 2020.06.14 |
Java - static 키워드, 싱글톤디자인패턴 (0) | 2020.06.14 |
Java - this. 문법 (0) | 2020.06.14 |