익명 클래스

조용근·2024년 1월 23일

자바 정리

목록 보기
13/21

익명 클래스

  • 이름이 없는 일회용 클래스(정의, 생성을 동시에 한다.)
  • 클래스 선언과 동시에 객체 생성
  • 생성자 존재 X(클래스 이름이 없기 때문)
// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

// 자식 클래스
class Dog extends Animal {
	@Override
    public String bark() {
        return "개가 짖습니다";
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.bark();
    }
}

위와 같이 자식 클래스가 부모 클래스의 상속을 받기 위해서는 extends를 사용하여 클래스를 만들고, Animal a= new Dog() 과 같이 객체를 생성해줘야만 했다.

하지만,

// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

public class Main {
    public static void main(String[] args) {
        // 익명 클래스 : 클래스 정의와 객체화를 동시에. 일회성으로 사용
        Animal dog = new Animal() {
        	@Override
            public String bark() {
                return "개가 짖습니다";
            }
        }; // 단 익명 클래스는 끝에 세미콜론을 반드시 붙여 주어야 한다.
        	
        // 익명 클래스 객체 사용
        dog.bark();
    }
}

익명 클래스는 클래스 정의와 객체를 동시에 생성할 수 있기 때문에, 따로 자식 클래스를 생성하지 않아도 된다. 그러나 이렇게 동시에 생성하기 때문에, 한 번만 사용 가능하며, 클래스는 버려진다.

  • 익명 클래스는 부모 클래스를 일회성으로 재정의(@Override)하기 위함이다.

주의

부모 클래스를 상속 받은 자식 클래스는 메서드 재정의 뿐만 아니라, 새로운 메서드 생성이 가능했다. 하지만, 익명 클래스는 오직 오버라이딩한 메서드만 사용이 가능하고, 새로 정의한 메서드는 외부에서 사용이 불가능하다.

// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Animal() {
            // @Override 메소드
            public String bark() {
                return "개가 짖습니다";
            }
            
            // 새로 정의한 메소드
            public String run() {
                return "달리기 ㄱㄱ싱";
            }
        };
        
        dog.bark();
        dog.run(); // ! Error - 외부에서 호출 불가능
    }
}

이유
new Animal()을 통해 생성된 인스턴스(dog)은 Animal 클래스를 상속 바은 클래스(익명)이기 떄문에, run()메서드는 Animal 클래스에 없으므로 사용이 불가능한 것이다.(bark()만 사용이 가능하다.)

선언 위치

  1. 여러 메서드 선언 시
class Animal { ... }

class Creature {
    // 필드에 익명자식 객체를 생성 하여 이용
    Animal dog = new Animal() {
        public String bark() {
            return "멍멍";
        }
    };

    public void method() {
        dog.bark();
    }
    
    public void method2() {
        dog.bark();
    }
}
  1. 지역 변수 선언 시
class Animal { ... }

class Creature {
	// ...
    
    public void method() {
    	// 지역 변수같이 클래스를 선언하여 일회용으로 사용
        Animal dog = new Animal() {
            public String bark() {
                return "멍멍";
            }
        };
        dog.bark();
    }
}

익명 객체

// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

// Main.java 파일
public class Main {
    public static void main(String[] args) {

        // 익명 객체 $1
        Animal dog = new Animal() {
            @Override
            public String bark() {
                return "개가 짖습니다";
            }
        };

        // 익명 객체 $2
        Animal cat = new Animal() {
            @Override
            public String bark() {
                return "고양이가 웁니다";
            }
        };

        // ...
    }
}
  • 익명 객체끼리는 내용이 똑같아도 별개로 취급되기 때문에 2개의 클래스가 만들어진다.

인터페이스와 익명 클래스

// 인터페이스
interface IAnimal {
    public String bark(); // 추상 메소드
    public String run();
}

public class Main {
    public static void main(String[] args) {
        // 인터페이스 익명 구현 객체 생성
        IAnimal dog = new IAnimal() {
            @Override
            public String bark() {
                return "개가 짖습니다";
            }
            
            @Override
            public String run() {
                return "개가 달립니다";
            }
        };
        
        // 인터페이스 구현 객체 사용
        dog.bark();
        dog.run();
    }
}

인터페이스를 익명 객체로 사용한 것이다.
// IAnimal dog = new IAnimal();는 에서 IAnimal은 인터페이스이기 때문에 이 자체가 객체가 아니라, 자식 클래스를 생성해서 implements하고 클래스를 초기화한 것이다.

하지만 익명 객체는 오직 하나의 인터페이스만 구현 가능하다.
그렇기 때문에, 다중 클래스를 따로 선언해야 한다.

interface IAnimal {
}

interface ICreature {
}

abstract class myClass {
}

public class Main {
    public static void main(String[] args) {
    
    	// 인터페이스 두개를 구현한 일회용 클래스 (일회용 이라도 어쩔수 없이 따로 선언)
        class useClass1 implements IAnimal, ICreature {
        }

        // 클래스와 인터페이스를 상속, 구현한 일회용 클래스 (일회용 이라도 어쩔수 없이 따로 선언)
        class useClass2 extends myClass implements IAnimal {
        }

        useClass1 u1 = new useClass1() {
        };

        useClass2 u2 = new useClass2() {
        };
    }
}

익명 객체는 추후 공부하게 될 람다식과 함께 많이 쓰인다.

Operate operate = new Operate() {
    public int operate(int a, int b) {
        return a + b;
    }
};//익명 클래스는 반.드.시 세미콜론을 붙여준다.

// 람다식으로 줄이기
Operate operate = (a, b) -> {
    return a + b;
};

// 더 짧게 줄이기 (리턴 코드만 있다면 생략이 가능)
Operate operate = (a, b) -> a + b;

출처 :https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%9D%B5%EB%AA%85-%ED%81%B4%EB%9E%98%EC%8A%A4Anonymous-Class-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%A7%88%EC%8A%A4%ED%84%B0%ED%95%98%EA%B8%B0

profile
Today I Learn

0개의 댓글