InnerClass, Anonymous Class
<Zoo> 클래스 생성
package test.mypac;
//동물원 클래스
public class Zoo {
//클래스 안의 클래스(내부 클래스)
public class Monkey{
public void say() {
System.out.println("안녕! 나는 원숭이야");
}
}
//내부 클래스
public class Tiger{
public void say() {
System.out.println("안녕! 나는 호랑이야");
}
}
//메소드
public Monkey getMonkey() { //내부클래스로 객체를 생성해서 리턴해주는 메소드
return new Monkey();
}
public Tiger getTiger() {
return new Tiger();
}
}
<MainClass03>
package test.main;
import test.mypac.Zoo;
import test.mypac.Zoo.Monkey;
import test.mypac.Zoo.Tiger;
public class MainClass03 {
public static void main(String[] args) {
//Zoo 클래스에 있는 getMonkey() 메소드를 호출해서
//리턴되는 값을 m1이라는 지역변수에 담아보세요.
Zoo z=new Zoo();
Monkey m1=z.getMonkey();
m1.say();
Tiger t1=z.getTiger();
t1.say();
//메소드 안에도 클래스를 정의할 수 있다.
//지역 내부 클래스, Local Inner Class
class Banana{
public void say() {
System.out.println("안녕 나는 바나나야!");
}
}
Banana b1=new Banana();
b1.say();
}
}
- 클래스 안에 클래스를 정의할 수 있다.
- InnerClass : 클래스 안에 정의된 클래스
클래스 안에 필드, 생성자, 메소드 를 정의할 수 있는데, + 여기에 클래스까지 추가하는 것!
public Monkey getMonkey() {
return new Monkey();
}
- 위와 같이 객체를 생성해 내부클래스 타입으로 리턴해주는 메소드를 만들어서 객체를 생성한다.
- 클래스 안의 일반메소드(say)는 참조값을 얻어내서 참조한다.
- new Zoo로 객체 생성 후 m1 변수안에 getMonkey로 생성한 객체를 넣는다.
import test.mypac.Zoo.Monkey;
import test.mypac.Zoo.Tiger;
- 내부클래스의 경우 위와 같이 import 한다.
- class Banana 와 같이 메소드 안에도 클래스를 정의할 수 있다.
지역변수를 만드는 곳에 정의되고, 지역 내부 클래스 Local Inner Class 라고 한다.
<MainClass04>
package test.main;
import test.mypac.Weapon;
public class MainClass04 {
//내부 클래스
static class YourWeapon extends Weapon{
@Override
public void attack() {
System.out.println("공중 공격을 해요!");
}
public static void main(String[] args) {
Weapon w1=new YourWeapon();
useWeapon(w1);
//Local Inner Class
class OurWeapon extends Weapon{
@Override
public void attack() {
System.out.println("지겹다 이제 아무나 공격하자!");
}
}
Weapon w2=new OurWeapon();
useWeapon(w2);
}
public static void useWeapon(Weapon w) {
w.prepare();
w.attack();
}
}
}
- Weapon 을 부모클래스로 받는 YourWeapon이라는 내부 static 클래스를 만들었다.
- 메인메소드 안에는 Weapon 을 부모클래스로 받는 OurWeapon이라는 지역 내부 클래스를 만들었다.
- YourWeapon이 static 클래스가 아니면 위와 같이 오류 발생. 내부클래스를 static으로 수정해주어야한다.
- main method는 특별하기 때문에 내부클래스도 static만 쓸 수 있다.
- static 영역에 메인메소드와 useWeapon이 함께 올라갈 때
여기서 내부클래스 YourWeapon 도 static 예약어를 붙여주어야 static 영역으로 들어간다.
- 이전 게시물 사례처럼 별도의 클래스를 따로 만들지않고
같은 클래스 내에서 new를 사용하여 변수에 넣고 이것을 useWeapon에 사용될 매개변수에 대입하는 구조!
- static 메소드 안에서 어떤 클래스를 사용하려면 그 클래스도 static에 올라가 있어야 한다.
- 메소드안에서 내부 클래스를 이용해서 객체 생성가능
내부클래스를 활용하면 YourWeapon이라는 클래스를 별도의 파일로 만들지 않고 메소드를 실행할 수 있다.
- 단, YourWeapon 내부클래스 여전히 사용되지 않는다. 그냥 객체를 전달하기위한 매개체로 사용될 뿐이다.
<MainClass05>
package test.main;
import java.util.Scanner;
import test.mypac.Weapon;
public class MainClass05 {
//필드
int num=999;
String name="kim";
Scanner scan = new Scanner(System.in);
//필드는 선언만 하면 기본값이 들어간다.
int weight; //0
boolean isRun; //false
String msg; //null
Scanner scan2; //null
//static 영역에 올리고싶은 필드는 static 예약을 이용해서 만든다.
static String greet="안녕";
//Anonymous Inner Class를 이용해서 Weapon type의 참조값 얻어내기
static Weapon w1=new Weapon() {
@Override
public void attack() {
System.out.println("무엇인지 모르겠지만 아무거나 공격하자!");
}
};
public static void main(String[] args) {
//메소드 호출하면서 static 필드에 미리 준비된 값을 전달하기
useWeapon(w1);
//Anonymous Local Inner Class를 이용해서 Weapon type의 참조값 얻어내기
Weapon w2=new Weapon() {
@Override
public void attack() {
System.out.println("다시 공격하자!");
}
};
//메소드 호출하면서 지역변수에 미리 준비된 값을 전달하기
useWeapon(w2);
//메소드 호출하면서 값을 즉석에서 만들어서 전달하기
useWeapon(new Weapon() {
@Override
public void attack() {
System.out.println("신기하게 공격하기");
}
});
}
public static void useWeapon(Weapon w) {
w.prepare();
w.attack();
}
}
- MainClass05 에 어떤 필드를 정의한다.
- 필드: 공간을 만들고 값을 대입하는 위치. 그 안에 코딩을 하는 건 불가능하다.
- 필드에서 메소드 안에 실행할 기능들을 나열하면 안된다.
- 하지만 필드에서 값을 만들어내는 것은 가능하다. new도 가능하다!
참고) boolean의 기본값은 false이다.
static Weapon w1;
- MainClass05 클래스의 static영역에 Weapon 타입의 w1이라는 필드를 만든다.
- w1안에 현재 null 이 들어있으므로, null 값을 전달한 것이나 마찬가지다. 콘솔창에서도 오류가 발생한다.
- 다른 클래스를 import하지 않고 w1에 참조값을 넣는 방법은?
- Weapon w1=new Weapon(){}; 하면 Weapon이 미완성 클래스이기 때문에 수정하라는 창이 뜬다.
클릭해서 메소드를 override하면 된다.
- 메인메소드 안에서 Weapon w2=new Weapon() { } 해도 똑같이 메소드가 override되는 창이 뜬다.
- 사용하지 않는 클래스는 굳이 만들지 않고, 메소드를 override하여 참조값을 대입한다.
new Weapon() { } 의 {} 부분이 클래스를 의미한다고 생각하면 된다.
→ class ? extends Weapon{ } 을 의미한다. 이름 없는 어떤 익명의 클래스를 만든 것이다.
- 익명 클래스가 Weapon 추상 클래스를 상속받는 것이라고 보면 된다.
weapon 뒤에 {}를 열어 상속받은 것. 클래스 내부에 정의된 클래스이다.
- 익명의 내부 클래스 anonymous inner class 를 사용해서 참조값을 얻어낸 것이다.
- new Weapon() 은 익명 클래스의 생성자를 호출한 것이다. 호출하면서 강제로 override시킨 것.
- 익명 클래스로 이름없는 객체를 생성한 것
- { } { } 부분 안쪽은 모두 클래스이다!
Weapon w2=new Weapon(){ };
- {} 안에 정의한 것은 메소드 안에 정의한 익명 내부 클래스(anonymous local inner class) 이다.
- 익명클래스도 클래스이기 때문에 Weapon이라는 클래스를 상속하는 데에 override가 강제된다.
- override를 재정의하고나면 new Weapon(){} 을 w2라는 변수에 넣을 수 있다.
이 지역변수를 useWeapon(w2);에다 전달하는 것
- 하지만 w2라는 변수는 한번밖에 사용하지 않았는데,
변수를 굳이 만들어야할까? 이 내용을 useWeapon() 안에 넣기만 하면 되는 거 아닌가?
useWeapon( new Weapon() { } );
- 위와 같은 형태로 지역변수를 만들지 않고 useWeapon() 안에서 바로 객체를 만들어서
아래 메소드의 매개변수로 전달할 수 있다.
<MainClass06>
package test.main;
import test.mypac.Weapon;
public class MainClass06 {
static Weapon w1=new Weapon() {
@Override
public void attack() {
System.out.println("편하게 공격해요");
}
};
public static void main(String[] args) {
Weapon w2=new Weapon() {
@Override
public void attack() {
System.out.println("아무나 공격!");
}
};
useWeapon(new Weapon() {
@Override
public void attack() {
System.out.println("공격! 공격!");
}
});
}
public static void useWeapon(Weapon w) {
w.prepare();
w.attack();
}
}
- 위와 같이 anonymous inner type을 자동완성으로 사용할 수 있다.
- Weapon w1=new Weapon 에서 ctrl+space 하면 자동완성되는 모양이 뜬다.
- 메인메소드 안에서도 Weapon w2=new Weapon 상태로 ctrl+space 사용가능.
- useWeapon ( new Weapon() { } ); 구조를 기억하기!
'국비교육(22-23)' 카테고리의 다른 글
18일차(1)/java(20) : 추상 클래스, 인터페이스 정리 / 람다식 (0) | 2022.10.31 |
---|---|
17일차(4)/java(19) : Interface (0) | 2022.10.30 |
17일차(2)/java(17) : Abstract Class (0) | 2022.10.28 |
17일차(1)/java(16) : 상속, 다형성, 접근지정자 정리 (0) | 2022.10.28 |
16일차(3)/java(15) : Extends, 접근 지정자 (0) | 2022.10.27 |