오늘의하루

[자바의 정석] 추상클래스 인터페이스 내부클래스 정리 본문

JAVA

[자바의 정석] 추상클래스 인터페이스 내부클래스 정리

오늘의하루_master 2022. 10. 19. 09:58

추상 클래스(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인터페이스를 구현하지 않았기 때문이다.
Comments