programming language/Java

[Java] : Local Class알아보기

공대키메라 2025. 4. 19. 23:28

지난 글에서 Nested Class와  Inner Class가 뭔지 공식문서를 읽어 보았는데,

 

이어서 Local Class, Anonymous Class 그리고 Lambda 에 대해 읽을 예정이다.

 

0. Enclosing Class?

Enclosing Class는 바디 안에 다른 클래스를 포함하고 있는 클래스이다.

 

그런데 생각해보니 Outer class도 있자나?

 

이전에 Inner class에 대해 공부할 때 Inner class의 외부 클래스를 Outer class라고 부를 수 있는데

 

enclosing class와 outer class가 뭐가 다른지 이번에는 GPT의 힘을 빌려보았다.

 

키메라 : 두 개는 비슷한데 뭐가 다른거야?

MyClass.java

public class MyClass {
    void method() {
        class LocalClass {
            void doSomething() {
                // 여기서 enclosing class는 MyClass
                // enclosing method는 method()
            }
        }
    }
}

 

enclosing class: 컴파일러나 JVM이 정확히 어떤 스코프에 포함되어 있는지 분석할 때 사용

outer class: 사람이 보기 편한 바깥 클래스 설명할 때 사용

 

이라고 한다. 고맙다 GPT!

1. 로컬 클래스(Local Class)

로컬 클래스는 블록 안에 정의된 클래스이며,
블록이란 중괄호로 감싸진 0개 이상의 문(statement)들로 이루어진 코드 묶음을 말한다.
로컬 클래스는 일반적으로 메서드 본문 안에서 정의되는 경우가 많다.

 

여기서 헷갈리는게 0개 이상의 문이라고 하는데, 빈 bracket도 유효한 블록으로 본다는 말이다

 

2. Inner Class ? Local Class?

글을 읽다가 헷갈리는게 있는데 Inner class랑 Local Class랑 많이 유사하다.

 

이게 뭐가 다르기에 용어를 다르게 붙인건가 확인하고 하자.

 

 

저번 글에서 Inner class는 non-static nested class 라고 했다.

 

반면에 Local Class는 블록 안에 정의된 클래스라고 한다.

 

 

사실 그렇다면 넓은 의미에서 Local Class가 Inner class에 포함이 되는 듯 하다.

 

Inner Class 는 정의대로 클래스 안의 클래스인 건데,

 

Local Class 는 블록 안의 class이기 때문이다.

 

 

근데 Local Class는 블록 안에 선언된 Class이니 Inner Class보다 다양한 상황이 있는거 같다.

 

그럼 그러한 내용이 있는지 계속 글을 읽어보도록 하겠다.

 

3. 로컬 클래스 선언(Declaring Local Class)

우리는 어느 블록 안에서든 class를 선언할 수 있다.

method body에도, for loop 에도, if 문에도 말이다. 

LocalClassExample.java

public class LocalClassExample {
  
    static String regularExpression = "[^0-9]";
  
    public static void validatePhoneNumber(
        String phoneNumber1, String phoneNumber2) {
      
        final int numberLength = 10;
        
        // Valid in JDK 8 and later:
        // int numberLength = 10;
       
        class PhoneNumber {
            
            String formattedPhoneNumber = null;

            PhoneNumber(String phoneNumber){
                // numberLength = 7;
                String currentNumber = phoneNumber.replaceAll(
                  regularExpression, "");
                if (currentNumber.length() == numberLength)
                    formattedPhoneNumber = currentNumber;
                else
                    formattedPhoneNumber = null;
            }

            public String getNumber() {
                return formattedPhoneNumber;
            }
            
            // Valid in JDK 8 and later:

//            public void printOriginalNumbers() {
//                System.out.println("Original numbers are " + phoneNumber1 +
//                    " and " + phoneNumber2);
//            }
        }

        PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
        PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);
        
        // Valid in JDK 8 and later:

//        myNumber1.printOriginalNumbers();

        if (myNumber1.getNumber() == null) 
            System.out.println("First number is invalid");
        else
            System.out.println("First number is " + myNumber1.getNumber());
        if (myNumber2.getNumber() == null)
            System.out.println("Second number is invalid");
        else
            System.out.println("Second number is " + myNumber2.getNumber());

    }

    public static void main(String... args) {
        validatePhoneNumber("123-456-7890", "456-7890");
    }
}

 

Local class는 enclosing class의 멤버에 접근할 수 있다.

 

Local class는 local variable에 접근할 수 있는데, Local class는 final로 정의된 local variable에만 접근 할 수 있다고 적혀 있다는데, 이것은 Java 8 이전이고, Java 8 이후에는 effectively final 한 변수도 사용이 가능하다.

 

effectively final 하다는 말은 한 번 선언과 함께 변수를 할당하고, 중도에 값을 변경하지 않은 상태라는 것이다.

사실상 final 인 변수라는 것이다.

 

실제로 그런지 테스트를 해 봤는데...

 

 

Local Class가 local variable에 접근했는데, 중도에 값을 변경하니 컴파일 에러가 나고 있는 것을 확인했다.

 

또 여기서 재미있는 표현이 있는데 capture variable이라는 것이 나온다.


로컬 클래스가 자신을 둘러싸고 있는 메서드의 로컬 변수에 접근할 때, 그 변수를 "캡처(capture)"한다고 한다.

즉, 로컬 클래스가 외부 변수를 자신의 내부로 가져와서 사용하는 것을 말한다.

 

3. Inner Class와 Local Class 비교하기

그러면 inner class와 local class에 대해 어떻게 언급하는지 알아보자.

 

우선 inner class와 local class 안에서 static 멤버를 선언할 수 없다.

 

정말 그런지 확인했는데,

 

 

validatePhoneNumber 라는 static method 안의 Local Class인 경우에는 local variable을 static으로 선언할 수 있다.

(Java 16 이상부터는 로컬 클래스이며, 로컬 클래스가 static 메서드 안에 있다면 가능하다고 한다. )

 

또 다음을 보자.

public class LocalClassExample {

	...
    
    
    // 추가
    public void greetInEnglish() {
        interface HelloThere {
            public void greet();
        }
        class EnglishHelloThere implements HelloThere {
            public void greet() {
                System.out.println("Hello ");
            }
        }
        HelloThere myGreeting = new EnglishHelloThere();
        myGreeting.greet();
    }
    
}

 

 

글에는 block 안에 interface를 선언할 수 없다고 적혀 있는데 문제가 없다. (?)

 

또 static initializer를 선언할 수 없다고 햇는데 그건 안됀다.

 

그리고 local class는 constant variable인 static 멤버를 가질 수 있다고 한다. 

 

 

안된다고 했는데 막상 해보니 문제가 없는 것인 class 내에 interface선언은 Java 16 이후에 된다고 한다.

 

Record를 도입하면서 다음 과 같은 History를 소개한다.

 

The ability to declare local record classes, local enum classes, and local interfaces was introduced.


필자는 역시나... Java 16 위인 Java 17을 사용 중이라서 잘 된다.

 

 

 static initializer 를 local class 내에 만들어서 해봣는데, 이건 되지 않는다.

 

 

4. 마무리

출처 : https://thisisprogrammingworld.tistory.com/29

 

마무리 하면서 참고할 만한 표를 퍼왔다. (출처 필수 표기!)

 

2번 섹션에서 내가 말하듯이 정리는 되어 있지 않았다.

 

다만 정리하면 맞는거 같은데... 틀리다면 피드백주시면 감사하겠습니다 꾸벅.

 

이 글과 함께 이전의 Nested Class와 Inner class를 보면 될듯하다.

 

다음에는 Anonymous Class 와 Lambda 에 대해 보려고 한다.

 

 

출처

https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html

https://openjdk.org/jeps/395

https://thisisprogrammingworld.tistory.com/29