ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 알기 쉬운 JAVA 내부 클래스(Inner class)에 대해 알아보자
    프로그래밍/JAVA 2020. 5. 12. 20:58

    내부 클래스(Inner class)

     

    내부 클래스는 클래스 안에 또 다른 클래스를 구성하는 것을 말한다.

    주로 이벤트핸들러를 처리할 때나 안드로이드 앱을 만들 때 많이 사용한다.

     

    생성 방법

    클래스가 정의되는 위치에 따라 분류할 수 있다.

    // Inner class의 기본적인 틀
    
    class A {
    
    	class B {
        	// Inner 멤버 클래스 : 클래스 안에서 선언된 클래스
        }
        
        void func() {
        	
            class C {
            	// Inner 로컬 클래스 : 메소드 안에서 선언된 클래스
                
            } // class C
            
        } // func()
        
    } // class A

    내부 클래스의 종류

    1) Inner Member class

    클래스 내부에서 멤버 변수 처럼 선언된 클래스를 말한다. 

    멤버 변수와 같이 static과 instance 클래스로 나눌 수 있다.

     

    2) Inner Local class 

    메소드 내부에서 지역 변수 처럼 선언된 클래스를 말한다.

    클래스 이름에서 알 수 있듯이 메소드 안에서 선언된 클래스의 속성은 메소드 밖에서 사용할 수 없다.

    Named Local class(이름 있는 클래스)와 Anonymous class(익명 클래스)로 나눌 수 있다.

    Inner Member class 생성과 출력방법

    public class Outer {
    	   int a = 10;    
        static int b = 20;	  
        
        public void print() {
        	System.out.println("print");
        
        // instance클래스인 Inner class 생성
        class Inner {
        	int c = 30;
            
            public void foo() {
            	System.out.println("foo()");
            }
        } // Inner
        
        // static인 Inner class 생성
        class SInner {
        	// 일반적으로 class에는 static을 붙이지 못하지만 Inner클래스는 붙일 수 있다.
            
            int d = 40;
    		void bar() {
    			System.out.println("bar()");
    		}
    		
    		static void baz() {
    			System.out.println("baz()");
    		}
    	} // SInner
    	
    } // Outer
        

    Outer class를 생성하고 클래스 안에 static이 붙이 않은 Inner 클래스와 static이 붙은 SInner클래스를 생성하였다.

     

    내부 클래스의 객체를 생성할 때는 클래스 이름 앞에 static의 유무에 따라 그 방법이 달라진다.

     

    변수를 호출할 때와 비슷하다고 생각하면 쉽다.

    static이 붙지 않은 전역변수(instance, 멤버변수)를 호출하기 위해선 객체를 생성해주고 "객체명.변수"로 작성한다.

    static이 붙은 전역변수를 호출하기 위해선 "클래스명.변수"로 작성한다.

     

    static이 붙지 않은 Inner 클래스의 객체를 생성할 때는

    1) Outer객체를 생성해주고 (Outer o = new Outer();)

    2) Outer.Inner oi = o.new Inner(); 로 작성한다.

    static이 붙은 SInner 클래스의 객체를 생성할 때는 Outer.SInner osi = new Outer.SInner(); 로 작성한다.

     

    이제 각각의 클래스를 호출하는 main 메소드를 작성해보자

    public class InnerClassTest {
    
    	public static void main(String[] args) {
        	// Outer 클래스의 변수 a, b를 출력하기 위해선 Outer의 객체를 생성해줘야 한다.
            Outer o = new Outer();
            
            // static이 붙은 변수는 "클래스명.변수"
            // static이 붙지 않은 변수는 "객체명.변수" 로 지정한다.
        	System.out.println("o.a = "+o.a);
            System.out.println("Outer.b = "+Outer.b);
            
            // Outer class 안에 있는 Inner 클래스의 변수 c를 출력
            Outer.Inner oi = o.new Inner();
            System.out.println("oi.c = "+oi.c);
            
            // Outer class 안에 있는 Inner 클래스의 foo() 메소드 호출
            oi.foo();
            
            // Outer class 안에 있는 SInner 클래스의 변수 d를 출력
    		// static class
    		Outer.SInner osi = new Outer.SInner();
    		System.out.println("osi.d = "+osi.d);
    		
            // Outer class 안에 있는 Inner 클래스의 bar() 메소드 호출
    		osi.bar();
            
            // Outer class 안에 있는 Inner 클래스의 baz() 메소드 호출
            // baz() 메소드가 static으로 선언했기 때문에 아래와 같이 클래스명.내부클래스명.메소드로 작성
            Outer.SInner.baz(); 
        }
    
    }
    o.a = 10
    Outer.b = 20
    oi.c = 30
    foo()
    osi.d = 40
    bar()
    baz()

     

    Inner Local class 생성과 출력방법

    Inner Local class는 메소드 블럭 안에 구성된 내부 클래스로 지역변수와 비슷한 특징을 갖는다.

    public class Outer2 {
    	String str = "$$$"; // 전역 변수
        
        void func() {
        	final int NUM = 100; // 지역 변수
            System.out.println("str: "+str);
    		System.out.println("num: "+NUM);
            
            class LocalInner {
            	String lstr = "@@@";
                
                void print() {
                	System.out.println("lstr= "+lstr); // lstr은 같은 클래스 안에 있기 때문에 호출 가능
    				System.out.println("str= "+str); // str은 전역변수기 때문에 호출 가능
                    System.out.println("num= "+NUM);
                    }
                    
    		} // LocalInner
            
            // Local class는 클래스를 정의한 후에만 사용 가능
    		LocalInner li = new LocalInner();
    		li.print();
            
        } // func()
        
        
        public static void main(String[] args) {
    		Outer2 o = new Outer2();
    		o.func();
        }
                    
    str: $$$
    NUM: 100
    lstr= ###
    str= $$$
    NUM= 100

    메소드 안에서 생성된 Inner class는 지역 변수 처럼 그 안에서만 사용할 수 있다.

    따라서 main에서 void print()를 직접적으로 호출할 수는 없다.

     

    메소드 안에서 생성된 Inner class를 호출하기 위해서는

    1. 메소드 안에 내부 클래스를 선언하고

    2. 그 클래스를 감싸고 있는 메소드 안에서 객체를 생성하고

    3. main에서 메소드를 호출해야지만 Inner class 안에 선언된 메소드를 호출할 수 있다.

     

    Anonymous class(익명 클래스)

    익명 클래스란 다른 내부 클래스와는 달리 이름을 가지지 않는 클래스를 의미한다. 익명 클래스는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성하는 일회용 클래스이다. 따라서 생성자를 선언할 수도 없으며, 오로지 단 하나의 클래스나 단 하나의 인터페이스를 상속받거나 구현할 수 있다.

    public class ColorFrame extends JFrame {
    		
            JButton rgb;
            Canvas can;
            
            public ColorFrame() {
    			
                rgb.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        Color c = JColorChooser.showDialog(null, "COLOR", Color.BLACK);
                        can.setBackground(c);
                    }
                });
                
            }
    }

    내부 클래스 사용 목적

    내부 클래스를 사용하게 되면 비슷한 형태의 클래스들을 묶을 수 있어서 코드의 캡슐화를 증가시킬 수 있다. 또한, 내부 클래스에서 외부 클래스의 멤버에 손쉽게 접근 할 수 있게 된다.

    댓글

Designed by Tistory.