🏃♂️ 들어가기 앞서..
본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕
*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.
inner class
)" 클래스 안의 클래스 "
말 그대로
클래스 안에
내부에 선언된 클래스인 것이다.
이런 구조로 선언하는 이유는
두 클래스가 서로 매우 긴밀한 관계에 있기 때문이다.
class A {
...
}
class B {
...
}
// ▼▼▼▼▼▼▼
class A { // 'B'의 외부 클래스
...
// 클래스 A의 멤버같은 긴밀함
class B { // 'A'의 내부 클래스
...
}
...
}
《내부 클래스》에서 외부 클래스 멤버 들을 쉽게 접근할 수 있다.
: 객체를 별도로 만들 필요도 없이 외부 클래스의 멤버를 사용할 수 있다.
코드 복잡성 감소 ( " 캡슐화 " )
class A {
int i = 100 ;
B b = new B() ;
}
class B {
void method() {
A a = new A() ;
System.out.println(a.i) ;
}
}
class C {
B b = new B() ; // 문제 없음
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.method(); // -> 100출력
}
}
/*
▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
*/
class A {
int i = 100 ;
B b = new B() ;
class B {
void method() {
// 객체 생성없이 멤버 변수 사용 가능
System.out.println(i) ;
}
}
}
/*
class C {
B b = new B() ;
// Error : B클래스는 A 내부에서만 사용 가능함
}
*/
"변수" 의 〔 선언위치에 따른 종류 〕와 같다.
( 유효범위(scope) & 접근성(accessibility) 동일 )
종류 | 특징 |
---|---|
인스턴스 내부클래스 (instance class) | <외부 클래스 멤버변수 선언위치> " 인스턴스 변수 "처럼 다루어지고 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용 |
스태틱 내부클래스 (static class) | <외부 클래스 멤버변수 선언위치> " static 변수 "처럼 다루어지고 주로 static 메서드에서 사용될 목적으로 선언됨 |
지역 내부클래스 (local class) | <외부클래스 메서드 / 초기화블럭 내부> 선언된 영역 내부에서만 사용 가능 |
익명 내부클래스 (Anonymous class) | 클래스 선언 & 객체 생성 을 동시에 하는 " 이름없는 클래스 (일회용) " |
내부클래스 도
엄연한 " 클래스 "이기 때문에
<abstract
나final
>과 같은 제어자를 사용할 수 있고멤버변수들처럼
<private
/protected
/public
/(default)
> 같은 " 접근제어자도 사용할 수 있다.
" 인스턴스(instance) 내부 클래스 "와
" 스태틱(static) 내부 클래스 "는
" 외부클래스의 멤버변수 (인스턴스 변수 & 클래스 변수) "와 같은 위치에 선언된다.
( 성질 또한 멤버변수와 같은 성질을 가짐. )
《 짚고 넘어가자! 》
인스턴스 멤버가 static 멤버 사용은 가능하지만
static 멤버가 인스턴스 멤버 사용하는 것은 불가능하다.
class Test_2 {
class InstanceInner {} // 인스턴스 내부 클래스
static class StaticInner {} // static 내부 클래스
// 인스턴스 멤버끼리 " 직접접근 " 가능
InstanceInner iv = new InstanceInner() ;
// static 멤버끼리 " 직접접근 " 가능
StaticInner cv = new StaticInner() ;
/*
같은 클래스 내에서의 각 내부 클래스 간 접근성
*/
// static 멤버의 " 인스턴스 멤버 직접접근 " 불가능
static void staticM() {
// InstanceInner obj1 = new InstanceInner() ;
StaticInner obj2 = new StaticInner() ;
// 단, 외부 클래스(Test_2) 인스턴스 생성하면 가능
// (실제로 이렇게까지 쓰지말자...ㅎㅎ)
Test_2 outer = new Test_2() ;
InstanceInner obj1 = new InstanceInner() ;
}
// 인스턴스 멤버의 " static 멤버 직접접근 " 가능
void instanceM() {
InstanceInner obj1 = new InstanceInner() ;
StaticInner obj2 = new StaticInner() ;
// 당연히 지역 내부 클래스는 외부에서 접근 불가
// LocalInner lv = new LocalInner();
}
void myM() {
class LocalInner {} // 지역 내부 클래스 생성
LocalInner lv = new LocalInner();
}
}
class Test_2 {
class InstanceInner { // 인스턴스 내부 클래스
int iv = 100 ; // 인스턴스 변수
// static int cv = 100 ; // static 변수 선언 불가 _ static 클래스에서만 선언가능
final static int Const = 100 ; // 상수(constant)는 선언 가능
}
static class StaticInner { // static 내부 클래스
int iv = 200 ;
static int cv = 200 ; // static 메서드라 가능
}
void method() {
class LocalInner { // 지역 내부 클래스
int iv = 300 ;
// static int cv = 300 ; // static 변수 선언 불가 _ static 클래스에서만 선언가능
final static int Const = 100 ; // 상수(constant)는 선언 가능
}
public static void main(String[] args) {
System.out.println(InstanceInner.CONST) ;
System.out.println(StaticInner.cv) ;
// System.out.println(LocalInner.CONST) ; 은 불가능
}
<출력>
100
200
내부 클래스 中
당연히
< static클래스 >만 " static 멤버 " 를 가질 수 있고
static 내부 클래스에서는
" 외부클래스의 인스턴스 멤버에 접근할 수 없다. "
드물지만
static 변수를 선언해야한다면
스태틱 클래스로 선언해야 한다.
( ★ " final static
붙은 변수 " ▶ 상수(constant) _ 모든 내부 클래스에서 정의 가능 )
❗ 틈새 꿀팁 ❗
[ 상수 선언 ]
- ~마다 다르지만 정해진 후엔 바뀌면 안된다. =
final
- 처음부터 절대적으로 설정 =
final static
class Outer {
private int outerIv = 0 ; // private변수
static int outerCv = 0 ; // static 변수
/* 인스턴스 내부 클래스 */
class InstanceInner {
int iiv = outerIv ; // 외부클래스 <private멤버> " 접근 가능 "
int iiv2 = outerCv ; // 외부클래스 static멤버 " 접근 가능 "
}
/* static 내부 클래스 */
static class StaticInner {
// int siv = outerIv ; // 외부클래스 <인스턴스 멤버> " 접근 불가 "
static int siv2 = outerCv ; // 외부클래스 static멤버 " 접근 가능 "
}
/* 메서드 내 [지역 내부 클래스] */
void myM() {
int lv = 0 ; //지역변수 -> 메서드 종료 소멸
final int LV = 0 ; // (JDK1.8부터 final 생략 가능하대요~
/*
메서드는 종료되서 소멸되는데
오히려 지역 클래스 객체가 더 오래 존재하는 경우 발생 가능
그래서 lv(지역변수) 사용 못하게끔 하는 것
*/
class LocalInner { // 지역 내부 클래스
int liv = outerIv ;
int liv2 = outerCv ;
//외부 클래스의 지역변수는 "상수" 만 접근 가능
// int liv3 = lv ; // 에러!
int liv4 = LV ; // 상수 접근 _ 문제 x
<< JDK1.8 부터 >>
/* final이 생략이 가능해졌는데 그렇다면 일반 "변수"인 것인데 ' 값이 안바뀌는 변수일 경우 ' 에러가 발생하지 않는다. */ class LocalInner { // 지역 내부 클래스 int liv = outerIv ; int liv2 = outerCv ; //외부 클래스의 지역변수는 "상수" 만 접근 가능 int liv3 = lv ; // lv 접근 가능!! int liv4 = LV ; // 상수 접근 _ 문제 x /* 만약 값이 바뀌게 되면 바로 컴파일 에러가 발생!!! */
사실 이런경우는
매우 드물다
" 타 클래스에서 내부 클래스에 접근한다 "
이것은
" 내부 클래스로 선언 자체를 하면 안됐었던 것 "이기 때문에
그저 참고용이다.
/* 내부 클래스를 가진 (외부)클래스 */
class Outer {
class InstanceInner {
int iv = 100 ;
}
static class StaticInner {
int iv = 200 ;
static int cv = 300 ;
}
void method() {
class LocalInner { // 지역 내부 클래스
int iv = 300 ;
}
}
}
class Test_3 {
public static void main(String[] args) {
// (외부)클래스 인스턴스 먼저 생성해야 한다
Outer oc = new Outer() ;
Outer.InstanceInner iI = oc.new InstanceInner(); // .을 통해 인스턴스 생성 가능
/*
static 내부 클래스의 인스턴스는
(외부)클래스 먼저 생성하지 않아도 된다.
대신 Outer.~ 형식으로 접근
*/
Outer.StaticInner sI = new Outer.StaticInner() ;
System.out.println("iI.iv : " + iI.iv) ;
System.out.println("Outer.StaticInner.cv : " + Outer.StaticInner.cv) ;
System.out.println("sI.iv : " + sI.iv) ;
}
}
<출력>
iI.iv : 100
Outer.StaticInner.cv : 300
sI.iv : 200
우리가 지겹도록 공부했던
그것(?)이 생각날 것이다.
이름이 같을 때,
구분할 수 있는 방법은?
바로
" this " 이다.
아 그리고 하나 더,
" (외부 클래스명).this
" 형식도 가능하다.
class Outer {
int value = 100 ;
class Inner {
int value = 200 ;
void method() {
int value = 300 ;
// 현재 메서드 내 지역 변수 (lv)
System.out.println("value : " + value) ;
// 현 인스턴스(Inner class) 변수 (Inner iv)
System.out.println("this.value : " + this.value) ;
// 현 외부 클래스 변수 (Outer iv)
System.out.println("Outer.this.value : " + Outer.this.value) ;
}
}
}