day21 - JAVA (inner class, static 내부 클래스, non-static 내부 클래스, 지역 내부 클래스, 무명 클래스)
[inner class]
-> 클래스 내부에 다시 클래스를 선언해야 하는 경우가 있다.
-> 이렇겍 클래스 내부에 들어 있는 클래스를 내부 클래스라고 한다.
-> 내부 클래스(중첩 클래스: nested class)는 바깥 클래스(Outer class)의 다른 멤버(메소드, 멤버변수를 말함) 와 같은 클래스의 멤버가 된다.
-> 내부 클래스는 다른 클래스 멤버와 마찬가지로 접근 속성을 가질 수도 있으며, 바깥 클래스 외부에서의 접근가능 여부는 접근 제어자에 의해 결정된다.
[static 내부 클래스]
-> static 내부 클래스(static inner class)는 내부 클래스의 객체를 바깥 클래스에 대해 독립적으로 만들 때 사용
-> static 키워드를 가진 내부 클래스로, 멤버 변수나 메소드처럼 클래스 내부에서 선언
-> 다른 클래스에서 Outer 클래스 내부의 클래스인 inner 클래스에 접근하기 위해서 객체를 생성할 때 다음과 같이 객체를 생성한다.
-> 클래스 이름 다음에 바로 inner 클래스 이름 사용
[non-static 내부 클래스]
-> non-static 내부 클래스는 static 내부 클래스와 선언되는 위치는 같으나 static 선언되지 않은 내부클래스 이다.
-> 다른 클래스에서 Outer 클래스의 내부클래스인 Inner 클래스에 접근하기 위해서 객체를 생성할 때는 먼저 바깥 클래스의 객체를 생성해서 그 레퍼런스를 가지고 내부 클래스의 객체를 생성한다.
[지역 내부 클래스(local inner class)]
-> static 과 non-static 내부 클래스가 바깥 클래스의 멤버의 위치에 선언되는 것에 비해, 지역 내부 클래스는 바깥 클래스의 메소드 안에 선언된 내부클래스이다.
[무명 클래스(anonymous inner class)]
-> 무명 내부 클래스는 지역 내부클래스의 변형으로 클래스 명을 갖지 않고 한번만 사용할 수 있다.
-> 주로 이벤트 처리에 많이 사용된다.
[내부 클래스 ex]
package javaPro.java_inner;
/*
* 내부 클래스 예제
*
* 인스턴스 내부클래스 : (static)클래스 멤버를 가질 수 없다. 단 상수는 가능
* static 내부클래스 : (static)클래스 멤버를 가질 수 있다.
* 지역내부클래스 : 메서드 내에 선언된 클래스. 메서드 내부에서만 사용이 가능함.
* 이름없는(무명의)내부클래스 : 클래스 없이 객체화 가능한 클래스
* 추상클래스,인터페이스 의 객체화 가능함.
*
*/
class Outer1 {
class instanceInner {// 인스턴스 내부 클래스
int iv = 100;
//static int cv = 10; // 클래스 멤버를 가질 수 없다.
final static int MAX = 200;
}
static class StaticInner { //static 내부 클래스
int iv = 300;
static int cv = 400;
final static int MAX = 500;
}
void method(){ // 지역 내부 클래스
class LocalInner{
int iv = 600;
//static int cv = 700; //클래스 멤버를 가질 수 없다.
final static int MAX = 700; // 상수는 가능하다.
}
LocalInner lc = new LocalInner();
System.out.println(lc.iv); // 600
System.out.println(lc.MAX); // 700
System.out.println(LocalInner.MAX); // 700
}
void method2(){
//LocalInner lc = new LocalInner(); // -> method() 메서드에서만 사용가능하다.
}
}
public class InnerEx1 {
public static void main(String[] args) {
Outer1.StaticInner si = new Outer1.StaticInner();
System.out.println(si.iv); //300
System.out.println(Outer1.StaticInner.cv); // 400
System.out.println(Outer1.StaticInner.MAX); // 500
//Outer1.InstanceInner ii = new Outer1.InstanceInner();
Outer1 outer = new Outer1();
Outer1.instanceInner ii2 = outer.new instanceInner();
System.out.println(ii2.iv); // 100
System.out.println(Outer1.instanceInner.MAX);
outer.method();
}
}
[지역 내부 클래스 주의해야 할 점]
-> 지역 내부 클래스에서 사용되는 메서드의 지역변수는 상수화(final) 되어야 한다.
-> 즉, 로컬 변수인데 final이 아닌 지역 변수는 내부 클래스에 있는 메서드 내에서 사용할 수 없다.
package javaPro.java_inner;
//[지역 내부클래스에서 사용되는 메서드의 지역변수는 상수화(final) 되어야 한다.]
class Outer2 {
private static int outercv = 20; //outercv 선언
static StaticInner cv = new StaticInner();
static InstanceInner cv2 = new Outer2().new InstanceInner();
// cv2의 타입은 InstantceInner, outer2 객체 생성후 InstantceInner 메모리 할당
static class StaticInner { // static inner class
int siv = new Outer2().outeriv;
static int scv = outercv;
}
static StaticInner cv3 = new StaticInner(); // static inner 클래스도 이렇게 선언해서 사용 가능
InstanceInner iv = new InstanceInner();
private int outeriv = 10; // outeriv 선언
class InstanceInner {
int iiv = outeriv;
int iiv2 = outercv;
}
void method(int pv) {
//지역 내부클래스에서 사용되는 메서드의 지역변수는 상수화(final) 되어야 한다.
int i = 0; // 이 i 처럼 메소드 안의 지역변수는 지역 내부클래스에서 사용되려면 final 이어야 한다.
//pv++; // 이 코드를 실행하면 아래 print 문에서 오류가 난다.(final 은 한번 초기화 하고 수정이 불가능)
//i++; // 이 코드를 실행하면 아래 print 문에서 오류가 난다.(final 은 한번 초기화 하고 수정이 불가능)
// -> 이 변수들을 수정시켰을 때 시스템 내에서 이 변수는 final이 아니라고 판단하게 되기 때문
outeriv++; // 이건 가능
class LocalInner { // 지역 내부 클래스
int liv = outeriv; // 외부 클래스의 private 멤버 접근 가능
int liv2 = outercv; // 외부 클래스의 private 멤버 접근 가능
void method() {
//지역 내부 클래스에서 내부 클래스가 속한 메서드의 지역변수 변경 안됨
// i = 100;
//pv++;
System.out.println("i=" + i);
System.out.println("pv=" + pv);
System.out.println(liv + ", " + liv2);
System.out.println(outeriv + ", " + outercv); // 외부클래스의 private 멤버 접근 가능
}
}
LocalInner li = new LocalInner();
li.method();
}
}
public class InnerEx2 {
public static void main(String[] args) {
Outer2 out = new Outer2();
out.method(1);
Outer2.InstanceInner i2 = out.new InstanceInner();
System.out.println(i2.iiv);
System.out.println(i2.iiv2);
//Outer2.StaticInner i3 = new Outer2().StaticInner();
//System.out.println(i3.siv);
System.out.println(Outer2.StaticInner.scv);
}
}