내부 클래스 (Inner Class)
내부 클래스는 클래스 안에 선언된 클래스이다. 주로 서로 깊은 관계에 있는 클래스에 사용하며 두 클래스의 멤버 간 쉬운 접근이 가능하고 외부에는 불 필요한 클래스의 노출을 감춰 코드를 간결하게 작성할 수 있다.
즉 객체지향의 '캡슐화'와도 관련이 어느 정도 있는 듯하다
장점을 정리하면
- 내부 클래스에서 외부 클래스의 멤버들에 쉽게 접근 가능
- 코드의 복잡함을 줄임 (캡슐화)
class A //외부 클래스
{
...
class B // 내부 클래스
{
...
}
static class C //정적 내부 클래스
{
...
}
void test()
{
class D //지역 내부 클래스
{
...
}
}
...
}
위와 같은 구조이며 내부 클래스는 외부 클래스를 제외하고는 다른 클래스에서 잘 쓰이지 않는 것이어야 한다.
클래스 간에 서로 밀접한 관계가 있는 경우에만 내부 클래스를 구현한다.
내부 클래스는 변수와 비슷하게 선언하는 위치와 키워드에 따라 4가지의 유형으로 나뉜다.
내부 클래스 | 선언 위치 | 사용 가능한 변수 |
인스턴스 내부 클래스 instance inner class |
외부 클래스의 멤버변수 선언위치 (멤버 내부 클래스) <외부 클래스 인스턴스 멤버들과 관련작업 목적> |
외부 인스턴스 변수 외부 전역 변수 |
정적 내부 클래스 static inner class |
외부 클래스의 멤버변수 선언위치 (멤버 내부 클래스) <외부 클래스 static멤버(메서드)에서 사용 목적> |
외부 전역 변수 |
지역 내부 클래스 local inner class |
외부 클래스의 메서드나 초기화 블럭 내부 | 외부 인스턴스 변수 외부 전역 변수 |
익명 내부 클래스 anonymous inner class |
클래스의 선언과 객체의 생성을 동시에 하는 일회용 익명 클래스 |
외부 인스턴스 변수 외부 전역 변수 |
인스턴스 내부 클래스
객체 내부에 멤버의 형태로써 존재하며, 외부 클래스의 모든 접근 지정자 멤버에 접근 가능
인스턴스 내부의 클래스는 외부 클래스를 먼저 생성 한 다음에 사용할 수 있는 특징이 있다. 따라서 클래스의 생성과 관계없이 사용 가능한 static 변수와 static 메서드는 인스턴스 내부 클래스에서 선언할 수 없다.
package Collection_Framework;
public class Inner_class_prac {
public static void main(String[] args) {
OuterClass o_class = new OuterClass();
System.out.println("외부 클래스 사용해서 내부 클래스 기능 호출");
o_class.testClass();
}
}
class OuterClass // 외부 클래스
{
private int num = 100; // 외부 클래스 필드 변수
private static int S_num = 500; // 외부 클래스 필드 변수 2
private inClass innerClass; // 내부 클래스 자료형 변수 선언
public OuterClass() // 외부 클래스 생성자
{
innerClass = new inClass();
}
//inClass innerClass = new inClass();
//외부 클래스는 기본생성자로 자동생성 시키고 내부클래스 인스턴스 만들어도 가능
class inClass // 인스턴스 내부 클래스
{
int inNum = 5; // 내부 클래스의 인스턴스 변수
void testResult() {
System.out.println("Outer num = " + num + " 외부 클래스의 인스턴스 변수");
System.out.println("Outer S_num = " + S_num + " 외부 클래스의 정적 변수");
}
}
public void testClass() {
innerClass.testResult();
}
}
결과::
외부 클래스 사용해서 내부 클래스 기능 호출
Outer num = 100 외부 클래스의 인스턴스 변수
Outer S_num = 500 외부 클래스의 정적 변수
정적 내부 클래스
외부 클래스의 인스턴스 생성과 상관없이 static변수를 쓰고 싶을 때 static 내부 클래스를 선언하면 된다.
package Collection_Framework;
public class static_inner_prac {
public static void main(String[] args) {
OuterClass1.Static_InnerClass n = new OuterClass1.Static_InnerClass();
//외부 클래스.내부클래스
n.printResult();
}
}
class OuterClass1{
private int number = 10;
private static int static_num = 30;
void print(){
System.out.println("Instance Method");
}
static void staticPrint(){
System.out.println("Static Method");
}
static class Static_InnerClass{ //정적 내부 클래스
void printResult(){
System.out.println("Outer number = " + static_num + "is Static variable in Outer Class");
staticPrint();
// print(); ERROR!
// number 변수와 print 메서드는 사용 불가 (정적 멤버가 아니다)
}
}
}
Instance Method
Outer number = 30 Static var in Outer Class
Static Method
지역 내부 클래스
지역 내부 클래스는 클래스의 멤버가 아닌, 메서드 안에서 정의되는 클래스이다.
'지역 - local'이라는 단어에서 알 수 있듯이 메서드 안에서만 동작하게 되고 메서드가 호출될 경우에만 메모리에 사용할 공간이 할당되기 때문에 static을 쓸 수 없다.
하지만 외부 클래스의 인스턴스 멤버와 static멤버를 모두 사용할 수 있다.
지역 클래스가 생성된 메서드 내부의 지역 변수도 사용 가능한데 final 이 붙은 변수만 가능하다.
(JDK1.8부터 없어도 자동으로 붙여줌)
따라서 메서드의 필드 변수의 값이 변하는 문장이 있으면 컴파일 에러가 난다.
package Collection_Framework;
public class local_inner_prac {
public static void main(String[] args) {
OuterClass2 outerClass2 = new OuterClass2();
outerClass2.local_test();
}
}
class OuterClass2{
int number = 10;
void local_test(){
int number2 = 20;
class LocalClass{ // 지역 내부 클래스 (메서드 안에서 존재)
void printResult(){
System.out.printf("외부 클래스 변수 number: %d\n", number);
System.out.printf("메서드 필드 변수 number2: %d\n", number2);
}
}
//지역 내부 클래스는 일반적으로 선언하고 나서 바로 인스턴스를 만들고 사용
LocalClass localClass = new LocalClass();
localClass.printResult();
}
}
외부 클래스 변수 number: 10
메서드 필드 변수 number2: 20
익명 내부 클래스
익명 내부 클래스는 다른 내부 클래스들과 다르게, 클래스의 선언과 생성을 동시에 하기 때문에 클래스의 이름이 없다.
그리고 단 한 번만 사용할 수 있는 일회용이고, 단 하나의 객체만을 생성할 수 있다.
new 상위클래스 이름(){
//멤버 선언
}
or
new 상위인터페이스 이름(){
// 멤버 선언
}
이름이 없기 때문에 생성자를 가질 수 없고 상위 클래스나 인터페이스를 이용해 클래스를 정의하기 때문에
한 번에 하나의 클래스를 상속받거나, 하나의 인터페이스만 구현할 수 있다.
package Collection_Framework;
interface FruitBox { //인터페이스 생성
String fruit1 = "Podo";
String fruit2 = "Sa_Gwa";
void printFruit();
}
public class anonymous_class {
public static void main(String[] args) {
//먼저 클래스를 하나 만들어 구현을 한것이 아닌
//Main 안에서 바로 익명 내부클래스로 사용해 구현했다.
FruitBox fruitBox = new FruitBox() {
@Override
public void printFruit() {
System.out.println(fruit1 + " & " + fruit2);
}
};
fruitBox.printFruit();
}
}
Podo & Sa_Gwa
'programming > JAVA' 카테고리의 다른 글
Java - Effective cont. (0) | 2022.05.20 |
---|---|
Java - Effective (0) | 2022.05.19 |
[TBC]Java - 컬렉션 프레임워크 (Collections Framework) (0) | 2022.05.17 |
Java - 지네릭 (generic) (0) | 2022.05.16 |
[TBC]Java - Array 정리 (0) | 2022.05.15 |