본문 바로가기

Java/Study

[JAVA] 로컬 클래스 , 익명 클래스, 람다의 스코프 차이


- Nested Class

- Local Class

- Anonymous Classes

- Lamda

Scope and Accessibility


Nested Class - 클래스 안의 클래스를 의미

자세한 설명은 링크를 참고하세요.

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

 

Nested Classes (The Java™ Tutorials > Learning the Java Language > Classes and Objects)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

Nested Class의 종류

□ static class
□ local class
Anonymous class

static class 개념은 간단하다.  클래스 앞에 Static이 붙는 것이다

static class
Local class

로컬 클래스는 메서드 안에 선언된 클래스를 의미한다.

 

클래스의 접근성을 짚고 넘어가고자 한다.

public class DemoClass {
    class InstanceInner{};
    static class StaticInner{};

    InstanceInner iv = new InstanceInner();
    StaticInner ic = new StaticInner();

    static void StaticMethod(){
        // static메서드 안에선 static인스턴스 접근이 불가능하다.
//        InstanceInner iv = new InstanceInner();/
        // 굳이 선언하고 싶으면 outer class를 선언하고 사용해야함
        DemoClass Dc = new DemoClass();
        InstanceInner ic = Dc.new InstanceInner();
        StaticInner si = new StaticInner();
    }
    void instanceMethod(){
        // 인스턴스 메서드에서 전부 접근 가능
        InstanceInner Ic = new InstanceInner();
        StaticInner SI = new StaticInner();
    }

    void myMethod(){
        // 지역변수 내에서 선언된 클래스는 지역 변수 밖에서 생성할 수 없다
        class LocalInner{}
        LocalInner li = new LocalInner();
    }
}

스태틱 메서드 안에서 인스턴스를 생성하는 경우

  인스턴스 클래스를 담고 있는 클래스를 먼저 생성하고 나서, 인스턴스 클래스를 접근해야 접근이 가능하다.

 

익명 클래스(Anonymous class)

이름 없는 클래스로 ,

부모 클래스   =new 부모클래스{
                  새로운 메서드나 변수를 선언할 수 있음
                  ** 하지만 부모 클래스이므로 자식에 선언된 메서드나 변수에 접근이 불가능하다 !!**
}

코드를 확인해보면,

class Test{
    private int number = 1;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    void whatNumber(){};
}

익명 클래스를 생성해보면

public class AnonymousClass {
    public static void main(String[] args) {
        Test t1 = new Test(){
            int number = 1;

            void testMethod(){
                System.out.println("익명 클래스 안에 선언된 메소드");
            }

            @Override
            void whatNumber() {
                super.whatNumber();
                testMethod();// 부모 클래스에 있는 메소드에선 새로 선언한 메소드 부를수 있지만
                System.out.println("제 번호는" + number);
            }
        };
        // 익명클래스에 선언된 메서드와 변수는 익명 클래스 밖에서 사용될 수 없다.
        // t1.number 나 t1.testMethod 접근 불가
        t1.whatNumber();

    }

}

Lambda 

익명  함수로  다른 객체에 적용 가능한 연산이 모두 수행될 수 있는 일급 객체를 의미합니다.

※람다의 변수에는 final변수나 effective final 변수만 올 수 있습니다

Java 8부터,

effective final변수란 선언되고 값이 변경되지 않은 변수를 의미합니다.

int a = 2;// effective final
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("a의 값은" + a);
            }
        };
        runnable.run();

run() 메서드 안에서 a의 값을 바꾸려고 하면 inner class에서 접근 가능한 변수는 final변수만 가능하다는 컴파일 에러가 뜹니다. 

즉, nested class 안에서는 변수의 값을 변경할 수 없으므로 람다식으로 변경이 가능합니다.

public class Lambda {
    public static void main(String[] args) {
        int a = 2;
        Runnable runnable = () -> {System.out.println("a의 값은" + a);};
        runnable.run();
    }
}

마지막으로, Scope and accessibility를 살펴보면,

public class ThreeTypeOfScope {
    public static void main(String[] args) {
        ThreeTypeOfScope threeScope = new ThreeTypeOfScope();
        threeScope.run()

    }
    private void run() {
//        final int baseNumber = 10;
        int baseNumber = 10;
//============================================================================================
        //로컬클래스
        class LocalClass{
            void printNumber(){
//                baseNumber++;// 에러남 - final로 선언한 변수를 수정하려고 하니깐
                int baseNumber = 5;
                System.out.println(baseNumber);
            }
        }
//=============================================================================================
        //익명클래스
        Consumer<Integer> integerConsumer = new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
//                baseNumber++;// 에러남
                int baseNumber = 5;
                System.out.println(baseNumber);
            }
        };
//=============================================================================================
        IntConsumer printInt = value -> {
            // 람다식에 사용한 변수는 final 혹은 effective final 이라함
//            int baseNumber = 5;컴파일 에러
            System.out.println(value + baseNumber);
        };
        printInt.accept(5);
    }
}

 

Scope 은 클래스의 범위를 의미하고, 

람다식 Scope = ThreeTypeOfScope 은 같은 범위

Shadowing이란 외부 변수가 내부 변수에 의해 가려지는 현상

로컬 클래스, 익명 클래스의 내부 변수에 의해 외부 변수가 가려진다.