1) 상속
상속 : 기존 클래스를 재사용해서 새로운 클래스를 작성하는 것
class Child extends Parent { } ➔ Child는 Parent를 상속받는다.
클래스는 멤버들의 집합이며 자손 클래스는 조상 클래스의 모든 멤버를 상속받기 때문에 Child 클래스는 Parent 클래스의 멤버들을 포함한다.(생성자, 초기화블럭 제외)
포함 : 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
class Circle { Point c = new Point(); } ➔ Circle는 Point를 포함한다.
상속과 포함은 얼핏 보면 비슷하다.
그렇다면 상속관계를 맺어줄지, 포함관계를 맺어줄지 애매할 때는 어떻게 정할까?
➔ '~은 ~이다(is-a)'와 '~은 ~을 가지고 있다(has-a)'를 넣어서 문장을 만들어보면 된다.
원(Circle)은 점(Point)이다 - Circle is a Point ➔ 상속
원(Circle)은 점(Point)를 가지고 있다 - Circle has a Point ➔ 포함
위 문장보다는 밑에 문장이 더 옳다. 이럴 때는 상속이 아닌 포함관계를 맺어주면 된다.
Object 클래스는 모든 클래스 상속 계층도의 최상위에 있는 조상 클래스이다.
상속 받는 클래스가 없는 클래스들은 자동적으로 Object 클래스부터 상속받게 되며 이미 어떤 클래스로부터 상속을 받았더라도 조상 클래스를 따라 올라가다보면 결국 최상위 조상은 Object 클래스일 것이다.
2) 오버라이딩
오버라이딩 : 조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것
조상클래스의 메서드를 자손클래스가 오버라이딩 할 때,
1. 선언부(메서드 이름, 매개변수, 반환타입)가 조상 클래스의 메서드와 일치해야 한다.
2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
(좁은 것부터 public, protected, (default), private 순서) 즉, 조상 클래스가 protected이면 자손은 protected나 public이어야 한다. 대부분 같은 범위의 접근 제어자를 사용한다.)
3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
오버로딩 vs 오버라이딩
오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것
오버라이딩 : 상속받은 메서드의 내용을 변경하는 것
1
2
3
4
5
6
7
8
9
10
11
|
class Parent{
void parentMethod() {}
}
class Child extends Parent{
void parentMethod() {} //오버라이딩
void parentMethod(int i) {} //오버로딩
void childMethod() {}
void childMethod(int i) {} //오버로딩
}
|
|
|
cs |
참조변수 super, 조상의 생성자 super()
super : 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수 (this와 비슷한 용도)
super() : 조상의 생성자를 호출하는데 사용되는 생성자
(참고로 this()는 같은 클래스의 다른 생성자를 호출하는데 사용되는 생성자였다.)
밑에 코드에서 this.x = x, this.y = y가 아니라 super(x, y)를 사용했음을 주목하자. this.x, this.y를 통해 조상 클래스로부터 상속받은 x, y를 초기화해주어도 되지만 조상의 멤버는 조상의 생성자를 통해 초기화되도록 작성하는게 더 바람직하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class Ex7_4{
public static void main(String[] args){
Point3D p = new Point3D(1,2,3);
System.out.println("x=" + p.x + ",y=" + p.y + ",z=" + p.z);
}
}
class Point{
int x, y;
Point(int x, int y){
this.x = x;
this.y = x;
}
}
class Point3D extends Point{
int z;
Point3D(int x, int y, int z){
super(x,y);
this.z = z;
}
}
|
cs |
3) package 와 import
패키지 : 클래스의 묶음.
소스파일 맨 위에 package '패키지명:' 한 줄만 적어주면 되며 한 번만 선언된다.
import 문 : 소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다. 즉, 'java.util.Date today = new java.util.Dat();' 이런 식으로 계속 작성해줘야 하는데 너무 길고 불편하다. 그래서 import 문이 존재한다.
코드 상단 package문 다음에 그리고 클래스 선언문 이전에. 'import java.util.Date;'와 같이 선언해주면 'Date today = new Date();'로 간결해진다.
'import 패키지명.클래스명' 과 'import 패키지명.*' 은 성능상 차이가 전혀 없다!
import 문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import 문을 사용하면 static 멤버를 호출할 대 클래스 이름을 생략할 수 있다.
'JAVA' 카테고리의 다른 글
자바의 정석(기초편) - Ch6. 객체지향프로그래밍Ⅰ정리 (0) | 2022.07.25 |
---|