1. 클래스에서 중첩 클래스 사용 제한
- 인스턴스 멤버 클래스는 클래스의 인스턴스 필드의 초기값이나 인스턴스 메소드에서 객체를 생성할 수 있습니다.
- 인스턴스 멤버 클래스는 정적 필드의 초기값이나 정적 메소드에서는 객체를 생성할 수 없습니다.
public class OutterClass {
// 인스턴스 필드
NestedInstanceClass nestedInstanceClass1 = new NestedInstanceClass();
NestedStaticClass nestedStaticClass1 = new NestedStaticClass();
// 정적 필드
// static NestedInstanceClass nestedInstanceClass2 = new NestedInstanceClass(); (x)
static NestedStaticClass nestedStaticClass2 = new NestedStaticClass();
// 인스턴스 메소드
void instanceMethod() {
NestedInstanceClass nestedInstanceClass = new NestedInstanceClass();
NestedStaticClass nestedStaticClass = new NestedStaticClass();
}
// 정적 메소드
static void staticMethod() {
// NestedInstanceClass nestedInstanceClass = new NestedInstanceClass(); (x)
NestedStaticClass nestedStaticClass = new NestedStaticClass();
}
//==인스턴스 멤버 클래스==//
class NestedInstanceClass { }
//==정적 멤버 클래스==//
static class NestedStaticClass { }
}
2. 중첩 클래스에서 클래스 사용제한
멤버 클래스에서 사용제한
- 정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드와 메소드에만 접근할 수 있고 인스턴스 필드와 메소드는 접근할 수 없습니다.
public class OutterClass {
// 인스턴스 멤버
String instanceField;
void instanceMethod() { }
// 정적 멤버
static String staticField;
static void staticMethod() { }
//==인스턴스 멤버 클래스==//
class NestedInstanceClass {
void testMethod() {
System.out.println(instanceField);
instanceMethod();
System.out.println(staticField);
staticMethod();
}
}
//==정적 멤버 클래스==//
static class NestedStaticClass {
void testMethod() {
// System.out.println(instanceField); (x)
// instanceMethod(); (x)
System.out.println(staticField);
staticMethod();
}
}
}
로컬 클래스에서 사용제한
- 로컬 클래스 내부에서는 바깥 클래스의 필드나 메소드를 제한 없이 사용할 수 있습니다.
public class OutterClass {
// 인스턴스 멤버
String instanceField;
void instanceMethod() { }
// 정적 멤버
static String staticField;
static void staticMethod() { }
void localClassMethod() {
//==로컬 클래스==//
class LocalClass {
void testMethod() {
System.out.println(instanceField);
instanceMethod();
System.out.println(staticField);
staticMethod();
}
}
}
}
주의) 메소드의 매개 변수나 로컬 변수를 로컬 클래스에서 사용할 때
- 로컬 클래스의 객체는 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용될 수 있습니다.
- 매개 변수나 로컬 변수는 메소드 실행이 끝나면 스택 메모리에서 사라지기 때문에 로컬 객체에서 사용할 경우 문제 발생
문제 해결 방법 (자바)
컴파일 시 로컬 클래스에서 사용하는 매개 변수나 로컬 변수의 값을 로컬 클래스 내부에 복사해 두고 사용
그리고 매개 변수나 로컬 변수가 수정되어 값이 변경되면 로컬 클래스에 복사해 둔 값과 달라지는 문제를 해결하기 위해
매개 변수나 로컬 변수를 final로 선언해서 수정을 막습니다.
결론적으로 로컬 클래스에서 사용 가능한 것은 final로 선언된 매개 변수와 로컬 변수뿐
자바 7 이전
- final 키워드 없이 선언된 매개 변수나 로컬 변수를 로컬 클래스에서 사용하면 컴파일 에러 발생
void localClassMethod(final int number) {
final int ten = 10;
//==로컬 클래스==//
class LocalClass {
int plus10() {
return number + ten;
}
}
}
자바 8 이후
- final 키워드 없이 선언된 매개 변수나 로컬 변수를 사용해도 컴파일 에러가 발생하지 않음
- final 선언을 하지 않아도 여전히 값을 수정할 수 없는 final의 특성을 갖습니다.
- final 키워드 존재 여부의 차이점은 로컬 클래스의 복사 위치
[final 키워드에 따른 복사 위치]
final 키워드가 있는 경우 로컬 클래스의 메소드 내부에 지역 변수로 복사
final 키워드가 없는 경우 로컬 클래스의 필드로 복사
void localClassMethod(int number) {
int ten = 10;
// number = 10; (x) final 특성
// plusNumber = 100; (x) final 특성
//==로컬 클래스==//
class LocalClass {
int plus10() {
return number + ten;
}
}
}
3. 중첩 클래스에서 클래스 참조
- 클래스 내부에서 this는 객체 자신의 참조
- 중첩 클래스에서 this 키워드를 사용하면 바깥 클래스의 객체 참조가 아니라, 중첩 클래스의 객체 참조가 됩니다.
- 중첩 클래스에서 바깥 클래스 참조를 얻으려면 바깥 클래스의 이름을 this 앞에 붙여주면 됩니다.
바깥클래스.this.필드;
바깥클래스.this.메소드();
예시
public class OuterPerson {
public String name;
public String getName() {
return name;
}
//==인스턴스 멤버 클래스==//
class NestedInstancePerson {
private String name;
public String getName() {
return name;
}
public void printName() {
OuterPerson.this.name = "OuterPerson"; // 바깥 클래스 필드
this.name = "NestedInstancePerson"; // 자가 자신 필드(인스턴스 멤버 클래스 필드)
System.out.println("Outer Person Name: " + OuterPerson.this.getName());
System.out.println("Nested Instance PersonName: " + this.getName());
}
}
// 실행
public static void main(String[] args) {
OuterPerson outerPerson = new OuterPerson();
OuterPerson.NestedInstancePerson nestedInstancePerson = outerPerson.new NestedInstancePerson();
nestedInstancePerson.printName();
}
}
'Backend > Java' 카테고리의 다른 글
[Java] 문자열 값이 비어있는지 확인하기(isEmpty, isBlack, hasText) (0) | 2022.05.03 |
---|---|
[Java] 문자열 타입으로 변경하기 (String Class) (0) | 2022.05.02 |
[Java] 중첩 클래스 (0) | 2022.04.26 |
[Java] 인터페이스 확장 (디폴트 메소드의 필요성) (0) | 2022.04.25 |
[Java] 인터페이스 상속 (0) | 2022.04.25 |