ꎀ늬 메뉎

Partially Committed

[CH07] 객첎지향프로귞래밍4 (OOP) 볞묞

💻 Study !/JAVA

[CH07] 객첎지향프로귞래밍4 (OOP)

WonderJay 2022. 8. 2. 17:30
728x90
반응형
SMALL

볞 포슀팅은 자바의 정석 교재륌 공부하며, 간닚히 정늬/Ʞ록 용도로 작성하였습니닀. 혹여, 잘못된 낎용읎 있닀멎 지적핎죌시멎 감사하겠습니닀.

 

 


1. 추상 큎래슀(Abstract class)

[추상큎래슀란?]

추상 큎래슀(Abstract class) 는 추상 메서드(Abstract method)륌 포핚하고 있는 큎래슀로, 읞슀턎슀륌 생성할 수 없고 였로지 상속을 통핎서만 완성읎 가능하닀. 킀워드 abstract ë¥Œ 앞에 붙여 완성할 수 있윌며, 추상 메서드륌 포핚하고 있닀는 것 왞에는 음반 큎래슀와 완전히 동음하닀.

 

[추상메서드란?]

추상 메서드는 메서드의 선얞부만 구현된 것을 의믞하며, 자섞한 구현/동작은 상속받은 큎래슀에 따띌서 달띌진닀. abstract void paly(int pos); ì™€ 같읎 ì„ ì–ží•  수 있윌며, 상속받은 큎래슀에서 자섞히 구현한닀.

 

[추상큎래슀의 작성]

abstract class Player{
    boolean pause;
    int currentPos;

    Player(){
        pause = false;
        currentPos = 0;
    }
    abstract void play(int pos);
    // abstract method
    abstract void stop();
    void play(){
        play(currentPos);
    }
    void pause(){
        if(pause)
        {
            pause = false;
            play(currentPos);
        }
        else {
            pause = true;
            stop();
        }
    }
}

위와 같읎 작성된 추상 큎래슀가 있닀. 읎륌 상속받은 CDplayer 큎래슀는 아래와 같읎 구현할 수 있닀.

class CDPlayer extends Player {
    void play(int currentPos) {
        /* */
    }

    void stop() {
        /* */
    }

    int currentTrack;

    void nextTrack() {
        currentTrack++;
    }

    void preTrack() {
        if (currentTrack > 1) {
            currentTrack--;
        }
    }
}

추상 메서드는 상속받는 큎래슀에서 구현핎쀄 수 있닀. abstract 킀워드륌 사용하지 않고 귞냥 빈 몞통을 만듀얎 놓아도 사싀 동음하지만, 굳읎 abstract 킀워드로 명시하는 것은 자손 큎래슀륌 작성할 때 프로귞래뚞가 추상 메서드임을 읞지하고 낎용을 직접 구현핎죌얎알 한닀는 것을 놓치지 않을 수 있Ʞ 때묞음 것읎닀.

 

아래의 큎래슀에서 공통된 부분을 뜑아낎얎 추상 큎래슀로 만듀 수 있닀.

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(){}
}

 

 ìœ„는 각각 move, stop 메소드와 x, y 변수가 공통적윌로 듀얎가있윌며, 읎러한 겜우에는 윔드륌 쀑복핎서 작성하Ʞ 볎닀는 추상 큎래슀륌 정의핎서 조상 큎래슀로 만듀얎죌멎 윔드가 볎닀 정돈될 수 있닀. 공통된 부분을 가지는 추상 큎래슀륌 Unit 윌로 정의하고 상속받도록 하자. 공통적윌로 듀얎가는 메소드륌 추상 메소드로 정의하고, 각각의 자손 큎래슀에서 구첎적윌로 구현부륌 작성핎죌멎 된닀.

 

abstract class Unit{
        int x,y;
        void move(int x,int y){}
        void stop(){}
}
class Marine{
    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(){}
}

ㄷ Unit 큎래슀타입의 찞조변수 배엎을 읎용하여, 서로 닀륞 종류의 읞슀턎슀륌 붂얎서 한번에 닀룰 수 있닀.

class source{
    public static void main(String[] args) {
        Unit[] group = new Unit[4];
        group[0] = new Marine();
        group[1] = new Tank();
        group[2] = new Dropship();
        
        for(int i = 0 ; i < group.length; i ++)
            group[i].move(100, 200);
    }
}

당연히도 Object ë°°ì—Žë¡œ 닀룰 겜우에는 move 핚수륌 사용할 수 없닀. Object 큎래슀에는 move 메소드가 없Ʞ 때묞읎닀.

2. 읞터페읎슀(interface)

  추상큎래슀의 음종읞 읞터페읎슀는, 추상큎래슀볎닀 추상화 수쀀읎 높Ʞ 때묞에 음반 메소드, 멀버 변수륌 멀버로 가질 수 없닀. 였로지 추상 메서드와 상수만을 멀버로 가질 수 있닀. 읞터페읎슀는 큎래슀에서처럌 ì„ ì–ží•  수 있닀. 닀만 class 킀워드 대신 interface 륌 사용핎알 한닀. ì ‘ê·Œ 제얎자는 큎래슀와 동음하게 public, default 륌 사용할 수 있닀.

 

몚든 멀버 변수는 public static  final 읎얎알 하고, 생략읎 가능하닀.

몚든 메서드는 public abstract 읎얎알 하며, 생략할 수 있닀.

닀만, static 메서드와 default 메서드는 예왞(JDK 1.8부터 적용됚.)

 

읞터페읎슀의 몚든 멀버에 대핎서 위 사항은 적용되Ʞ 때묞에, 제얎자륌 생략할 수 있는 것읎닀. 생략된 제얎자는 컎파음 시 컎파음러에 의핎 추가된닀. 읞터페읎슀의 메서드는 몚두 추상메서드여알 하지만, JDK 1.8 버전부터 읞터페읎슀에 static 메서드와 default 메서드륌 허용할 수 있게 되었윌나 현재 싀묎에서는 JDK 1.8 을 사용하지 않는 겜우가 많Ʞ 때묞에 읎전 버전곌 읎후 버전에 대한 찚읎점을 잘 알고 있을 필요가 있닀.

interface PlayingCard {
    public static final int SPADE = 4;
    final int DIAMOND = 3;
    static int HEART = 2;
    int CLOVER = 1;

    public abstract String getCardNumber();
    String getCardKind();
}

 ìží„°íŽ˜ìŽìŠ€ëŠ” 였직 읞터페읎슀로부터만 상속을 받을 수 있고, 닀쀑 상속읎 허용된닀. 읞터페읎슀는 추상 큎래슀와 같읎 ê·ž 자첎로 읞슀턎슀륌 생성할 수는 없윌며, 추상 큎래슀가 상속을 통핎 추상 메서드륌 완성시킀는 것곌 같읎 읞터페읎슀의 겜우도 마찬가지읞데 읎륌 extends 가 아닌 implements 륌 사용한닀는 것읎 찚읎점읎닀. 구현하는 읞터페읎슀의 메서드 쀑에서 음부 부분만 구현한닀멎, abstract 킀워드륌 앞에 붙여서 abstract class 로 ì„ ì–ží•Žì•Œ 하며, 상속곌 구현을 동시에 할 수도 있닀.

class source {
    public static void main(String[] args) {
    Fighter f = new Fighter();
    
    if(f instanceof Unit)
        System.out.println("f is an instance of Unit Class");
    if(f instanceof Fightable)
        System.out.println("f is implemented from Fightable");
    if(f instanceof Movable)
        System.out.println("f is implemented from Movable");
    if(f instanceof Attackable)
        System.out.println("f is implemented from Attackable");
    if(f instanceof Object)
        System.out.println("f is implemented from Object");
    }
}
class Fighter extends Unit implements Fightable{
    public void move(int x, int y){
        // ...
    }
    public void attack(Unit u){
        // ...
    }
}
class Unit {
    int currentHP;
    int x;
    int y;
}
interface Fightable extends Movable, Attackable{ }
interface Movable { void move(int x, int y); }
interface Attackable { void attack(Unit u); }

  상속 받을 때, interface 는 implement 킀워드륌 사용했을 뿐읎지 class 에서의 상속곌 동음하닀. 귞러므로 interface 는 조상읎띌고 할 수 있윌며, Movable interface 에 구현된 메소드읞 move 핚수륌 볎멎 ì ‘ê·Œ 제얎자륌 public 윌로 섀정하였닀는 것에 죌목핎알 한닀. 였버띌읎딩 할 때에는 조상의 메소드 볎닀 넓은 범위의 ì ‘ê·Œ 제얎자로 지정핎알 하는데, Movable 읞터페읎슀에 void move(int x, int y)띌고 정의된 메소드는 public abstract 가 생략된 것읎닀. 귞래서 읎륌 싀제로 구현하는 Fighter 큎래슀에서는 void move(int x, int y)의 접귌제얎자륌 public 윌로 핎알만 하는 것읎닀.

  

  읞터페읎슀는 큎래슀에서와 달늬 닀쀑 상속읎 가능하닀고 했닀. 닀만 두 조상윌로부터 상속받은 멀버 쀑 읎늄읎나 선얞부가 같고 구현 낎용읎 닀륞 겜우가 발생할 수 있는데, 읎러한 겜우에는 자손 큎래슀에서 ì–Žë– í•œ 조상의 메서드륌 상속받는 것읞지 알 수 없닀. 한 쪜윌로부터의 상속을 포Ʞ하거나, 읎늄 충돌읎 발생하지 않도록 조상 큎래슀륌 변겜하는 것읎 음반적읞 대응읎닀. 귞래서 읎러한 닀쀑상속은 득볎닀 싀읎 더 크닀고 판닚하였Ʞ 때묞에 java 에서는 허용하지 않았닀. C++ 에서는 허용한닀. 여튌 자바는 닀쀑 상속을 허용하지 않는 것읎 하나의 대표적읞 닚점윌로 작용하는데, 읎륌 읞터페읎슀의 닀쀑 상속을 허용핚윌로썚 얎느정도 대응할 수 있었지만 싀제로 자바에서 읞터페읎슀로 닀쀑상속을 구현하는 겜우는 잘 없닀고 한닀. 

 

  읞터페읎슀는 static 상수만 정의할 수 있Ʞ 떄묞에 조상 큎래슀의 멀벌 변수와 충돌하는 겜우가 거의 없고, 충돌된닀고 하더띌도 큎래슀 읎늄을 붙여서 구분읎 가능하닀. 추상 메서드는 구현 낎용읎 전혀 없Ʞ 때묞에 조상 큎래슀의 메서드와 선얞부가 음치하는 겜우에는 조상 큎래슀 쪜의 메소드륌 상속받윌멎 되Ʞ 때묞에 묞제가 발생하지 않는닀. 허나 읎렇게 하멎 충돌은 플하지만 닀쀑 상속의 장점은 잃는닀. 만앜에 두 개의 큎래슀로부터 상속을 받아알만 하는 상황읎 발생한닀멎, 비쀑읎 높은 큎래슀륌 상속받고 나뚞지 한 큎래슀는 낎부에 멀버로 포핚시킀거나 필요한 부분을 뜑아서 읞터페읎슀로 구현하는 것읎 좋닀. TVCR 읎띌는 큎래슀륌 TV와 VCR 로부터 몚두 상속받도록 만듀Ʞ 위핎서는, 비쀑읎 높은 큎래슀읞 TV 륌 상속받도록 하고, VCR 큎래슀와 동음한 메서드륌 가지는 interface 읞 IVCR 을 만든 닀음 아래와 같읎 구현하는 것읎 좋닀.

public class TVCR extends TV implements IVCR{
    VCR vcr = new VCR();
    public void play() {
        vcr.play();
    }
    public void stop() {
        vcr.stop();
    }
    /*
    ...
     */
}

새로 메서드륌 작성핎알 하는 부닎은 있지만 VCR 큎래슀의 읞슀턎슀륌 사용하여 쉜게 닀쀑 상속을 구현할 수 있닀. 또한 VCR 큎래슀의 낎용읎 바뀌얎도 변겜된 낎용읎 TVCR 큎래슀에도 자동윌로 반영된닀. 읞터페읎슀륌 사용하지 않고 귞냥 VCR 큎래슀륌 TVCR 큎래슀에 포핚시쌜서 구현할 수 있지만, 읞터페읎슀륌 활용핚윌로썚 닀형적 특성을 읎용할 수 있닀는 것읎 장점읎닀.

 

  자손 큎래슀의 읞슀턎슀는 조상 큎래슀 타입의 ì°žì¡° 변수로 찞조하는 것읎 가능하닀. 읞터페읎슀도 큎래슀의 조상읎띌고 할 수 있Ʞ 때묞에, 읞터페읎슀 타입의 ì°žì¡° 변수로 구현한 큎래슀의 읞슀턎슀륌 ì°žì¡°í•  수 있고, 형 변환 또한 가능하닀. interface Fightable 을 Fighter class 가 구현한 겜우, Fightable f = (Fightable)new Fighter(); 혹은 Fightable f = new Fighter(); 와 같읎 찞조하는 것읎 가능하닀. 귞럌로 읞터페읎슀는 메서드의 맀개변수 타입윌로 사용가능하닀.

 

void attack(Fightable f){ ... }

 

 ìží„°íŽ˜ìŽìŠ€ 타입의 맀개변수륌 둔닀는 것은 메서드륌 혞출할 때, 핎당 읞터페읎슀륌 구현한 큎래슀의 읞슀턎슀륌 맀개변수로 제공핎알 한닀는 것을 의믞한닀. 귞래서 위의 attack 메서드륌 혞출할 때에는 맀개변수로 Fightable 읞터페읎슀륌 구현한 큎래슀의 읞슀턎슀륌 넘겚죌얎알 한닀는 것읎닀. Fightable 읞터페읎슀륌 구현한 Fighter 큎래슀가 있닀고 치자. 귞러멎 attack 메서드의 맀개변수로 Fighter 읞슀턎슀륌 넘겚쀄 수 있닀. 귞말은 슉슚 attack(new Fighter()) 와 같읎 할 수 있닀는 것읎고, 마찬가지로 늬턎 타입윌로 읞터페읎슀의 타입을 지정하는 것 또한 가능하닀. 늬턎 타입을 읞터페읎슀로 한닀는 것은 핎당하는 읞터페읎슀륌 구현한 큎래슀의 읞슀턎슀륌 반환한닀는 것을 의믞한닀. 

interface Parseable{
    public abstract void parse(String fileName);
}

class ParserManager{
    public static Parseable getParser(String type){
        if(type.equals("XML")) {
            return new XMLParser();
        }else{
            Parseable p = new HTMLParser();
            return p;
            // return new HTMLParser();
        }
    }
}

class XMLParser implements Parseable{
    public void parse(String fileName){
        /* 
        * ...
        * */
        System.out.println(fileName + "- XML parsing completed.");
    }
}

class HTMLParer implements Parseable{
    public void parse(String fileName){
        /*
        ...
         */
        System.out.println(fileName + "-HTML parsing completed.");
    }
}

class ParserTest{
    public static void main(String[] args) {
        Parseable parser = ParserManager.getParser("XML");
        parser.parse("document.xml");
        parser = ParserManager.getParser("HTML");
        parser.parse("document2.html");
    }
}

위 윔드륌 볎멎 Parseable 읞터페읎슀는 parsing Ʞ능을 구현할 목적윌로 abstract method parse(String fileName)을 정의하였닀. XMLParser 큎래슀와 HTMLParser 큎래슀는 Parseable 읞터페읎슀륌 구현한 것읎고, ParserManager 큎래슀의 getParser 메서드는 맀개변수로 넘겚받는 type 의 값에 따띌서 XMLParser 읞슀턎슀 혹은 HTMLParser 읞슀턎슀륌 반환한닀. 만앜 새로욎 버전의 XML 구묞 분석Ʞ읞 NewXMLParser 큎래슀륌 추가핎알한닀멎, ParserManager 큎래슀의 getParser 메서드에서 return new NewXMLParser(); 윌로만 수정핎죌멎 된닀. 읎러한 특징은 분산한겜 프로귞래밍에서 큰 장점윌로 작용된닀. 예륌 듀얎, 서버닚에서의 변겜만 핮도 사용자 컎퓚터의 프로귞랚의 변겜 없읎 업데읎튞가 가능할 것읎닀.

 

  읎러한 읞터페읎슀륌 사용하는 읎유와 장점을 정늬핎볎자.

1. 개발 시간을 닚축할 수 있닀.

  읞터페읎슀만 사용핎서 프로귞랚을 작성하는 것읎 가능하Ʞ 때묞읎닀. 메서드 혞출 부에서 메서드의 낎용에 상ꎀ없읎 선얞부만 알멎 된닀. 동시에 닀륞 엔지니얎가 읞터페읎슀륌 구현하는 큎래슀륌 만듀도록 하멎, 횚윚적윌로 개발할 수 있닀.

 

2. 표쀀화가 가능하닀.

  프로젝튞의 Ʞ볞 틀을 읞터페읎슀로 작성을 뚌저 한 닀음에, 팀원듀에게 구첎적윌로 구현하도록 핚윌로썚 윔드의 표쀀화가 가능하닀.

 

3. 서로 ꎀ계없는 큎래슀듀에게 ꎀ계륌 맺얎쀄 수 있닀.

  상속ꎀ계에 놓여있지도 않고 같은 조상큎래슀륌 가지고 있지도 않은, 서로 아묎런 ꎀ계도 없는 큎래슀듀에게 읞터페읎슀륌 공통윌로 구현하도록 핚윌로썚 ꎀ계륌 만듀얎 쀄 수 있닀.

 

4. 독늜적읞 프로귞래밍읎 가능하닀.

  읞터페읎슀륌 사용핚윌로썚 구현부와 선얞부륌 분늬할 수 있윌므로, 싀제 구현에 독늜적읞 프로귞랚을 작성하는 것읎 가능하며 큎래슀 간의 ꎀ계륌 읞터페읎슀륌 읎용하여 간접적읞 ꎀ계로 변겜핎쀀닀멎 한 큎래슀의 변겜읎 닀륞 큎래슀에 영향을 죌지 않는 독늜적읞 프로귞래밍을 할 수 있닀.

 

  특정 데읎터베읎슀륌 사용하는 큎래슀륌 만듀었지만, 추후에 닀륞 데읎터베읎슀로의 변겜을 요하는 상황읎 있을 수 있닀. 읎때, 데읎터베읎슀 ꎀ렚 읞터페읎슀륌 읎용하여 프로귞랚을 정의하였닀멎 프로귞랚을 변겜하지 않더띌도 데읎터베읎슀의 종류륌 바꟞는 것은 크게 얎렵지 않은 음읎닀. 자바에서는 닀수의 데읎터베읎슀와 ꎀ렚된 읞터페읎슀륌 제공하고 있얎, 읎륌 읎용하멎 특정 데읎터베읎슀에 종속되지 않는 프로귞랚을 작성할 수 있닀.

class source{
    public static void main(String[] args) {
        Tank tank = new Tank();
        Dropship dropship = new Dropship();


        Marine marine = new Marine();
        SCV scv = new SCV();
        scv.repair(tank);
        scv.repair(dropship);
    }
}

interface Repairable{ } // interface

class Unit{
    int hitPoint;
    final int MAX_HP;
    Unit(int hp) {
        MAX_HP = hp;
    }
}

class GroundUnit extends Unit{
    GroundUnit(int hp){
        super(hp);
    }
}

class AirUnit extends Unit{
    AirUnit(int hp){
        super(hp);
    }
}

class Tank extends GroundUnit implements Repairable{
    Tank(){
        super(150);
        hitPoint = MAX_HP;
    }
    public String toString(){
        return "Tank";
    }
}

class Dropship extends AirUnit implements Repairable{
    Dropship(){
        super(125);
        hitPoint = MAX_HP;
    }
    public String toString(){
        return "Dropship";
    }
}

class Marine extends GroundUnit{
    Marine(){
        super(40);
        hitPoint = MAX_HP;
    }
}

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++;
            }
            System.out.println(u.toString() + " repairing completed");
        }
    }
}

  위와 같읎 Marine, SCV, Tank, DropShip 큎래슀가 있닀고 하자. Marine, SCV, Tank 는 GroudUnit 을 조상 큎래슀로 가지고 있고 Dropship 은 AirUnit 을 조상 큎래슀로 가지고 있닀. 싀제 슀타크래프튞 게임에서는 Ʞ계 유닛에 대하여 repair Ʞ능을 수행할 수 있닀. 읎륌 구현하렀고 하닀 볎니, repair 메소드륌 각각에 핎당하는 만큌 였버로딩핎알 하는 상황읎 발생한닀. 읎는 횚윚적읎지 않윌며, 읎러한 상황에서 읞터페읎슀륌 읎용하멎 각각의 큎래슀에 대한 상속ꎀ계륌 유지하멎서 공통점을 부여할 수 있닀. Repairable 읞터페읎슀륌 정의한 닀음 각각의 Ʞ계 유닛에 대하여 읞터페읎슀륌 구현하도록 정의하멎 된닀.  repair 메서드에서 r 맀개변수는 Repairable 타입읞데, Repairable 읞터페읎슀는 정의된 멀버가 없Ʞ 때묞에 r 윌로는 할 수 있는게 아묎도 없닀. 귞래서 instanceof 연산자륌 읎용하여 타입을 첎크한 닀음에 Unit 큎래슀에 정의된 멀버륌 사용할 수 있도록 하였닀. 

 

  귞래서 읞터페읎슀는 도대첎 묎엇읞가? 

아래의 두 가지 사항을 엌두에 두고 있얎알 한닀.

 

1. 큎래슀륌 사용하는 쪜(User)곌 큎래슀륌 제공하는 쪜(Provider)읎 있닀.

2. 메서드륌 사용(혞출)하는 쪜(User)에서는 사용하렀는 메서드(Provider)의 선얞부만 알멎 되고, 낎용은 몰띌도 된닀.

 

class A{
    public void methodA(B b){
        b.methodB();
    }
}
class B{
    public void methodB(){
        System.out.println("MethodB()");
    }
}

class source{
    public static void main(String[] args) {
        A a = new A();
        a.methodA(new B());
    }
}

위와 같읎 작성된 프로귞랚을 볎멎 큎래슀 B 의 methodB() 의 선얞부가 바뀌멎 큎래슀 A 도 변겜되얎알 하는 구조륌 가진닀. 읎와 같읎 직접적읞 ꎀ계륌 가지는 큎래슀는 Provider 읎 변겜되멎 User 또한 변겜읎 불가플하닀. 읎러한 상황에서는 읞터페읎슀륌 읎용하멎 큎래슀 A가 큎래슀 B 륌 직접적윌로 혞출하지 않고도 읞터페읎슀륌 맀개첎로 하여 접귌하도록 하멎, 큎래슀 B 의 변겜 사항읎 발생하더띌도 큎래슀 A 는 변겜하지 않아도 된닀. 읎와 같읎 간접적윌로 ꎀ계륌 변겜하렀멎 읞터페읎슀륌 읎용핎서 큎래슀 B 의 선얞부와 구현부륌 분늬할 필요가 있닀.

interface I{
    public abstract void methodB();
}

위와 같읎 큎래슀 B의 메서드 B 륌 추상화하여 정의하는 interface 륌 만듀얎 쀀 닀음, 큎래슀 B 에서 구현하도록 한닀.

class A{
    public void methodA(I i){
        i.methodB();
    }
}
class B implements I{
    public void methodB(){
        System.out.println("MethodB()");
    }
}

읎렇게 핎죌멎 큎래슀 A 에서 큎래슀 B 륌 사용하지 않윌므로, 간접적읞 ꎀ계가 된닀. 큎래슀 A 에서 여전히 큎래슀 B 의 메서드륌 혞출하고 있음에도 큎래슀 A 는 읞터페읎슀 I 륌 통핎서 큎래슀 B 의 메서드에 접귌하Ʞ 때묞에 큎래슀 B 의 변겜에 전혀 영향을 받지 않는닀. 

 

  JDK1.8 부터 읞터페읎슀에 추상 메서드 뿐만 아니띌 디폮튾 메서드와 static 메서드도 추가할 수 있닀. static 메서드는 읞슀턎슀와 ꎀ계 없는 독늜적읞 메서드읎므로 사싀 허용하지 않았을 읎유가 크게 없었는데, JAVA 얞얎에 대한 닚순화륌 위핎 읞터페읎슀의 메서드는 몚두 추상 메서드여알지 한닀는 것에 대한 예왞 사항을 두지 않은 것읎띌고 한닀. 귞래서 읞터페읎슀와 ꎀ렚된 static 메서드는 별도의 큎래슀에 만듀었얎알 하는데, 대표적윌로 java.util.Collection 읞터페읎슀가 있닀. 읎 읞터페읎슀와 ꎀ렚된 static 메서드듀은, 읞터페읎슀에는 추상 메서드만 ì„ ì–ží•  수 있닀는 규칙 때묞에 Collection 읎띌는 큎래슀에 별도로 듀얎가게 되었닀. 만앜 쎈Ʞ부터 읞터페읎슀에 추상 메서드 뿐만읎 아니띌 static 메서드륌 추가할 수 있었더띌멎 Collection 큎래슀는 졎재하지 않았을 것읎닀. 읞터페읎슀에서도 역시 static 메서드의 ì ‘ê·Œ 제얎자는 public 윌로 핎알하며, 생략읎 가능하닀.

 

  읞터페읎슀에 메서드륌 추가한닀는 것은 추상 메서드륌 추가한닀는 것읎고, 읎말은 슉슚 읞터페읎슀륌 구현하고 있는 몚든 큎래슀듀에서 새롭게 추가된 추상 메서드륌 구현핎알한닀는 의믞읎닀. 읎러한 작업은 ꜀나 복잡한 음읎며, 읞터페읎슀의 변겜을 최대한 방지하렀고 핮도 얎쩔수 없읎 핎알만하는 상황읎 종종 발생한닀. 읎러한 상황에서 볎닀 쉜게 í•Žê²°í•  수 있게 하Ʞ 위핎 JDK 섀계자듀은 디폮튾 메서드(default method) ë¥Œ 고안하였닀. 디폮튾 메서드륌 읞터페읎슀에 추가하더띌도 핎당하는 읞터페읎슀륌 구현하는 큎래슀의 변겜은 필요하지 않는닀. 앞에 default í‚€ì›Œë“œë¥Œ 붙여서 메서드륌 선얞하멎 되는데, 추상 메서드와는 달늬 음반 메서드처럌 몞통 부분을 만듀얎죌얎알 하며 ì ‘ê·Œ 제얎자는 public 을 사용핎알 하고 생략읎 가능하닀. 읞터페읎슀에 추상 메서드륌 추가하는 대신 디폮튾 메서드륌 추가하멎 핎당 읞터페읎슀륌 구현한 큎래슀륌 변겜하지 않아도 되는 것읎닀. 읎는 조상 큎래슀에 새로욎 메서드륌 추가한 것곌 동음하닀. 닀만 새롭게 추가한 디폮튾 메서드와 êž°ì¡Ž 메서드의 읎늄 충돌읎 발생하는 겜우가 있는데 1. 여러 읞터페읎슀의 디폮튾 메서드 간 충돌읎 발생하는 겜우에는 읞터페읎슀륌 구현한 큎래슀에서 디폮튾 메서드륌 였버띌읎딩하여 핎결한닀. 2. 디폮튾 메서드와 조상 큎래슀의 메서드 간 충돌읎 발생하멎, 조상 큎래슀의 메서드가 상속되고, 디폮튾 메서드는 묎시된닀. ê·žëƒ¥ 필요한 쪜의 메서드와 같은 낎용윌로 였버띌읎딩하도록 하자...

3. 낎부 큎래슀(inner class)

  큎래슀 안에 ì„ ì–ží•œ 큎래슀륌 낎부 큎래슀띌고 하는데, 읎렇게 핚윌로썚 1. 낎부 큎래슀에서 왞부 큎래슀의 멀버듀을 쉜게 접귌할 수 있고, 2. 윔드의 복잡성을 쀄음 수 있닀(캡슐화)는 장점읎 있닀. 낎부 큎래슀로 만드는 것은 왞부 큎래슀에서 잘 사용하지 않는 큎래슀여알 한닀.

class A{
    class B{
        
    }
}

  낎부 큎래슀는 ì„ ì–ž 위치에 따띌서 종류가 달띌진닀. instance class 는 왞부 큎래슀의 멀버 변수 선얞부에서 선얞하며, 왞부 큎래슀의 읞슀턎슀 멀버처럌 닀뀄진닀. static class 도 동음하게 왞부 큎래슀의 멀버 변수 선얞부에서 선얞하는데, 왞부 큎래슀의 static 멀버와 같읎 닀룚얎진닀. local class 는 왞부 큎래슀의 메서드 혹은 쎈Ʞ화 뾔럭 낎에서 선얞되며, ì„ ì–ž 영역 낎부에서만 사용읎 가능하닀. anonymous class 는 큎래슀의 ì„ ì–ž 및 객첎의 생성을 동시에 하는 음회용 익명 큎래슀읎닀.

 

  큎래슀에서는 default 와 public ì ‘ê·Œ 제얎자만 사용읎 가능하나 낎부 큎래슀는 변수와 동음하게 public, default, private, protected ì ‘ê·Œ 제얎자륌 사용가능하닀. 또한 abstract 와 final 곌 같은 제얎자도 사용읎 가능하닀. 낎부 큎래슀륌 정의할 때 유의핎알 할 점은 만앜 낎부 큎래슀에서 static member 을 사용핎알 하는 겜우띌멎 낎부 큎래슀도 static 윌로 만듀얎죌얎알 한닀는 것읎닀. 왜냐멎 static member 띌는 것은 객첎 생성 없읎 사용읎 가능한 member 읞데, 만앜 낎부 큎래슀가 static 읎 아니띌멎 몚순읎 발생한닀는 것읎닀. 낎부 큎래슀가 static 읎여알지 녌늬가 성늜한닀. 또한 쀑요한 것은 static 낎부 큎래슀에서는 왞부 큎래슀의 읞슀턎슀 멀버에 접귌할 수 없닀. final static 은 상수읎므로 허용한닀.

 

  • static 큎래슀에서만 static 멀버륌 정의할 수 있닀.
  • 읞슀턎슀 멀버 간 혹은 static 멀버 간에는 서로 직접 접귌읎 가능하닀.
  • static 멀버는 읞슀턎슀 멀버에 직접적윌로 접귌할 수 없닀. 굳읎 접귌하렀멎 객첎륌 생성핎알만 한닀. 
  • 왞부 큎래슀의 private 멀버도 낎부 큎래슀에서는 직접 접귌읎 가능하닀.
  • 왞부 큎래슀의 지역변수는 final 읎 붙은 변수(상수)만 ì ‘ê·Œ 가능하닀. JDK1.8 부터는 final 생략읎 가능핎짐에 유의.
  • 읞슀턎슀 큎래슀의 읞슀턎슀륌 생서앟렀멎 왞부 큎래슀의 읞슀턎슀륌 뚌저 생성핎알만 한닀.
  • static 낎부 큎래슀의 읞슀턎슀는 왞부 큎래슀륌 뚌저 생성치 않아도 된닀.
  • 익명 큎래슀는 선얞곌 객첎의 생성을 동시에 진행핎서, 음회성윌로 사용되는 큎래슀읎닀. 

References

http://www.yes24.com/Product/Goods/24259565

 

Java의 정석 - YES24

최귌 7년동안 자바 분알의 베슀튞 셀러 1위륌 지쌜옚 `자바의 정석`의 최신판. 저자가 칎페에서 12년간 직접 독자듀에게 답변을 핎였멎서 쎈볎자가 얎렀워하는 부분을 잘 파악하고 ì“Ž 책. 뿐만 아

www.yes24.com

728x90
반응형
LIST
Comments