티스토리 뷰
주의 사항!
- 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
- 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
- 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.
바깥 필드와 메서드에서 사용 제한
인스턴스 멤버 클래스는 바깥 클래스의 인스턴스 필드의 초기값으로 사용될 객체를 생성하거나 인스턴스 메서드에서 객체를 생성할 수 있습니다. 하지만 정적 필드의 초기값으로 사용될 객체를 생성하거나 정적 메서드에서 객체를 생성하는 것은 불가능합니다. 반면 정적 멤버 클래스는 모든 필드의 초기값이나 모든 메서드에서 객체를 생성할 수 있습니다.
즉, 인스턴스 멤버 클래스는 인스턴스 필드와 인스턴스 메서드에 대해서만 객체를 생성할 수 있고, 정적 멤버 클래스는 정적 필드와 메서드에 대해서도 객체를 생성할 수 있습니다.
//인스턴스 필드
B field1 = new B();
C field2 = new C();
//인스턴스 메서드
void method1()
{
B var1 = new B();
C var2 = new C();
}
//정적 필드 초기화
//static B field3 = new B(); 에러 발생
static C field4 = new C();
//정적 메서드
static void method2()
{
//B var1 = new B(); 에러 발생
C var2 = new C();
}
//인스턴스 멤버 클래스
class B {}
//정적 멤버 클래스
static class C {}
(이유는 제가 생각해 보기로 다음과 같습니다. 인스턴스 필드와 메서드는 클래스의 인스턴스를 생성해야만 사용할 수 있습니다. 반면, 정적 필드와 메서드는 인스턴스를 생성하지 않아도 사용할 수 있습니다.
클래스 A 안에 멤버로서 클래스 B가 선언되었다고 가정해 보겠습니다. 그리고 클래스 A에는 정적 필드와 정적 메서드도 있습니다. 클래스 A의 정적 필드와 정적 메서드는 클래스 A의 인스턴스를 생성하지 않아도 사용할 수 있어야 합니다. 이때 정적 필드는 반드시 초기값을 가지고 있어야 합니다. 클래스 A의 정적 필드의 초기값으로 클래스 B의 인스턴스를 사용하고, 정적 메서드에서는 클래스 B의 인스턴스를 생성하고 있다고 생각해 보겠습니다. 만약 클래스 B가 인스턴스 멤버로서 선언되어 있다면 어떻게 될까요?
클래스 B는 클래스 A의 인스턴스가 생성되지 않으면 사용할 수 없습니다. 따라서 클래스 A의 인스턴스가 생성되지 않아도 사용할 수 있어야 할 정적 필드와 정적 메서드에서 클래스 A의 인스턴스가 반드시 필요한 클래스 B가 사용된다는 것은 전혀 맞지 않습니다. 클래스 B도 클래스 A의 인스턴스에 독립적이어야 합니다. 따라서 클래스 A의 정적 필드와 정적 메서드에는 정적 멤버로서 선언된 클래스 B만 사용될 수 있습니다.)
멤버 클래스에서 사용 제한
인스턴스 멤버 클래스 안에서는 바깥 클래스의 모든 필드와 메서드에 접근할 수 있지만, 정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드와 메서드에만 접근할 수 있고 인스턴스 필드와 메서드는 접근할 수 없습니다.
(왜냐하면 인스턴스 멤버 클래스는 바깥 클래스의 인스턴스가 생성되어야 사용할 수 있는데 바깥 클래스의 인스턴스가 생성되면 바깥 클래스의 인스턴스 멤버까지 모두 사용할 수 있게 되기 때문입니다. 하지만 정적 멤버 클래스는 바깥 클래스의 인스턴스가 생성되지 않아도 사용할 수 있어야 하는데 이때는 바깥 클래스의 인스턴스 멤버들을 사용할 수 없으므로 정적 멤버들에만 접근할 수 있게 되는 것입니다.)
//ClassA.java
package chapter00.exam00;
public class ClassA
{
int field1;
static int field2;
void method1()
{
System.out.println("run method1");
}
static void method2()
{
System.out.println("run static method2");
}
class B
{
void method3()
{
System.out.println("run class B method3");
field1 = 10;
method1();
field2 = 20;
method2();
}
}
static class C
{
void method4()
{
System.out.println("run static class C meteod4");
//field1 = 10;
//method1();
field2 = 10;
method2();
}
}
}
//exam00.java
package chapter00.exam00;
public class exam00
{
public static void main(String[] args)
{
ClassA.method2();
ClassA.field2 = 2;
ClassA a = new ClassA();
a.method1();
a.field1 = 1;
ClassA.B b = a.new B();
b.method3();
ClassA.C c = new ClassA.C();
c.method4();
}
}
/*
실행결과
run static method2
run method1
run class B method3
run method1
run static method2
run static class C meteod4
run static method2
*/
로컬 클래스에서 사용 제한
로컬 클래스 내부에서는 바깥 클래스의 필드나 메서드를 제한 없이 사용할 수 있습니다. 문제는 메서드의 매개 변수나 로컬 변수를 로컬 클래스에서 사용할 때입니다. 로컬 클래스의 객체는 메서드의 실행이 끝나도 힙 메모리에 존재해서 계속 사용될 수 있습니다. 그런데 매개 변수나 로컬 변수는 메서드의 실행이 끝나면 스택 메모리에서 사라지기 때문에 로컬 객체에서 사용할 경우 문제가 발생합니다.
자바는 이 문제를 해결하기 위해 컴파일 시 로컬 클래스에서 사용하는 매개 변수나 로컬 변수의 값을 로컬 클래스 내부에 복사해 두고 사용합니다. 그리고 매개 변수나 로컬 변수가 수정되어 값이 변경되면 로컬 클래스에 복사해둔 값과 달라지는 문제를 해결하기 위해 매개 변수나 로컬 변수를 final로 선언해서 수정을 막습니다. 결론적으로 말해서 로컬 클래스에서 사용 가능한 것은 final로 선언된 매개 변수와 로컬 변수뿐이라는 것입니다.
매개 변수나 로컬 변수를 final로 선언하지 않아도 여전히 값을 수정할 수 없는 fianl의 특성을 갖습니다. final 키워드의 존재 여부의 차이점은 로컬 클래스의 복사 위치입니다. final 키워드가 있다면 로컬 클래스의 메서드 내부에 로컬 변수로 복사되지만, final 키워드가 없다면 로컬 클래스의 필드로 복사됩니다.
void outMethod(final int arg1, int arg2)
{
final int var1 = 1;
int var2 = 2;
class LocalClass
{
void method()
{
int result = arg1 + arg2 + var1 + var2;
}
}
}
생각할 게 많아 보이지만 우리는 로컬 클래스의 내부 복사 위치에 신경 쓸 필요 없이 로컬 클래스에서 사용된 매개 변수와 로컬 변수는 모두 final 특성을 갖는다는 것만 알면 됩니다.
(로컬 클래스가 바깥 클래스의 필드나 메서드를 제한 없이 사용할 수 있다고 했지만, 이는 로컬 클래스가 선언된 메서드의 따라 달라집니다. 로컬 클래스가 선언된 메서드가 인스턴스 메서드라면 모든 필드와 메서드를 사용할 수 있지만, 정적 메서드라면 정적 필드와 정적 메서드만 사용할 수 있습니다.)
중첩 클래스에서 바깥 클래스 참조 얻기
클래스 내부에서 this는 객체 자신의 참조입니다. 중첩 클래스에서 this 키워드를 사용하면 바깥 클래스의 객체 참조가 아니라, 중첩 클래스의 객체 참조가 됩니다. 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 바깥 클래스의 이름을 this 앞에 붙여주면 됩니다.
바깥클래스.this.필드;
바깥클래스.this.메서드();
'공부 일지 > JAVA 공부 일지' 카테고리의 다른 글
자바, 익명 객체 (0) | 2021.04.13 |
---|---|
자바, 중첩 인터페이스 (0) | 2021.04.13 |
자바, 중첩 클래스 (0) | 2021.04.11 |
자바, 중첩 클래스와 중첩 인터페이스란? (0) | 2021.04.11 |
자바, 디폴트 메서드와 인터페이스 확장 (0) | 2021.04.11 |