본문 바로가기

프로그래밍/자바

[자바/기본] 내부 클래스(InnerClass)

728x90
반응형
SMALL

내부 클래스(Inner Class)

  • 내부 클래스란 하나의 클래스 내부에 선언된 또 다른 클래스를 의미한다.
  • 내부 클래스 또한 일반적으로 선언되는 클래스와 다른점이 없다
    • 다른 점은 클래스 내부에서 선언된다는 점
  • 그렇다면 언제 내부 클래스를 설계 해야할까??
    • 상속 관계로 묶을 수 없지만 A객체가 생성되어야 B객체가 존재할 수 있다고 하면 B를 A의 멤버 내부 클래스로 선언할 수 있다.
    • EX) 컴퓨터 - 메모리 / 자동차 - 타이어
    • is - a : 상속관계
    • has - a
      • 종속 관계일때, 멤버 내부 클래스
      • 독립 관계일때, 멤버 변수
  •  종류
    • Member inner class (멤버 내부 클래스) : 다른 클래스 내부에서 선언된 클래스
    •  Nested class (static 내부 클래스) : 다른 클래스의 내부에서 static으로 선언된 클래스
    • Local class (지역 클래스)
      • Local inner class (지역 내부 클래스): 메소드 내부에서 선언된 클래스
      • Anonymous inner class (익명 내부 클래스) : 이름이 없는 local class

Member Inner 클래스(멤버 내부)

//예시 Car.java
//Car는 외부 클래스
public class Car {
    private String type;
    
    //같은 이름의 멤버변수
	private int price = 1000;
    
    public Car(String type) {
        this.type = type;
    }
    
    //has - a 종속관계인 타이어 내부 클래스
    public class Tire {
        
        private int radius;
        
        //같은 이름의 멤버 변수
        private int price = 10;
        
        public Tire(int raidus) {
            this.radius = raidus;
        }
        
        public void dispalyInfo() {
            System.out.println("차량 종류 : " + type);	//외부 클래스의 멤버 변수 바로 접근 가능
            System.out.println("바퀴 크기 : " + radius);
        }
        
        //같은 이름의 멤버 변수가 있다면
        public void showPrice(){
            System.out.println(price);		//10
            System.out.println(this.price);	//10

            System.out.println(Car.this.price);	//1000
        }
    }
}
  • 위 예시에서 Car 라는 클래스는 Tire 라는 클래스를 멤버 내부 클래스로 가진다.
  • Car has - a Tire
  • 또한, 외부 클래스의 멤버 변수에 바로 접근 할 수 있다.
  • 만약, 같은 이름의 멤버 변수가 있다면 (예시는 price), this 가 있든 없든 내부 클래스의 변수를 가져오게 된다.
    • 따라서 외부 클래스의 this 를 통한 멤버변수를 지정해줘야 한다.

Static Inner Class (static 내부 클래스)

  • 앞서 설명했듯이 static 이 사용된 내부 클래스
  • static : 클래스의 인스턴스 (객체)가 생성되지 않아도 사용 될 수 있는 멤버 (변수, 메소드)
    • 따라서, nested class는 외부 클래스가 생성되지 않아도 내부 클래스의 인스턴스를 생성할 수 있다.
    • Static에서는 static 메소드, 변수 만 사용할 수 있기 때문에 외부 클래스에서 static으로 선언된 변수와 메소드만 사용 가능하다
public class Outer {

    private int check;
    private static int stat_check;

    public Outer() {}
    
    //Nested class
   
    public static class NestedInner {
        public void checkcheck() {
            // System.out.println(check);   // 사용불가!
            System.out.println(stat_check);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Outer.NestedInner nestedInner = new Outer.NestedInner();
        nestedInner.checkcheck();

        //외부 클래스를 생성하지 않아도 되지만 이렇게 선언 하는 것은 불가능
        //실제로는 내부 클래스이기 때문에 내부클래스가 생성되는 방식을 따라야한다.
        //NestedInner nono = new NestedInner();
    
  	//주소값 비교
        Outer.NestedInner n1 = new Outer.NestedInner();
        Outer.NestedInner n2 = new Outer.NestedInner();
        System.out.println(n1 == n2);       //false
    }
}
  • 주의 : static 변수의 경우 하나의 변수가 여러 객체에서도 공유 되는 것으로 이해하고 있었으나 static 클래스의 경우 그런 동작을 하지는 않는것 처럼 보여졌다.
  • 따라서, 외부 클래스를 생성하지 않고 내부클래스를 생성 할 수 있다는 것에 주목해야한다.

Local Inner Class (지역 클래스)

  • 정의 된 메소드 내부에서만 사용 가능
    • 참조 변수 선언, 인스턴스 생성 등
  • 접근 제어자를 사용 할 수 없다 (public, private, protected)
  • 외부 클래스의 멤버 변수는 모두 사용 가능
  • effective final 인 지역변수나 매개 변수만 사용 가능하다
    • final로 선언된 변수
    • 한번 초기화 된 이후로 값이 변경 되지 않는 변수
public class Main {
    public static void main(String[] args) {
        int a = 100;
        
        //지역 변수
        class Inner {
            int b = 100;
            public void print(){
                //a += 1;	// 변수 a 는 final이기 때문에 사용 할 수 없음
                System.out.println("a : " + a);
              	System.out.println("b : " + b);
            }
        }

        Inner in = new Inner();
        in.print();
    }
}
  • 위 설명과 예시를 보면 궁금한 점이 하나 생긴다.
    • a 가 final 이 아닌데??
  • Java8 부터 지역 내부 클래스에서 로컬변수 및 매개변수를 사용 할 때 해당 변수는 사실 final로 취급 되기 때문에 컴파일러가 final 키워드를 붙여주게 된다.
  • 따라서 사용 하는 것은 가능 하지만 값을 변경 하는 것은 불가능 하다.

Anonymous Inner Class (익명 내부 클래스)

  • 이름이 없는 local inner class
  • 이름이 없기 때문에 생성자를 만들 수 없음
  • 클래스의 정의와 동시에 인스턴스를 생성됨
  • 인터페이스, 일반 클래스, 추상 클래스 등으로 만드는 것이 가능
  • 상속 받은 이름 없는 클래스의 인스턴스를 생성 후
    • 멤버 변수 및 메소드 선언
    • 메소드 오버라이딩
  • 프로그램에서 일시적으로 한번만 사용 되고 버려지는 객체
    • 즉, 재사용 되지는 않음

 

인터페이스명/부모클래스명 변수명 = new 인터페이스명/부모클래스명() {
    // 익명 클래스의 내용
};
  • 위와 같은 형식으로 선언하고 사용하게 된다.
interface Person {
    void walk();
}
public class Main {
    public static void main(String[] args) {
        // 익명 클래스로 생성
        Person person = new Person() {
            @Override
            public void walk() {
                System.out.println("뚜벅뚜벅 오버라이드로 메소드를 구현해서 클래스로 만들었어");
            }
        };
        person.walk(); // 익명 클래스의 함수 사용!

        // 람다식으로 표현
        Person lambda = () -> System.out.println("람다식으로 구현하는 방법");
        lambda.walk();
    }
}
  • Person이라는 인터페이스를 만들어서 익명클래스를 생성하는 방법의 예시
  • Lambda 식과 관련 된 내용은 추후에 정리

 

 

728x90
반응형
LIST

'프로그래밍 > 자바' 카테고리의 다른 글

[자바/기본] Optional 이란?  (0) 2024.02.19
[자바/기본] 람다식 (Lambda) 란?  (0) 2024.02.16
[자바/기본] List 란?  (0) 2024.02.13
[자바/기본] Collection Framework란?  (0) 2024.02.11
[자바/기본] Generic 이란?  (0) 2024.02.11