ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바의 정석] 추상클래스 인터페이스 내부클래스 정리
    JAVA 2022. 10. 19. 09:58
    728x90
    반응형

    추상 클래스(Abstract class)

    클래스를 설계도라고 하면 추상 클래스는 미완성된 설계도를 말하며 다른 클래스의 작성을 돕기 위하 목적으로 사용됩니다.

    • 추상 클래스는 추상 메서드를 포함하고 있는 클래스를 말합니다.
    • 일반 메서드는 추상 메서드를 호출할 수 있습니다.
    • 추상 클래스는 인스턴스를 생성할 수 없습니다.
    abstract class Player{ // 추상 클래스
        int currentPos;
        
        Player(){
            currentPos = 0;
        }
        
        abstract void play(int pos); // 추상 메서드
        abstract void stop(); // 추상 메서드
        
        void play(){ // 오버로딩
            play(currentPos); // 추상 메서드 호출
        }
    }

    추상 메서드(Abstract Method)

    선언부만 있으며 구현부가 없는 메서드를 말하며 꼭 필요하지만 자식 클래스마다 다르게 구현될 것으로 예상되는 경우에 사용됩니다.

    • 추상 클래스를 상속받은 자식 클래스는 추상 메서드를 모두 구현해야 사용 가능합니다.
    • 추상 메서드를 구현한다는 것은 오버 라이딩을 하는 것이기 때문에 오버 라이딩 규칙을 따라야 한다.
    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){/*내용생략*/}
        // 추상 메서드 stop을 구현하지 않았기 때문에 추상 클래스가된다.
    }

    추상 클래스의 작성

    여러 개의 클래스에 공통적으로 사용될 수 있는 부분을 뽑아서 추상 클래스로 작성하게 됩니다.

    // 클래스 예제
    class Marine{
        int x,y; // 공통 되는 부분
        void move(int x, int y){} // 공통 되는 부분
        void stop(){} // 공통 되는 부분
        void stimPack(){}
    }
    
    class Tank{
        int x,y; // 공통 되는 부분
        void move(int x, int y){} // 공통 되는 부분
        void stop(){} // 공통 되는 부분
        void changeMode(){}
    }
    
    class Dropship{
        int x,y; // 공통 되는 부분
        void move(int x, int y){} // 공통 되는 부분
        void stop(){} // 공통 되는 부분
        void load(){}
        void unload(){}
    }
    
    // 공통 되는 부분을 추상 클래스로 만든다.
    abstract class Unit{
        int x, int y
        abstract void move(int x, int y);
        void 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(){}
    }
    
    // 다형성을 이용해서 부모 타입의 참조변수로 자식 타입의 객체를 다룬다.
    Unit[] group = new Unit[4];
    group[0] = new Marine();
    group[1] = new Tank();
    group[2] = new Marine();
    group[3] = new Dropship();
    
    for(int i = 0; i < 4; i++){
        group[i].move(100,200);
        // 메서드가 중복되는 경우 실제 생성된 인스턴스에 있는 메서드를 호출하게 된다.
        // 그러므로 move는 추상 메서드를 호출하는게 아니다.
    }

    인터페이스(interface)

    인터페이스는 일종의 추상 클래스이며 실제로 구현된 것이 전혀 없는 기본 설계도이다.

    • 인터페이스에서는 추상 메서드, 디폴트 메서드, static 메서드, 상수만을 가질 수 있다.
    • 인스턴스를 생성할 수 없으며 클래스 작성에 도움을 줄 목적으로 사용된다.
    • 개발 시간을 단축할 수 있으며 표준화가 가능하다.
    • 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.

    인터페이스의 작성

    인터페이스의 멤버 중 추상 메서드와 상수의 경우 제어자를 생략할 수 있습니다.

    인터페이스의 모든 멤버 변수는 public static final이기 때문에 생략 가능하다.
    인터페이스의 모든 메서드는 public abstract이기 때문에 생략 가능하다.
    // 기본 작성 방법
    interface InterfaceName{
        public static final int NUMBER = 1;
        public abstract method(/* 매개변수 */);
    }
    
    // 예제
    interface PlayingCard{
        int SPADE = 4; // public static final 생략
        final int DIAMOND = 3; //public static 생략
        static int HEART = 2; // public final 생략
        int CLOVER = 1; // public static final 생략
        
        public abstract String getCardNumber(); // 추상 메서드
        String getCardKind(); // public abstract 생략
    }

    인터페이스의 상속

    인터페이스도 클래스처럼 상속이 가능하며 다중 상속이 허용된다.

    • 인터페이스는 Object 클래스와 같은 최고 조상이 없다.
    interface Movable{
        void move(int x, int y);
    }
    
    interface Attackable{
        void attack(Unit u);
    }
    
    interface Fightable extends Movable, Attackable{ } // 인터페이스 다중 상속

    인터페이스의 구현

    인터페이스를 구현한다는 것은 클래스를 상속받는 것과 같으며 상속 후 모든 추상 메서드를 구현하지 않으면 추상 클래스가 된다.

    • 인터페이스는 상속과 구현이 동시에 가능하다.
    // 기본 작성 방법
    class ClassName implements InterfaceName{
        // 인터페이스에 정의된 추상메서드를 구현해야한다.
    }
    
    // 예제
    interface Fightable{ // 추상 클래스
        void move(int x, int y); // 추상 메서드
        void attack(Unit u); // 추상 메서드
    }
    
    class Fighter implements Fightable{
        public void move(int x, int y){}
        // 만약 void move(){}를 하면 오버라이딩 규칙에 어긋나기 때문에 에러가 발생한다.
        public void attack(Unit u){}
    }
    
    abstract class Fighter2 implements Fightable{
        public void move(int x, int y){}
        // 추상 메서드 attack을 구현하지 않았기 때문에 추상클래스가 된다.
    }
    
    // 클래스 상속과 인터페이스 구현을 동시에 진행
    class Fighter3 extends Unit implements Fightable{
        public void move(int x, int y){}
        public void attack(Unit u){}
    }

    인터페이스를 이용한 다형성

    인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있다.

    • 매개변수로 인터페이스를 지정할 수 있다.
    • 메서드의 리턴 타입으로 인터페이스를 지정할 수 있다.
    // 인터페이스 타입의 참조변수로 인터페이스를 구현한 클래스의 인스턴스를 생성할 수 있다.
    class Fighter extends Unit implements Fightable{
        public void move(int x, int y){}
        // 인터페이스를 메서드의 매개변수 타입으로 지정할 수 있다.
        public void attack(Fightable f){}
        
        Fightable method(){
            // ....
            return new Fighter();
        }
    }
    
    Fighter f1 = new Fighter();
    Fightable f2 = new Fighter();

    디폴트 메서드

    인터페이스에서 디폴트 메서드와 static 메서드는 JDK 1.8 때 추가되었으며 디폴트 메서드는 인터페이스에 추가된 일반 메서드를 말합니다.

    interface MyInterface{
        void method(); // 추상 메서드
        default void newMethod(){} // 디폴트 메서드 (일반 메서드)
    }

    디폴트 메서드와 기존의 메서드가 충돌하는 경우는 아래와 같이 해결할 수 있다.

    경우 해결법
    여러 인터페이스의 디폴트 메서드 간의 충돌 클래스에서 디폴트 메서드를 오버라이딩해야한다.
    디폴트 메서드와 부모 클래스의 메서드 간의 충돌 디폴트 메서드는 무시된다.
    interface MyInterface{
        default method(){System.out.println("MyInterface method");}
    }
    class Parent{
        public method(){System.out.println("Parent class method");}
    }
    
    class Child extends Parent implements MyInterface{ }
    
    Child c = new Child();
    c.method(); // Parent class method (디폴트 메서드 무시된다.)

    인터페이스 예제 - 관계 맺어주기

    interface Repairable{} // 인터페이스
    
    class Unit{
        int hitPoint;
        final int MAX_HP;
        Unit(int hp){ // 생성자
            MAX_HP = hp; // 생성자로 상수 초기화
        }
    }
    
    class GroundUnit extends Unit{
        GroundUnit(int hp){
            super(hp); // Unit(int hp) 생성자 호출
        }
    }
    
    class Tank extends GroundUnit implements Repairable{
        Tank(){
            super(150); // GroundUnit(int hp) 생성자 호출
            hitPoint = MAX_HP;
        }
        public String toString(){return "Tank";}
    }
    
    class Marine extends GroundUnit{
        Marine(){
            super(40); // GroundUnit(int hp) 생성자 호출
            hitPoint = MAX_HP;
        }
        public String toString(){return "Marine";}
    }
    
    class SCV extends GroundUnit implements Repairable{
        SCV(){
            super(60);
            hitPoint = MAX_HP;
        }
        void repair(Repairable r){
            if(r instanceof Unit){
                Unit u = (Unit)r;
                while(u.hitPoint != u.MAX_HP){
                    u.hitPoint++;
                }
            }
        }
    }
    
    Tank tank = new Tank();
    Marine marine = new Marine();
    SCV scv = new SCV();
    
    scv.repair(tank);
    scv.repair(marine); // Error! Marine클래스는 Repairable인터페이스를 구현하지 않았기 때문이다.
    728x90
    반응형
Designed by Tistory.