내부 클래스를 만드는 이유는 주로 캡슐화 때문
내부 클래스
- 클래스 내부에 선언한 클래스. 중첩 클래스라고도 함
- 종류 : 인스턴스 내부 클래스, 정적내부 클래스, 지역 내부 클래스, 익명 내부 클래스(이걸 제일 많이 사용함)
인스턴스 내부 클래스
- 외부 클래스가 instance화 되어야 생성이 가능
정적내부 클래스
- 외부 클래스의 생성과 상관없이 생성 가능
지역 내부 클래스(local class)
- 메서드 내부에서 정의하여 사용하는 클래스
- 로컬 변수를 선언하듯이 선언.
- 메서드의 호출이 끝나면 메서드에 사용된 지역변수의 유효성은 사라짐(스택에 담겼다가 없어지니까)
- 그런데 지역 내부 클래스에서 바깥 메서드의 지역변수의 값을 변경하려고 하면 그 변수의 생성시기가 다르기에 값 변경이 불가능함
- 바깥 메서드의 i, num이 stack에 담겼다가 사라지면(함수가 끝날때) 값 참조도 불가능하니 아예 상수 pool에다가 저 값들을 넣어줌(final로 선언)
class Outer{ int outNum = 100; static int sNum = 200; Runnable getRunnable(int i){ int num = 100; class MyRunnable implements Runnable{ int localNum = 10; @Override public void run() { //num = 200; //에러 남. 지역변수는 상수로 바뀜 //i = 100; //에러 남. 매개 변수 역시 지역변수처럼 상수로 바뀜 System.out.println("i =" + i); System.out.println("num = " +num); System.out.println("localNum = " +localNum); System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수)"); System.out.println("Outter.sNum = " + Outer.sNum + "(외부 클래스 정적 변수)"); } } return new MyRunnable(); } } Outer out = new Outer(); Runnable runner = out.getRunnable(100); runner.run(); // 이부분에서 바깥 메서드의 변수들에 대한 접근이 문제가 됨
익명 내부 클래스
- 지역 내부 클래스에서 MyRunnable이라는 이름은 그 안에서만 불리기에 굳이 필요가 없음
- 그래서 그냥 바로 new Runnable(){}로 해서 return 해버림. 구현되어야 하는것(interface기에 Override해주어야 하는 method들)은 body에 구현하고
class Outer{ Runnable getRunnable(int i){ return new Runnable(){ @Override public void run(){ .... } } } }