JAVA

자바의 정석(기초편) -ch7. 객체지향프로그래밍 Ⅱ-(3)

광터틀 2022. 7. 30. 14:56

6) 추상클래스

추상클래스 : 미완성 설계도. 인스턴스 생성 불가하다. 상속을 통해 자손클래스에 의해서 완성된다.

 

ex) TV는 기능의 차이에 따라 여러 종류의 모델이 있지만, 이들의 설계도는 아마 90%는 동일할 것이다. 서로 다른 세 개의 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
abstract class Unit{
    int x, y;
    abstract void move(int x, int y);
        //move메서드는 지상유닛이냐 공중유닛이냐에 따라 메서드가 다르다.
        //따라서 move메서드를 추상적으로 짜놓고 각각 유닛클래스에서 구현한다.
    void stop(){
        //현재 위치에 정지한드는 코드
        //유닛이 무엇이든 stop메서드는 선언부와 구현부 모두 똑같을 것이다.
        //따라서 추상메서드가 아닌 일반메서드로 짠다.
    }
}
 
class Marine  extends Unit{
    void move(int x, int y){
        //지정된 위치로 이동한다는 코드
    }
    void stimPack(){
        //스팀팩 사용한다는 코드
    }
}
 
class Tank extends Unit{
    void move(int x, int y){
        //지정된 위치로 이동한다는 코드
    }
    void changeMode(){
        //공격모드를 변환한다는 코드
    }
}
 
class Dropship extends Unit{
    void move(int x, int y){
        //지정된 위치로 이동한다는 코드
    }
    void load(){
        //선택된 대상을 태우는 코드
    }
    void unload(){
        //선택된 대상을 내리는 코드
    }
}
cs

 

7) 인터페이스

인터페이스 : 일종의 추상클래스

인터페이스는 추상클래스보다 추상화정도가 높아서 추상화클래스와는 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만 멤버로 가질 수 있다.


추상클래스 vs 인터페이스

추상클래스 : 부분적으로만 완성된 미완성 설계도

인터페이스 : 구현된 것은 아무것도 없고 밑그림만 그려져 있는 기본 설계도


<인터페이스 멤버의 제약사항>

모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다

모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다

단, static 메서드와 디폴트 메서드는 예외(JDK 1.8부터)


구현을 위한 상속 정의할 때

클래스 extends 

인터페이스 ➔ implements


리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인터페이스를 반환한다는 것이다.


디폴트 메서드 : 인터페이스가 변경소요가 있어서 메서드를 추가해야할 경우, 인터페이스를 구현한 모든 클래스들에 새로 추가된 메서드를 추가로 구현해야한다. 이는 보통 큰 일이 아니기에 디폴트 메서드를 이용하면 된다.

추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 대문에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다.

 

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
class Ex7_11{
    public static void main(String[] args){
        Child3 c = new Child3();
        c.method1();
        c.method2();
        MyInterFace.staticMethod();
        MyInterface2.staticMethod();
    }
}
 
class Child3 extends Parent3 implements MyInterface, MyInterface2{
    public void method1(){
        System.out.println("method1() in Child3");
    }
    /*
    MyInterface, MyInterface2를 둘 다 상속받아 구현하는 클래스이다.
    두 인터페이스에 모두 method1()이 있어서 충동되므로 오버라이딩해야한다.
    그래서 Child3에 method1() 메서드가 오버라이딩 된 것.
    */
}
 
class Parent3{
    public void method2(){
        System.out.println("method2() in Parent3");
        /*Child3 입장에서는 Parent3는 조상클래스, MyInterface는 디폴트 클래스다.
        조상클래스, 디폴트 클래스에 모두 method2()가 있을 때는 조상클래스가 상속, 디폴트클래스는 무시
        따라서 Ex7_11클래스의 메인메서드에서 c.method2()를 했을 때 Parent3의 method2()가 실행된다.
        */
        
    }
}
 
interface MyInterface{
    default void method1(){
        System.out.println("method1() in MyInterface");
    }
    default void method2(){
        System.out.println("method2() in MyInterface");
    }
    static void staticMethod(){
        System.out.println("staticMethod() in MyInterface");
    }
}
 
interface MyInterface2{
    default void method1(){
        System.out.println("method1() in MyInterface2");
    }
    static void staticMethod(){
        System.out.println("staticMethod() in MyInterface2");
    }
}
cs

8) 내부클래스

내부클래스는 클래스 내에 선언된 클래스이다.

내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있으며 코드의 복잡성을 줄일 수 있다.(캡슐화)

 

밑에 코드에서 볼 수 있듯 내부클래스는 선언 위치에 따라서 인스턴스클래스, 스태틱클래스, 지역클래스, 익명클래스로 구분된다. (변수가 선언위치에 따라 구분되는 것과 비슷)

1
2
3
4
5
6
7
8
class Outer{
    class InstanceInner{ }
    static class StaticInner{ }
    
    void MyMethod(){
        class LocalInner{ }
    }
}
cs

내부 클래스 중에서 스태틱 클래스만 static 멤버를 가질 수 있다. 다만, final static은 상수이므로 항상 가능하다.

인스턴스클래스는 외부클래스, 스태틱클래스의 인스턴스멤버를 객체생성 없이 사용할 수 있지만 스태틱 클래스는 외부 클래스, 스태틱클래스의 인스턴스멤버를 객체생성 없이 사용할 수 없다.

 

익명클래스 : 선언과 객체 생성을 동시에 하기 때문에 한번만 사용될 수 있고 하나의 객체만을 위한 일회용 클래스이다.

이름이 없으므로 생성자도 가질 수 없으며 조상클래스 혹은 구현하려는 인터페이스 이름을 사용해서 정의하기 때문에 단 하나의 클래스르 ㄹ상속받거나 단 하나의 인터페이스만 구현할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.awt.*;
import java.awt.event.*;
 
class Ex7_19{
    public static void main(String[] args){
        Button b = new Button("Start");
        //new 조상클래스이름 or 구현인터페이스이름으로 익명클래스 시작
        b.addActionListener(new ActionListener(){ 
                public void actionPerformed(ActionEvent e){
                    System.out.println("ActionEvent occurred!!!");
                }
            }//익명 클래스 끝
        );
    }
}
cs