[혼공자] 5주차_인터페이스, 중첩 클래스와 중첩 인터페이스

혼자 공부하는 자바 개정판


5주차 학습 진도 : Chapter 8, 9 (인터페이스, 중첩 클래스와 중첩 인터페이스)




Chapter 8 인터페이스

8-1 인터페이스


인터페이스 선언

인터페이스는 클래스가 구현해야 하는 메서드의 집합을 정의합니다. 인터페이스는 interface 키워드를 사용하여 선언합니다. 인터페이스 내의 메서드는 기본적으로 추상 메서드로 정의되며, 메서드의 몸체는 포함되지 않습니다. 아래는 간단한 인터페이스의 예입니다:


public interface RemoteControl {
    // 상수
    public int MAX_VOLUME = 10;
    public int MIN_VOLUME = 0;

    // 추상 메소드
    public void turnOn();
    public void turnOff();
    public void setVolume(int volume);
}




인터페이스 구현

클래스는 인터페이스를 구현하기 위해 implements 키워드를 사용합니다. 한 클래스는 여러 개의 인터페이스를 구현할 수 있으며, 이때 각 인터페이스의 모든 메소드를 구현해야 합니다. 아래는 RemoteControl 인터페이스를 구현한 Television 클래스의 예입니다.


public class Television implements RemoteControl {
    
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }

    public void turnOff() {
        System.out.println("TV를 끕니다.");
    }
}




인터페이스 사용

인터페이스를 사용하면 객체지향 프로그래밍의 다형성을 활용할 수 있습니다. 인터페이스 타입으로 변수 선언 후, 이를 구현한 객체를 할당하여 메소드를 호출할 수 있습니다. 다음은 RemoteControl 인터페이스를 사용하는 간단한 예제입니다.


public class MyClass {

    RemoteControl rc = new Television();

    MyClass(RemoteControl rc) {
        this.rc = rc;
        rc.turnOn();
        rc.setVolume(5);
    }

}


public class MyClassExample {
    public static void main(String[] args) {
        MyClass myClass1 = new MyClass();
        myClass1.rc.turnOn();
        myClass1.rc.setVolume(5);
    }
}





8-2 타입 변환과 다형성


자동 타입 변환

자바에서는 자식 클래스의 객체를 부모 클래스 타입으로 자동 변환할 수 있습니다. 이는 자식 클래스가 부모 클래스의 모든 특성을 가지기 때문입니다.


필드의 다형성

필드의 다형성은 객체지향 프로그래밍에서 중요한 개념으로, 동일한 타입의 필드가 다양한 구현체를 참조할 수 있게 해줍니다. 이를 통해 코드의 유연성과 확장성을 높일 수 있습니다.


public class Car {
    Tire frontLeftTire = new HankookTire();
    Tire frontRightTire = new HankookTire();
    Tire backLeftTire = new HankookTire();
    Tire backRightTire = new HankookTire();

    void run() {
        frontLeftTire.roll();
        frontRightTire.roll();
        backLeftTire.roll();
        backRightTire.roll();
    }
}




매개 변수의 다형성

메서드 매개변수로 인터페이스 타입을 사용하면 다양한 객체를 전달할 수 있습니다. 이는 코드의 유연성을 높이는 중요한 요소입니다.


public class Driver {
    public void drive(Vehicle vehicle) {
        vehicle.run();
    }
}




강제 타입 변환

자동 타입 변환 후, 원래의 객체 타입으로 다시 변환할 수 있습니다. 이때는 명시적으로 타입을 지정해야 하며, 올바른 타입으로 변환하지 않으면 ClassCastException이 발생할 수 있습니다.


public class VehicleExample {
    public static void main(String[] args) {
        Vehicle vehicle = new Bus();
        
        vehicle.run();
        
        Bus bus = (Bus) vehicle;    // 강제 타입 변환
        
        bus.run();
        bus.checkFare();
    }
}




객체 타입 확인

instanceof 연산자를 사용하여 객체의 타입을 확인할 수 있습니다. 이를 통해 안전하게 강제 타입 변환을 수행할 수 있습니다.


public class Driver {
    public void drive(Vehicle vehicle) {
        if(vehicle instanceof Bus) {
            Bus bus = (Bus) vehicle;
            bus.checkFare();
        }
    }
}




인터페이스 상속

인터페이스는 다른 인터페이스를 상속받을 수 있습니다. 이는 인터페이스 간의 관계를 형성하고, 메서드의 집합을 작성하는데 유용합니다.


public interface InterfaceC extends interfaceA, interfaceB {
    public void methodC();
}





Chapter 9. 중첩 클래스와 중첩 인터페이스


9-1 중첩 클래스와 중첩 인터페이스 소개


중첩 클래스

중첩 클래스는 다른 클래스의 내부에 정의된 클래스를 말합니다. 중첩 클래스는 외부 클래스의 멤버 변수와 메서드에 직접 접근할 수 있습니다.


class A {
    class B {
        B() {}    // 생성자

        int field1; // 인스턴스 필드
        void method1() { //인스턴스 메서드
            System.out.println("method1 호출됨");
        }
    }

    public static void main(String[] args) {
        A outer = new A();       // 외부 클래스 인스턴스 생성
        B inner = outer.new B(); // 중첩 클래스 인스턴스 생성
        inner.field1 = 10;       // 필드 값 설정
        inner.method1();         // 메서드 호출
        System.out.println("field1: " + inner.field1); // 필드 값 출력
    }
}



중첩 클래스의 접근 제한

중첩 클래스는 외부 클래스의 접근 제한자에 따라 접근할 수 있는 범위가 달라집니다. 예를 들어, private로 선언된 외부 클래스의 멤버는 내부 클래스에서 접근할 수 있습니다.


public class A {
    private class B {
        void display() {
            System.out.println("B 클래스의 메서드");
        }
    }

    public class C {
        void display() {
            System.out.println("C 클래스의 메서드");
        }
    }

    void method1() {
        B b = new B();   // B는 A 내에서만 접근 가능
        C c = new C();   // C는 외부에서도 접근 가능
        b.display();
        c.display();
    }

    public static void main(String[] args) {
        A a = new A();
        a.method1();   // 메서드 호출
    }
}



중첩 인터페이스

중첩 인터페이스는 클래스 내부에 정의된 인터페이스입니다. 중첩 인터페이스는 외부 클래스의 멤버로 사용할 수 있으며, 주로 외부 클래스와 관련된 특정 기능을 정의할 때 유용합니다.


class A {
    [static] interface I {    // 중첩 인터페이스
    void method();
    }
}



9-2 익명 객체


익명 객체는 이름이 없는 클래스의 객체로, 주로 일회성으로 사용됩니다. 익명 객체는 인터페이스를 구현하거나 추상 클래스를 상속받을 때 사용됩니다.


익명 자식 객체 생성

익명 자식 객체는 인터페이스를 구현하는 익명 객체를 생성할 때 사용됩니다.



class Parent {}

class A {
    Parent field = new Parent();    // 익명 자식 객체 생성
    void method() {
        Parent localVar = new Parent();    // 로컬 변수에 익명 자식 객체를 대입
    }
}



익명 구현 객체 생성

추상 클래스를 상속받는 익명 객체도 생성할 수 있습니다. 이를 통해 간편하게 특정 클래스의 기능을 구현할 수 있습니다.


class A {
    void method1(RemoteControl rc) { }

    void method2() {
        method1(    // method1() 메서드 호출
            new RemoteControl() {    // method1()의 매개값으로 익명 구현 객체를 대입
                @Override
                void turnOn() { }
            }
        );
    }
}



익명 객체의 로컬 변수 사용

익명 객체 내에서 로컬 변수에 접근하려면 그 변수가 final이거나 사실상 final이어야 합니다. 이는 익명 클래스가 로컬 변수를 캡처할 수 있도록 보장하는 자바의 규칙입니다.


class Anonymous {
    void method(int x, int y) {
        System.out.println("x: " + x + ", y: " + y);
    }
}

public class AnonymousExample {
    public static void main(String[] args) {
        // 익명 객체 생성
        new Anonymous() {
            @Override
            public void method(final int x, int y) {
                System.out.println("Anonymous - x: " + x + ", y: " + y);
            }
        }.method(0, 0); // 메서드 호출
    }
}





기본 숙제(필수) : 클래스를 선언할 때 인터페이스는 어떻게 선언 될 수 있는지 정리하기


인터페이스는 interface키워드를 사용해 선언하며, 메서드는 기본적으로 추상적이고, 상수를 정의할 수 있습니다.


public interface RemoteControl {
    // 상수
    public int MAX_VOLUME = 10;
    public int MIN_VOLUME = 0;

    // 추상 메서드
    public void turnOn();
    public void turnOff();
    public void setVolume(int volume);
}



클래스는 implements 키워드를 사용해 인터페이스를 구현하며, 모든 추상 메서드를 오버라이드해야 합니다.


public class Television implements RemoteControl {

    // 필드
    private int volume;
    
    // turnOn() 추상 메서드의 실체 메서드
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }
    
    // turnOff() 추상 메서드의 실체 메서드
    public void turnOff() {
        System.out.println("TV를 끕니다.");
    }
}




추가 숙제(선택) : p.443 (09-1) 확인 문제 3번 풀어보기



3. 다음과 같이 Car 클래스 냅부에 Tire와 Engine이 멤버 클래스로 선언되어 있습니다. 바깥클래스(NestedClassExample)에서 멤버 클래스의 객체를 생성하는 코드를 빈칸에 작성해 보세요.


package sec01.verify.exam03;

public class Car {
    class Tire { }
    static class Engine { }
}


package sec01.verify.exam03;

public class NestedClassExample {
    public static void main(String[] args) {
        Car myCar = new Car();

        Car.Tire tire = myCar.new Tire();

        Car.Engine engine = new Car.Engine();
    }
}

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다