[ CH05. 상속, 오버라이딩, package, 제어자, 다형성, 추상클래스, 인터페이스 ]
1. 상속
1.1 상속
- 정의
- 부모 클래스(슈퍼 클래스)에 만들어진 필드, 메소드를 자식 클래스(서브 클래스)가 물려받음
(생성자, 초기화블럭 제외)
- 상속을 통해 간결한 자식 클래스 작성 가능
- 공통부분은 부모클래스에서 관리, 개별 부분은 자식 클래스에서 관리
- 장점
- 클래스의 간결화 -> 멤버의 중복 작성 X
- 클래스 관리 용이 -> 클래스들의 계층적 분류
- 소프트웨어 생산성 향상 -> 클래스 재사용과 확장, 새로운 클래스 작성 속도 빠름 - 선언
- extends 키워드 사용
public class Person {
}
public class Student extends Person { // Person을 상속받는 클래스 Student 선언
}
public class StudentWorker extends Student { // Student를 상속받는 StudentWorker 선언
}
- 예제
class Point{
private int x,y; // 한 점을 구성하는 x, y 좌표
public void set(int x, int y) {
this.x = x; this.y= y;
}
public void showPoint() { // 점의 좌표 출력
System.out.println("("+x+"," + y + ")");
}
}
class ColorPoint extends Point{ // Point를 상속받는 colorPoint 선언
private String color; // 점의 색
public void setColor(String color) {
this.color = color;
}
public void showColorPoint() { // 컬러점의 좌표 출력
System.out.print(color);
showPoint(); // Point 클래스의 showPoint() 호출
}
}
public class ColorPointEx {
public static void main(String[] args) {
Point p = new Point(); // Point 객체 생성
p.set(1, 2); // Point 클래스의 set() 호출
p.showPoint();
ColorPoint cp = new ColorPoint(); // colorPoint 객체 생성
cp.set(1, 2); // Point 클래스의 set() 호출
cp.setColor("red"); // colorPoint 클래스의 setColor() 호출
cp.showColorPoint(); // 컬러의 좌표 춮력
}
}
// [ 출력 결과 ]
// (1, 2)
// red(3,4)
- 특징
- 다중 상속 X ( 자식 클래스가 여러 부모 클래스를 상속받는 것 X )
- 상속 횟수 무제한
- 상속의 최상위 조상 클래스: java.lang.Object 클래스
- 모든 클래스는 자바 컴파일러에 의해 Object클래스 상속이 자동으로 이루어짐 → 11개 메서드 상속 - 접근 지정자
- 슈퍼 클래스의 private 멤버
- 다른 모든 클래스에 접근 불허
- 클래스 내의 멤버들에게만 접근 허용
- 슈퍼 클래스의 디폴트 멤버
- 같은 패키지 내 모든 클래스에 접근 허용
- 슈퍼 클래스의 public 멤버
- 다른 모든 클래스에 접근 허용
- 슈퍼 클래스의 protected 멤버
- 같은 패키지 내의 모든 클래스 접근 허용
- 다른 패키지에 있어도 서브 클래스는 접근 허용
- 슈퍼 클래스와 서브 클래스의 생성자 간의 호출 및 실행
- new에 의해 서브 클래스의 객체가 생성될 때, 슈퍼 클래스의 생성자와 서브 클래스 생성자 모두 실행
- 호출 순서
- 서브 클래스 생성자 -> 실행 전 슈퍼 클래스 생성자
- 실행 순서
- 슈퍼 클래스의 생성자 -> 서브 클래스의 생성자
- 서브 클래스에서 슈퍼 클래스 생성자 선택
- 서브 클래스에서 슈퍼 클래스 생성자 하나를 선택함
- 서브 클래스에서 슈퍼 클래스 생성자를 선택 X -> 컴파일러가 자동으로 슈퍼 클래스의 기본 생성자 선택
- 서브 클래스에서 명시적으로 슈퍼 클래스의 생성자 선택하는 방법
- super() 이용
- super
- 서브 클래스에서 슈퍼 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조 변수
- 상속받은 멤버와 자신의 멤버가 중복 정의되어 구별해야 할 때 사용
- 인스턴스 메서드에서만 사용 O
- super()
- 서브 클래스에서 명시적으로 슈퍼 클래스의 생성자 선택 호출
- 인자를 이용하여 슈퍼 클래스의 생성자와 일치하는 생성자 호출
- Object클래스를 제외한 모든 클래스의 생성자 첫 줄에 this() 또는 super()를 호출해야 함
- 그렇지 않으면, 컴파일러가 자동으로 super();를 생성자의 첫 줄에 삽입
1.2 포함
- 정의
- 한 클래스의 멤버변수로 다른 클래스 선언
- 작은 단위의 클래스 먼저 만들고, 조합하여 하나의 커다란 클래스 생성
- 상속 VS 포함
- 각 클래스간의 관계를 파악하여 상속 또는 포함관계로 유기적 연결하게 작성하면 코드를 재사용함으로써 더 효율적인 코드 작성 가능
- 상속관계 : ~은 ~이다. (is-a)
- 포함관계 : ~은 ~를 가지고 있다. (has-a)
- 2개의 클래스를 다중 상속받고 싶은 상황에서, 단일 상속을 위해, 비중이 높은 클래스 하나만 상속, 나머지는 포함 관계로 작성
2. 메소드 오버라이딩(method overriding)
- 정의
- 슈퍼 클래스의 메소드를 서브 클래스에서 재정의
- 슈퍼 클래스의 메소드의 이름, 매개변수 타입 및 개수, 리턴 타입 등 모든 것 동일하게 작성
- 접근제어자 변경 O → 조상클래스의 메서드의 접근제어자와 같거나 더 넓은 범위의 접근제어자만 가능
- 조상클래스의 메서드보다 많은 수의 예외 선언 X. 조상클래스에 선언된 예외가 아닌 다른 예외는 안됨
- 동적 바인딩 발생
- 서브 클래스에 오버라이딩된 메소드가 무조건 실행되는 동적 바인딩


- 동적 바인딩
- 실행할 메소드를 실행 시(run time)에 결정
- 오버라이딩 메소드가 항상 호출

- 정적 바인딩
- 컴파일러는 super의 접근을 정적 바인딩으로 처리

- 오버라이딩 vs 오버로딩 예제
- Circle과 Triangle은 Shape이다. (상속관계)
- Circle은 Point를 가진다 (포함관계)
class DrawShape {
public static void main(String[] args) {
Point[] p = { new Point(100, 100),
new Point(140, 50),
new Point(200, 100)
};
Triangle t = new Triangle(p);
Circle c = new Circle(new Point(150, 150), 50);
t.draw(); // 삼각형을 그린다.
c.draw(); // 원을 그린다.
}
}
class Shape {
String color = "black";
void draw() {
System.out.printf("[color=%s]%n", color);
}
}
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point() {
this(0,0);
}
String getXY() {
return "("+x+","+y+")"; // x와 y의 값을 문자열로 반환
}
}
class Circle extends Shape {
Point center; // 원의 원점좌표
int r; // 반지름
Circle() {
this(new Point(0, 0), 100); // Circle(Point center, int r)를 호출
}
Circle(Point center, int r) {
this.center = center;
this.r = r;
}
void draw() { // 원을 그리는 대신에 원의 정보를 출력하도록 했다.
System.out.printf("[center=(%d, %d), r=%d, color=%s]%n", center.x, center.y, r, color);
}
}
class Triangle extends Shape {
Point[] p = new Point[3];
Triangle(Point[] p) {
this.p = p;
}
void draw() {
System.out.printf("[p1=%s, p2=%s, p3=%s, color=%s]%n", p[0].getXY(), p[1].getXY(), p[2].getXY(), color);
}
}

3. package와 import
3.1 패키지(package)
- 서로 관련된 클래스와 인터페이스의 묶음
- 물리적으로 폴더형태
- 서브패키지 가질 수 있으며, '.'로 구분
- 클래스의 실제 이름은 패키지명이 포함
ex) String 클래스의 실제 이름 : java.lang.String
3.2 패키지 선언
- 선언 형태 : package 패키지명;
- 패키지는 소스파일에 첫 번째 문장으로 단 한번 선언
- 모든 클래스는 하나의 패키지에 속하며, 패키지 미선언시 이름없는(unnamed) 패키지에 속함
- 하나의 소스파일에 둘 이상의 클래스 포함 → 같은 패키지
3.3 import문
- 사용할 클래스가 속한 패키지를 지정
- 클래스를 사용할 때 패키지명 생략
- java.lang 패키지의 클래스는 import 안해도 사용 O
3.4 import문의 선언
- 패키지문과 클래스 선언 사이에 선언
- import 선언 방법
- import문은 지정된 패키지에 포함된 클래스들만을 import, 서브패키지에 속하는 클래스들까지 import 하는 것 X
- import한 패키지에 같은 이름의 클래스 존재하는 경우 → 클래스 앞에 패키지명 붙여야 함
4. 제어자(modifiers)
4.1 제어자 개념
- 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미 부여
- 하나의 대상에 여러 개의 제어자 조합 O, 접근제어자는 단 하나만 사용
4.2 static
- 위치 : 멤버변수, 메서드, 초기화 블록
4.3 final
- 위치 : 클래스, 메서드, 멤버변수, 지역변수
- final이 붙은 변수는 상수 → 보통, 선언과 초기화 동시에 함, 인스턴스변수는 생성자에서 초기화 가능
4.4 abstract
- 위치 : 클래스, 메서드
4.5 접근 제어자
- 멤버, 클래스에 사용되며, 외부로부터의 접근 제한
- 클래스의 접근제어자 : public, default
- 멤버변수와 메서드 접근제어자 : public, protected, default, private
4.6 생성자의 접근제어자
- 생성자의 접근제어자는 클래스의 접근제어자와 일치
- 생성자에 접근제어자 사용 → 인스턴스 생성 제한 가능
4.7 제어자의 조합
- 메서드에 static과 abstract 함께 사용 X
- static 메서드는 구현부있는 메서드에서만 사용 가능 - 클래스에 abstract와 final 함께 사용 X
- abstract 메서드의 접근제어자가 private X
- 메서드에서 private과 final 함께 사용할 필요 X
5. 다형성(polymorphism)
5.1 다형성 정의
- 하나의 참조변수로 여러 타입의 객체 참조
- 부모타입의 참조변수로 자식타입의 객체 참조 O
자식타입의 참조변수로 부모타입의 객체 참조 X
5.2 업캐스팅(upcasting)
- 정의
- 서브 클래스 객체를 슈퍼 클래스 타입으로 타입 변환 - 특징
- 업캐스팅은 자동으로 타입 변환됨
- 객체 내에 슈퍼 클래스의 멤버만 접근 가능
class Person { … }
class Student extends Person { … }
Student s = new Student();
Person p = s; // 업캐스팅, 자동타입변환
5.3 다운캐스팅(downcasting)
- 정의
- 슈퍼 클래스 객체를 서브 클래스 타입으로 변환
- 개발자의 명시적 타입 변환 필요
5.4 instanceof 연산자
- 업캐스팅된 레퍼런스로 객체의 타입 판단 어려움 => instaceof 연산자 사용
- 정의
- 레퍼런스가 가리키는 객체의 타입 식별 - 사용법
- 객체 레퍼런스 instanceof 클래스 타입
- 연산 결과는 불린 값(true / false) - 예제
5.5 참조변수와 인스턴스변수의 연결
- 멤버변수 중복정의 ⇒ 참조변수의 타입에 따라 연결되는 멤버변수가 달라짐 (참조변수타입에 영향받음)
- 메서드 중복정의 ⇒ 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 메서드가 호출
(참조변수 타입에 영향 X)
5.6 매개변수의 다형성
- 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스 넘겨줄 수 있음
5.7 여러 종류의 객체를 하나의 배열로 다루기
- 조상타입의 배열에 자손들의 객체 담을 수 있음
6. 추상 클래스
6.1 추상 메서드(abstract method)
- 선언되어 있으나 구현되어 있지 않은 메소드, abstract로 선언
- 추상 메소드는 서브 클래스에서 오버라이딩하여 구현해야 함
public abstract String getName();
public abstract void setName(String s);
6.2 추상 클래스(abstract class)
- 추상 클래스(abstract class)의 2종류
1) 추상 메소드를 하나라도 가진 클래스
2) 추상 메소드가 하나도 없지만 abstract로 선언된 클래스
// 1) 추상 메소드를 포함하는 추상 클래스
abstract class Shape { // 추상 클래스 선언
public Shape() { }
public void paint() { draw(); }
abstract public void draw(); // 추상 메소드
}
// 2) 추상 메소드 없는 추상 클래스
abstract class MyComponent { // 추상 클래스 선언
String name;
public void load(String name) {
this.name = name;
}
}
- 추상 클래스는 객체를 생성 X
abstrct class Shape {
...
}
public class AbstractError {
public static void main(String [] args) {
Shape shape;
shape = new Shape(); // 컴파일 오류. 추상 클래스 Shape의 객체를 생성할 수 없다.
}
}
- 추상 클래스의 상속
1) 추상 클래스의 단순 상속
- 추상 클래스를 상속받아, 추상 메소드를 구현하지 않으면 추상 클래스 O
- 이러한 서브 클래스도 abstract로 선언
2) 추상 클래스 구현 상속
- 서브 클래스에서 슈퍼 클래스의 추상 메소드 구현(오버라이딩)
- 서브 클래스는 추상 클래스 X - 추상 메소드 구현 예시
public class GoodCalc extends Calculator {
@Override
public int add(int a, int b) { // 추상 메소드 구현
return a + b;
}
@Override
public int subtract(int a, int b) { // 추상 메소드 구현
return a - b;
}
@Override
public double average(int[] a) { // 추상 메소드 구현
double sum = 0;
for (int i = 0; i <a.length; i++)
sum += a[i];
return sum/a.length;
}
public static void main(String [] args) {
GoodCalc c = new GoodCalc();
System.out.println(c.add(2,3));
System.out.println(c.subtract(2,3));
System.out.println(c.average(new int [] { 2,3,4 }));
}
}
// [ 출력 결과 ]
// 5
// -1
// 3.0
7. 인터페이스
7.1 인터페이스 정의
- 클래스가 구현해야 할 메소드들이 선언되는 추상형
- 추상메서드와 상수만을 멤버로 가질 수 있음
7.2 인터페이스 선언
- interface 키워드로 선언
public interface SerialDriver{...}
7.3 인터페이스의 구성 요소들
- 상수
- public만 허용, public static final 생략 가능 - 추상 메소드
- public abstract 생략 가능 - default 메소드(java 8)
- 인터페이스에 코드가 작성된 메소드
- 인터페이스를 구현하는 클래스에 자동 상속
- public 접근 지정만 허용, public 생략 가능 - private 메소드(java 8)
- 인터페이스 내에 메소드 코드가 작성되어야 함
- 인터페이스 내에 있는 다른 메소드에 의해서만 호출 가능 - static 메소드(java 8)
- public, private 모두 지정 가능
- public 일 때, 생략 가능
7.4 인터페이스 특징
- 인터페이스의 객체 생성 불가
- 인터페이스 타입의 레퍼런스 변수 선언 가능
- 인터페이스 구현
- 인터페이스를 상속받는 클래스는 인터페이스의 모든 추상 메소드 반드시 구현 - 다른 인터페이스 상속 가능
- 인터페이스의 다중 상속 가능
- 인터페이스는 Object클래스와 같은 최고 조상 없음
// 오류: 인터페이스 객체 생성 불가
new PhoneInterface();
// 인터페이스의 레퍼런스 변수 선언 가능
PhoneInterface galaxy;
7.5 인터페이스 구현
- 인터페이스의 추상 메소드를 모두 구현한 클래스
- implements 키워드 사용
- 여러 개의 인터페이스 동시 구현 가능 (= 다중 인터페이스 구현)
- 예시
class SamsungPhone implements PhoneInterface { // 인터페이스 구현
// PhoneInterface의 모든 메소드 구현
public void sendCall() { System.out.println("띠리리리링"); }
public void receiveCall() { System.out.println("전화가 왔습니다."); }
// 메소드 추가 작성
public void flash() { System.out.println("전화기에 불이 켜졌습니다."); }
}
7.6 인터페이스 상속
- extends 키워드 이용
- 다중 인터페이스 상속 가능
- 상속과 구현 동시에 가능
// extends 키워드 이용
interface MobilePhoneInterface extends PhoneInterface {
void sendSMS(); // 새로운 추상 메소드 추가
void receiveSMS(); // 새로운 추상 메소드 추가
}
// 다중 인터페이스 상속
interface MP3Interface {
void play(); // 추상 메소드
void stop(); // 추상 메소드
}
interface MusicPhoneInterface extends MobilePhoneInterface, MP3Interface {
void playMP3RingTone(); // 새로운 추상 메소드 추가
}
// 상속과 구현 동시에 가능
class Phone extends MobilePhoneInterface implements MP3Interface{
void play(){};
void stop(){};
}
7.7 인터페이스를 이용한 다형성
- 서로 다르게 구현할 수 있는 기능들을 규격 선언 -> 클래스의 다형성 실현
- 인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스 참조 가능
- 인터페이스를 메서드의 매개변수 타입으로 지정 O
- 인터페이스를 메서드의 리턴타입으로 지정 O
7.8 추상 클래스 vs 인터페이스
- 유사점
- 객체 생성 X
- 상속을 위한 슈퍼 클래스로만 사용
- 클래스의 다형성 실현 - 차이점
8. 내부 클래스(inner class)
8.1 내부 클래스 정의
- 클래스 안에 선언된 클래스
- 특정 클래스 내에서만 주로 사용
- GUI어플리케이션(AWT, Swing)의 이벤트처리에 주로 사용
8.2 내부 클래스의 종류와 특징
- 내부 클래스의 종류는 변수의 선언위치에 따른 종류와 동일
8.3 내부 클래스의 제어자와 접근성
- static 클래스만 static 멤버를 정의 가능
- 내부 클래스도 외부 클래스의 멤버로 간주
- 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근 가능
- 내부클래스의 생성
8.4 익명 클래스(anonymous class)
- 이름이 없는 일회용 클래스, 단 하나의 객체만을 생성
class Inner{
public static void main(String[] args){
Button b = new Buttn("start");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("ActionEvent occurred!!");
}
} // 익명 클래스 끝
};
} // main 메서드 끝
} // Ineer 클래스 끝
- 익명 클래스의 클래스 파일 형태
- 익명 클래스는 이름 X ⇒ '외부 클래스명$숫자.class'형식으로 클래스 파일명 결정
[ 참조 ]
1. Java의 정석 3판 (지은이 : 남궁성)
2. 명품 JAVA Programming 개정 3판 (지은이 : 황기태, 김효수)
'JAVA' 카테고리의 다른 글
CH06. java.lang 패키지와 유용한 클래스 (0) | 2021.05.10 |
---|---|
[Tip] static 메서드의 오버라이딩 불가 (0) | 2021.05.07 |
CH04. 객체지향, 클래스와 객체, 변수와 메서드, 오버로딩, 생성자, this레퍼런스, 변수 초기화 (0) | 2021.04.29 |
CH03. 반복문과 배열 그리고 예외 처리 (0) | 2021.04.28 |
CH02. 변수, 연산자, 조건문 (0) | 2021.04.27 |
댓글