// 부모 클래스
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();
}
}
익명 클래스는 클래스 정의와 객체를 동시에 생성할 수 있기 때문에, 따로 자식 클래스를 생성하지 않아도 된다. 그러나 이렇게 동시에 생성하기 때문에, 한 번만 사용 가능하며, 클래스는 버려진다.
부모 클래스를 상속 받은 자식 클래스는 메서드 재정의 뿐만 아니라, 새로운 메서드 생성이 가능했다. 하지만, 익명 클래스는 오직 오버라이딩한 메서드만 사용이 가능하고, 새로 정의한 메서드는 외부에서 사용이 불가능하다.
// 부모 클래스
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()만 사용이 가능하다.)
class Animal { ... }
class Creature {
// 필드에 익명자식 객체를 생성 하여 이용
Animal dog = new Animal() {
public String bark() {
return "멍멍";
}
};
public void method() {
dog.bark();
}
public void method2() {
dog.bark();
}
}
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 "고양이가 웁니다";
}
};
// ...
}
}
// 인터페이스
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;