공부/Java

자바 익명 클래스

Stair 2024. 9. 14. 13:57
반응형

https://surrealcode.tistory.com/63

 

자바 지역 클래스

https://surrealcode.tistory.com/62 자바 중첩 클래스, 내부 클래스예전 반복문을 배울 때 for문 안에 for문을 중첩하는 것을 배웠던 적이 있다.for(){    for((){        ~~~~~    }}이런 for문을 2중 for문 또는

surrealcode.tistory.com

익명 클래스는 지역 클래스의 종류 중 하나이기에 이전 게시글인 자바 지역클래스를 참고하도록 하자.

 

 

자바의 익명 클래스(anonymous class)는 지역 클래스의 특별한 종류의 하나이다.

익명 클래스는 지역 클래스인데, 클래스의 이름이 없다는 특징이 있다.

 

 

public class LocalOuterV2 {

    private int outInstanceVar = 3;

    public void process(int paramVar){
        int localVar = 1;

        class LocalPrinter implements Printer{
            int value = 0;

            @Override
            public void print() {
                System.out.println("value = " + value);
                System.out.println("localVar = " + localVar);

                System.out.println("paramVar = " + paramVar);
                System.out.println("LocalOuterV1.this.outInstanceVar = " + LocalOuterV2.this.outInstanceVar);
            }
        }

        LocalPrinter localPrinter = new LocalPrinter();
        localPrinter.print();


    }

    public static void main(String[] args) {
        LocalOuterV2 localOuterV1 = new LocalOuterV2();
        localOuterV1.process(2);
    }
}

이전에 만들었던 예제 코드이다.

여기서는 지역 클래스를 사용하기 위해 선언과 생성이라는 2가지 단계를 거친다.

1. 선언 : 지역 클래스를 LocalPrinter라는 이름으로 선언한다. 이때 Printer 인터페이스도 함께 구현한다.

2. 생성 : new LocalPrinter()를 사용해서 앞서 선언한 지역 클래스의 인스턴스를 생성한다.

 

익명 클래스를 사용하면 클래스의 이름을 생략하고, 클래스의 선언과 생성을 한번에 처리할 수 있다.

public class AnonymousOuter {

    private int outInstanceVar = 3;

    public void process(int paramVar){
        int localVar = 1;


        Printer printer = new Printer() {
            int value = 0;

            @Override
            public void print() {
                System.out.println("value = " + value);
                System.out.println("localVar = " + localVar);

                System.out.println("paramVar = " + paramVar);
                System.out.println("LocalOuterV1.this.outInstanceVar = " + AnonymousOuter.this.outInstanceVar);
            }
        };

        printer.print();


    }

 

이 코드는 앞서 만들었던 LocalOuterV2와 완전히 같은 코드이다. 여기서는 익명 클래스를 사용하였다.

 

new Printer() {body}

익명 클래스는 클래스의 본문(body)을 정의하면서 동시에 생성한다.

new 다음에 바로 상속 받으면서 구현 할 부모 타입을 입력하면 된다.

이 코드는 마치 인터페이스 Printer를 생성하는 것 처럼 보인다. 하지만 자바에서 인터페이스를 생성하는 것은 불가능하다. 이 코드는 인터페이스를 생성하는 것이 아니고, Printer라는 이름의 인터페이스를 구현한 익명 클래스를 생성하는 것이다.

 

 

익명 클래스 특징

1. 익명 클래스는 이름 없는 지역 클래스를 선언하면서 동시에 생성한다.

2. 익명 클래스는 부모클래스를 상속 받거나, 인터페이스를 구현해야 한다. 익명 클래스를 사용할 때는 상위 클래스나 인터페이스가 필요하다.

3. 익명 클래스는 말 그대로 이름이 없다. 이름을 가지지 않으므로 생성자를 가질 수 없다.

 

 

익명 클래스의 장점

익명 클래스를 사용하면 클래스를 별도로 정의하지 않고도 인터페이스나 추상 클래스를 즉석에서 구현할 수 있어 코드가 더 간결해진다.

 

public class Ex1Main {

    public static void helloProgram(Process process){
        System.out.println("프로그램 시작");

        process.run();

        System.out.println("프로그램 종료");

    }

    static class dice implements Process{

        @Override
        public void run() {
            //코드 조각 시작
            int randomValue = new Random().nextInt(6) + 1;
            System.out.println("주사위 = " + randomValue);
            //코드 조각 종료
        }
    }

    static class sum implements Process{

        @Override
        public void run() {
            //코드 조각 시작
            for(int i = 0; i < 3; i++){
                System.out.println("i = " + i);
            }
            //코드 조각 종료
        }
    }

    public static void main(String[] args) {
        dice dice = new dice();
        sum sum = new sum();

        System.out.println("hello 실행");
        helloProgram(dice);
        helloProgram(sum);
    }

}

위의 코드를 보자

 

프로그램 시작, 프로그램 종료를 출력하는 부분은 변하지 않는 부분이다.

코드 조각을 시작하고 종료하는 부분은 변하는 부분이다.

결국 코드 조각을 시작하고 종료하는 부분을 외부에서 전달받아야 한다. 이것은 단순히 문자열 같은 데이터를 전달 받는 것과는 차원이 다른 문제이다.

 

코드 조각은 보통 메서드(함수)에 정의한다. 따라서 코드 조각을 전달하기 위해서는 메서드가 필요하다.

그런데 지금까지 학습한 내용으로는 메서드를 전달할 수 있는 방법이 없다. 대신에 인스턴스를 전달하고, 인스턴스에 있는 메서드를 호출하였다.

 

 

정리

문자열 같은 데이터를 메서드에 전달할 때는 String, int 와 같은 각 데이터에 맞는 타입을 전달하면 된다.

코드 조각을 메서드에 전달할 때는 인스턴스를 전달하고 해당 인스턴스에 있는 메서드를 호출하면 된다.

 

 

public static void main(String[] args) {

    System.out.println("hello 실행");
    helloProgram(new Process() {
        
        @Override
        public void run() {
            //코드 조각 시작
            int randomValue = new Random().nextInt(6) + 1;
            System.out.println("주사위 = " + randomValue);
            //코드 조각 종료
        }
    });

    helloProgram(new Process() {

        @Override
        public void run() {
            //코드 조각 시작
            for (int i = 0; i < 3; i++) {
                System.out.println("i = " + i);
            }
            //코드 조각 종료
        }
    });
}

익명 클래스는 참조값을 굳이 담아 둘 필요 없이 바로 전달할 수 있다.

 

 

 

람다(lamda)

자바8 이전에는 메서드에 인수로 전달할 수 있는 것은 크게 2가지였다.

1. int double과 같은 기본형 타입

2. Process Member와 같은 참조형 타입(인스턴스)

 

지금처럼 코드 조각을 전달하기 위해 클래스를 정의하고, 메서드를 만들고 또 인스턴스를 꼭 생성해서 전달해야 할까?

생각해보면 클래스나 인스턴스와 관계 없이 다음과 같이 메서드만 전달할 수 있다면 더 간단하지 않을까

 

자바8에 들어서면서 큰 변화가 있었는데, 바로 메서드(더 정확히는 함수)를 인수로 전달할 수 있게 되었다. 이것을 간단히 람다(Lamda)라 한다.

public class Ex1RefMainV5 {

    public static void helloProgram(Process process){
        System.out.println("프로그램 시작");

        process.run();

        System.out.println("프로그램 종료");

    }


    public static void main(String[] args) {

        System.out.println("hello 실행");
        helloProgram(() -> {
            //코드 조각 시작
            int randomValue = new Random().nextInt(6) + 1;
            System.out.println("주사위 = " + randomValue);
            //코드 조각 종료
        });

        helloProgram(() -> {
            //코드 조각 시작
            for (int i = 0; i < 3; i++) {
                System.out.println("i = " + i);
            }
            //코드 조각 종료
        });
    }

}

코드를 보면 클래스나 인스턴스를 정의하지 않고, 메서드(더 정확히는 함수)의 코드 블럭을 직접 전달하는 것을 확인할 수 있다.

 

람다에 대한 자세한 내용은 다음에 별도로 다뤄보자.

반응형

'공부 > Java' 카테고리의 다른 글

자바 예외처리 2  (5) 2024.09.16
자바 예외처리 1  (0) 2024.09.15
자바 지역 클래스  (0) 2024.09.14
자바 중첩 클래스, 내부 클래스  (1) 2024.09.13
자바 날짜와 시간  (1) 2024.09.12