관리 메뉴

제뉴어리의 모든것

[Section1][Java] 객체지향 프로그래밍 기초 - 2 본문

코드스테이츠/정리 블로깅

[Section1][Java] 객체지향 프로그래밍 기초 - 2

제뉴어리맨 2022. 7. 8. 16:31

생성자

객체를 초기화(멤버 변수들 값 대입) 시켜주는 특수한 메소드.

 

일반 메서드와의 차이점

  • 반환타입이 없다
  • 메소드명이 클래스명과 같다
  • 만들어 주지 않아도 컴파일러에 의해 자동 생성된다. (클래스내에 생성자를 정의하면 자동 생성 해주지 않는다)

기본 생성자

개발자가 직접 만들어 주지 않아도 컴파일러의 의해 컴파일시에 만들어지는 생성자로써

매개변수와 메소드의 body 부분의 내용이 존재하지 않는다. (개발자가 기본생성자 형태로 직접 만들수도 있다)

 

개발자가 생성자를 만드는것과 안 만드는것의 차이

개발자가 어떤식의 생성자를 만들었든지 일단 하나라도 만든다면 컴파일러는 기본 생성자를 만들어주지 않는다.

그러므로 생성자를 만든 순간 해당 객체를 생성할때 만든 생성자 중 하나를 선택하여 객체를 생성하여야 한다.

 

 this()

해당 클래스의 생성자를 의미함.

(괄호안에 매개변수를 넣어준다면 매개변수가 존재하는 생성자를 의미한다.)

 

this()의 사용 조건

  • 생성자에서만 사용 가능하다.
  • 생성자 body 내에서 첫번째 줄에 위치하여야 한다

 

내부 클래스 (Inner Class)

클래스 내부에 정의된 클래스

 

내부 클래스의 사용 이유

  • 관련된 클래스끼리 관리하여 코드의 복잡성을 줄이고 캡슐화를 높이기 위함
  • 내부 클래스에서는 관련이 깊은 외부클래스의 변수와 메소드에 접근이 간편하기 때문

 

내부 클래스의 장점

  • 코드 복잡성을 줄여줌 (내부 클래스와 외부클래스간의 로직이 내부적으로만 처리 되기에 메인 로직은 간단해짐)
  • 특정 클래스간의 내부에서만 필요한 내용을 굳이 외부에 노출할 필요가 없으므로, 밀접한 관련이 있는 두 객체간의 접근 관련 코드들이 외부에 노출되지 않음

 

내부 클래스 종류

  • 인스턴스 내부 클래스
    클래스의 멤버 레밸에서 정의되는 클래스

    선언 위치 : 
    클래스의 멤버 레밸 위치 (멤버 변수, 멤버 메소드가 존재하는 블럭안에)

    사용 가능 변수 :
    외부 클래스의 모든 변수(인스턴스 변수 + 클래스 변수)



  • 정적 내부 클래스
    클래스의 멤버 레밸에서 정의되지만, static 키워드가 붙어서 정적인 클래스

    선언 위치 :
    클래스의 멤버 레밸 위치 (멤버 변수, 멤버 메소드가 존재하는 블럭안에)

    사용 가능 변수 :
    외부 클래스의 static(정적) 변수
  • 지역 내부 클래스
    클래스의 멤버 메소드 내에서 정의되는 클래스

    선언 위치 :
    클래스의 멤버 메소드 혹은 생성자의 내부 (메소드의 블럭안에)

    사용 가능 변수 :
    외부 클래스의 모든 변수(인스턴스 변수 + 클래스 변수) + 지역 변수(메서드 내에 선언된 변수)

  • 익명 내부 클래스
    멤버 메소드 내에서 특정 클래스를 이용하여(상속받는 개념) 정의되는 클래스로써
    객체의 생성과 동시에 클래스가 정의된다.

    선언 위치 :
    클래스의 멤버 메소드 혹은 생성자의 내부 (메소드의 블럭안에)

    사용 가능 변수 :
    외부 클래스의 모든 변수(인스턴스 변수 + 클래스 변수) + 지역 변수(메서드 내에 선언된 변수)

    + 익명 내부 클래스 사용 방법
     숙주타입 변수명 = new 숙주타입(){
         해당인스턴스가 가지고있는 특정 메서드를 재정의해서 쓸수있다
        } ;


멤버 내부 클래스

클래스의 멤버 레밸 (멤버변수, 멤버메소드가 정의되는 블럭안에)에 정의되어 있는 클래스.

인스턴스 내부 클래스 + 정적 내부 클래스


+ 클래스 전체 내부에서 선언된 변수들 중 클래스 블락 안에 바로 선언 된 변수들(멤버 인스턴스 변수, 멤버 정적 변수)을

멤버 변수라고 하듯이, 클래스도 특정 클래스 블락 안에 바로 정의된 클래스 클래스들을 멤버 내부 클래스라고 한다. 

 

 

내부 클래스의 사용 예

#1 ~ #8 : Outer outer = new Outer(); 해당 코드 진행시 내부적인 코드 진행순서

public class InnerClassPractice {
    public static void main(String[] args) {
        
        Outer outer = new Outer(); // #1

        Outer.InClass inClass = new Outer().new InClass("SeperatedInClass");

        System.out.println("Outer 클래스의 객체를 만들어서 자동으로 만들어진 내부 클래스 이름 : "+outer.inClass.name);
        System.out.println("자체적으로 만들어진 내부 클래스 이름 : "+inClass.name);

        outer.method();

        Outer anonymousClass = new Outer(){ //익명 내부 클래스 선언, Outer 클래스를 상속받아서 정의

            @Override    //Outer 클래스의 메소드를 재정의하여 사용 가능
            public void method() {
//                super.method(); //상속받은 클래스의 메소드를 굳이 사용하진 않아도 된다.
            }
        };
    }
}

class Outer{

    private int num = 1; // #3
    private int sNum = 2; // #4

    public InClass inClass = new InClass("ParameterConstructor");  // #5
    //new 키워드와 생성자를
    // 이용하여 Outer 객체를 생성할때 Outer 생성자에서는 생성자의 시그니쳐 부분까지만 진입을 했다가 멤버 변수부분 부터 순차적으로 아래로 코드가 진행 되므로 InClass의 name 변수가 여기서 초기화 됬다가
    // 멤버 변수 부분을 모두 진행하고선 생성자의 시그니쳐 부분에서 멈춰져 있던 Outer의 생성자 부분에서부터 Outer의 생성자가 작동하여 초기화 되므로
    // 값을 덮어버림.


    public Outer(){ // #2
        inClass = new InClass(); // # 6

        System.out.println("Outer 생성자");
    }

    class InClass{

        String name = "멤버 영역 초기화"; // #7
        public InClass() {
            this.name = "BasicConstructor";
        }

        public InClass(String _name) { //6
            this.name = _name; // #8
        }
    }

    public void method(){
        int num2 = 15;

        class LocalInnerClass{
            int num = 5;

            public void print(){
                System.out.println();
                System.out.println("===== Outer클래스의 method 메서드 =====");
                System.out.println("num2 = " + num2);
                System.out.println("num = " + num);
                System.out.println("===== Outer클래스의 method 메서드 =====");
                System.out.println();
            }

        }

        LocalInnerClass localInnerClass = new LocalInnerClass();

        localInnerClass.print();
    }



}

 

 

회고

내부 클래스에 대해 공부하며 예제를 만들어 보다가

새로운 사실을 알게되었다.

"new 클래스명()" 과 같이 객체를 생성하는 코드를 IDE에서 break 포인트로 순차적 진행해 보았을때,

해당 생성자의 생성자 시그니쳐로 일단 진입한다. 그리고 해당 생성자의 클래스 멤버 레밸에 변수 중 값이 대입되는 경우,

생성자 시그니쳐 에서 바로 멤버 레밸의 변수에 값이 대입되는 코드로 넘어간다.

그리고 해당 코드가 진행 되고 나서 다시 생성자 시그니쳐로 돌아와 해당 생성자의 body 부분을 진행한다.

결론적으로, 생성자가 호출되고나서 멤버변수에 값이 직접 대입되는 코드가 있다면 생서자의 body를 바로 진행하는 것이 아니다. 그래서 멤버 변수 선언과 동시에 대입되는 값은 생성자에서 대입되는 값으로 덮어쓰여 진다.

 

 

참조 : https://haenis.tistory.com/57