[작성일: 2023. 02. 01]
내부 클래스(inner class)
- 클래스 안의 클래스
- 내부 클래스에서 외부 클래스의 멤버들을 객체생성 없이 쉽게 접근할 수 있음.
- 코드의 복잡성을 줄일 수 있음.(캡슐화)
- 내부 클래스의 종류와 유효범위(scope)는 변수와 동일함.(iv, cv, lv)
class A { // B 클래스의 외부 클래스
int i = 100;
B b = new B();
class B { // A 클래스의 내부 클래스
void method() {
System.out.println(i); // 객체 생성없이 외부 클래스의 멤버 접근 가능
}
}
}
// class C {
// B b = new B(); // 사용 불가
// }
public class InnerTest {
public static void main(Strint[] args) {
}
}
내부 클래스 | 특징 |
인스턴스 클래스 (instance class) |
- 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다루어짐. - 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언 됨. |
스태틱 클래스 (static class) |
- 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static 멤버처럼 다루어짐. - 주로 외부 클래스의 static 멤버, 특히 static 메서드에서 사용될 목적으로 선언 됨. |
지역 클래스 (local class) |
- 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있음. |
익명 클래스 (anonymous class) |
- 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스 (일회성) - AWT, SWING 등 이벤트 처리에 쓰임. |
내부 클래스의 제어자와 접근성
- 내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일함.
- 내부 클래스의 접근 제어자는 default와 public 뿐만 아니라, private, protected도 가능함.
- static 멤버를 가질 수 있는 건 static 클래스뿐이므로 주의해서 작성할 것
- 외부 클래스의 객체를 먼저 생성해야 내부 클래스의 객체 생성이 가능해짐.
class Ex7 {
class InstanceInner {
int iv = 100;
static int cv = 100; // 에러! static 변수 선언 불가능
final static int CONST = 100; // final static은 상수이므로 허용함.
}
static class StaticInner {
int iv = 200;
static int cv = 200; // static 클래스만 static 멤버 정의 가능.
}
void myMethod() {
class LocalInner {
int iv = 300;
static int cv = 300; // 에러! static 변수 선언 불가능
final static int CONST = 300; // final static은 상수이므로 허용함.
}
int i = LocaliNNER.const; // ok
}
public static void main(String[] args) {
System.out.println(InstanceInner.CONST); // 가능
System.out.println(StaticInner.cv); // 가능
// System.out.println(LocalInner.CONST);
// 에러! 지역 내부 클래스는 메서드 내에서만 사용 가능함.
}
class Ex7_2 {
class InstacneInner {}
static class StaticInner {}
InstanceInner iv = new instanceInner(); // 인스턴스 멤버끼리는 접근 가능
static Staticinner cv = new StaticInner(); // static 멤버끼리는 접근 가능
static void staticMethod() { // static 멤버는 인스턴스 멤버에 직접 접근 불가능
// InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
}
void instanceMethod() { // 인스턴스 메서드에서는 인스턴스 멤버와 static 멤버 모두 접근 가능
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// LocalInner lv = new LocalInner(); // 지역 내부 클래스는 외부에서 접근 불가능
}
void myMethod() {
class LocalInner {}
LocalInner lv = new LocalInner(); // 내부에서만 사용 가능
}
}
class Outer {
private int outerIv = 0;
static int outerCv = 0;
class InstanceInner {
int iiv = outerIv; // 외부 클래스의 private 멤버 접근 가능
int iiv2 = outerCv;
}
static class StaticInner {
int siv = outerIv; // static 클래스는 외부 클래스의 인스턴스 멤버에 접근 불가능
static int scv = outerCv; // 외부 클래스의 static 맴버 접근 가능
}
void myMethod() {
int lv = 0; // 메서드 종료와 함께 지역변수는 소멸됨.
final int LV = 0; // JDK1.8부터 final 생략 가능
class LocalInner {
int liv = outerIv;
int liv2 = outerCv;
// 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근 가능함.
int liv3 = lv; // JDK1.8부터 값이 안 바뀌면 상수로 취급하기 때문에 에러 없음.
int liv4 = lV; // OK
}
}
}
class Outer2 {
class InstanceInner {
int iv = 100;
}
static class StaticInner {
int iv = 200;
static int cv = 300;
}
void myMethod() {
class LoclaInner {
int iv = 400;
}
}
}
class Ex7_3 {
public static void main(String[] args) {
Outer2 oc = new Outer2(); // 외부 클래스의 객체를 먼저 생성해야 내부 클래스 객체 생성 가능
Outer2.InstanceInner ii = oc.new InstanceInner();
System.out.println("ii.iv);
System.out.println("Outer2.StaticInner.cv);
// static 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 됨.
Outer2.StaticInner si = new Outer2.StaticInner();
// 앞에 외부 클래스 이름 붙여줘야 함.
System.out.println(si.iv);
}
}
class Outer3 {
int value = 10; // Outer3.this.value, 외부 클래스의 iv
class Inner {
int valuee = 20; // this.value , 내부 클래스의 iv
void method1() {
int value = 30; // lv
System.out.println(value); // 가까운 value 출력 -> lv
System.out.println(this.value);
System.out.println(Outer3.this.value);
}
}
}
class Ex7_4 {
public static void main(String[] args) {
Outer3 outer = new Outer3();
Outer3.Inner inner = outer.new Inner();
inner.method1();
}
}
// 결과
30
20
10
익명 클래스(anonymous class)
- 이름이 없는 일회용 클래스(조상의 이름 사용)
- 클래스의 정의와 생성을 동시에 함.
new 조상클래스이름() { // ex) new Ojbect() {}
// 멤버 선언
// 클래스의 내용
}
또는
new 구현인터페이스이름() {
// 멤버 선언
}
//Java의 AWT에서 자주 사용함.
import java.awt.*;
class 7_5 {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new ActionListener() {
// 클래스의 정의와 객체 생성을 동시에 함. 조상의 이름 사용.
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent Occurred!");
}
}
}
}
🐣 해당 게시글은 자바의 정석(남궁성 님) 영상으로 함께 공부하며 요약/정리한 글입니다.
🐣 입문 개발자가 작성한 글이므로 틀린 내용이나 오타가 있을 수 있습니다.