추상 클래스 (Abstract Class)

클래스를 설계도에 비유한다면, 추상 클래스는 미완성 설계도에 비유할 수 있다.

추상클래스는 인스턴스를 생성할 수 없고, 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
abstract class Player {    // 추상메서드
    abstract void play(int pos);    // 추상메서드 구현
    abstract void stop();    // 추상메서드 구현
}
 
class AudioPlayer extends Player {
    void play(int pos) { ... }     // 추상메서드 구현
    void stop() { ... }    // 추상 메서드 구현
}
 
abstract class AbstractPlayer extends Player {
    // 하나만 구현하길 원한다면 자손 클래스 역시 추상클래스로 지정해야 한다.
    void play(int pos) { ... }    // 추상메서드 구현
}
cs

같은 크기의 TV라도 기능의 차이에 따라 여러 종류의 모델이 있다. 

각각의 설계도를 따로 그리는 것보다는, 이들의 공통 부분만을 그린 미완성 설계도를 만들어 놓고

이 미완성 설계도를 이용해 각각의 설계도를 완성해나가는 것이 좋다.


사용 예제

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
// 추상클래스
abstract class Player {
    boolean pause;
    int currentPos;
 
    Player() {
        pause = false;
        currentPos = 0;
    }
 
    abstract void play(int pos);     // 추상메서드
    abstract void stop();    // 추상메서드
 
    void play() {
        play(currentPos);    // 추상메서드를 사용 가능
    }
 
    void pause() {
        if(pause) {
            pause = false;
            play(currentPos);
        }
        else {
            pause = true;
            stop();
        }
    }
}
 
// Player 클래스를 조상으로 하는 CDPlayer 클래스
class CDplayer extends Player {
    void play(int currentPos) { ... } // 추상메서드 구현
    
    void stop() { ... }    // 추상메서드 구현
 
    int currentTrack; // 추가로 정의된 멤버
 
    void nextTrack() { // 추가로 정의된 멤버
        currentTrack++;
        ...
    }
}
cs


즉, 추상 클래스는 사용자가 구체적인 내용을 생각하지 않고 사용할 수 있는 기능으로,

메서드가 실제로 어떻게 구현될지 몰라도 메서드의 선언부만 알고 있으면 사용하는 것이 가능하다.



추상화(Abstraction)

클래스 간의 공통점을 찾아내서 공통의 조상을 만드는 작업이다.

기존의 클래스의 공통부분을 뽑아서 조상 클래스를 만드는 것이라 할 수 있다.

구체화와 반대되는 의미로, 구체화는 상속을 통해 클래스를 구현하는 작업이다.


동작 방법이 달라지는 메소드는 추상 메소드로 만들어서 하위 클래스에서 구현하도록 하고 

모든 클래스의 공통분모의 경우에는 상위 클래스에 두어서, 코드의 중복을 없애고 유지보수의 편의성 등을 얻을 수 있다.





참고 도서: 자바의 정석 책



다형성 (Polymorphism)

하나의 객체가 여러 개의 자료형을 가질 수 있는 것을 말한다.

상속과 연관이 있으며, 조상 클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있다.

즉, 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 한다.



예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
class TV {
    boolean power;
    int channel;
 
    void power() { ... };
    void channelUp() { ... };
    void channelDown() { ... };
}
 
class CaptionTV extends TV {
    String text;
    void caption() { ... };
}
cs



1
Tv tv = new CaptionTv();
cs

Tv 클래스와 CaptionTv 클래스가 상속관계에 있을 경우, 

조상클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하는 것이 가능하다.


1
2
Tv tv = new CaptionTv();
CaptionTv ctv = new CaptionTv();
cs

tv 변수는 Tv 클래스에서 정의되지 않은 맴버인 text와 caption()을 사용할 수 없다.

tv와 ctv 모두 같은 타입의 인스턴스이지만, 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.


1
2
3
4
5
6
Tv tv = null;
CaptionTv ctv1 = new CaptionTv();
CaptionTv ctv2 = null;
 
tv = ctv1; // 형변환 생략가능 (up-casting)
ctv2 = (CaptionTv) tv;  // 형변환 생략불가 (Down-casting)
cs

Tv 타입의 tv를 자손인 CaptionTv 타입으로 변환하는 것은 참조변수가 다룰 수 있는 멤버의 개수를 늘리는 것이므로,

실제 인스턴스 멤버 개수보다 참조변수가 사용하는 멤버의 개수가 더 많아져 문제가 발생할 수 있기에 형변환을 생략하지 않는다.



instanceof 연산자

특정 객체가 특정 클래스의 객체인지를 조사할 때 사용되는 자바의 내장 키워드

instanceof 왼쪽에는 참조변수를, 오른쪽에는 클래스명이 피연산자로 위치하며, 연산의 결과로 true/false를 리턴한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyInstance {
    public static void main (String args[]) {
        FireEngine fe = new FireEngine();
    
        if (fe instanceof FireEngine) {
            System.out.println("FireEngine 인스턴스");
        }
        if (fe instanceof Car) {
            System.out.println("Car 인스턴스");
        }
        if (fe instanceof Object) {
            System.out.println("오브젝트 인스턴스");
        }
    }
}
 
class Car { ... }
 
class FireEngine extends Car { ... }
cs

결과

FireEngine 인스턴스

Car 인스턴스

오브젝트 인스턴스

즉, instanceof는 fe 객체가 FireEngine, Car, Object으로 만들어진 객체인가를 묻는 조건식이다. 



다형성은 메서드의 매개변수에도 적용된다.

1
2
3
4
5
6
7
8
9
10
11
12
class Product {
    int price, bonuspoint;
}
 
class Tv extends Product { ... }
class Computer extends Product { ... }
class Audio extends Product { ... }
 
class Buyer {
    int money = 1000;
    int bonuspoint = 0;
}
cs

위와 같은 코드가 있을 때, Buyer 클래스에 물건을 구입하는 메서드를 추가할 것이다.


1
2
3
4
5
6
7
8
9
10
11
void buy (TV tv){
    money = money - tv.price;
    bonuspoint = bonuspoint + tv.bonuspoint;
}
 
void buy (Computer computer){
    money = money - computer.price;
    bonuspoint = bonuspoint + computer.bonuspoint;
}
 
...
cs

Tv, Computer, Audio 각각의 buy의 메서드가 필요하고, 제품에 대한 종류가 늘어난다면 새로운 buy() 를 추가해야할 것이다.


1
2
3
4
5
6
7
8
9
10
void buy (Product p){
    money = money - p.price;
    bonuspoint = bonuspoint + p.bonuspoint;
}
 
Buyer b = new Buyer();
Tv tv = new Tv();
Computer computer = new Computer();
b.buy(tv);
b.buy(computer);
cs

다형성을 적용한다면 위와 같은 하나의 메서드로 간단히 처리할 수 있다.

Product 클래스의 자손타입의 참조변수면 어느 것이나 매개변수로 받아들일 수 있다.


즉, 하나의 타입으로 다양한 실행결과를 얻을 수 있으며, 코드 재사용성이 높아지고 유지보수에 용이하다.



다형성은 또 다른 말로 메서드나 클래스를 다양한 방법으로 동작하는 것을 말한다.

오버로딩, 오버라이딩, 인터페이스 등이 다형성을 이용한다.




참고 출처

- 자바의 정석 책

https://wikidocs.net/269



접근 제어자 (Access Modifier)

멤버나 클래스를 외부에서 접근하지 못하도록 제한하여, 클래스의 내부에 선언된 데이터를 보호한다.

접근제어자는 클래스, 멤버변수, 메서드, 생성자에 사용될 수 있다.


public: 접근 제한이 전혀 없다.

protected: 패키지와 관계없이 상속관계에 있는 자손클래스에서 접근이 가능하다.

default: 같은 패키지 내에서만 접근이 가능하다.

private: 같은 클래스 내에서만 접근이 가능하다.



캡슐화(Encapsulation)

비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해, 실제 구현내용 일부를 외부에 감추어 은닉한다.

캡슐화된 클래스 내부의 메서드(setter, getter)만을 통해 변수를 조작할 수있다.


클래스 내의 변수에 대해 수정 권한을 설정하여, 유지보수할 때의 오류를 최소화할 수 있다.

클래스 내부의 데이터 형태가 변경되어도 다른 객체에 영향을 주지 않아 독립성이 유지된다.

각 객체의 세부 내용은 알 필요가 없으므로 객체간의 결합도가 낮아진다.




참고 도서: 자바의 정석

'Java' 카테고리의 다른 글

추상 클래스 (Abstract Class) 와 추상화 (Abstraction)  (0) 2018.11.27
다형성 (Polymorphism)  (0) 2018.11.27
JVM (Java Virtual Machine) 개념과 JVM 메모리 구조  (0) 2018.11.27
생성자 (Constructor)  (0) 2018.11.27
상속 (Inheritance)  (0) 2018.11.27

+ Recent posts