[JAVA] 객체 지향 프로그래밍 Ⅰ 정리 - (3)

DongGyu Jung·2022년 1월 19일
0

자바(JAVA)

목록 보기
11/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.


이번에는 저번 정리(객체 지향 프로그래밍 Ⅰ 정리 - (2))에 이어서

생성자초기화에 대해 자세히 알아보도록 하자.


📖 생성자 _ constructor

인스턴스가 생성될 때 호출되는
" 인스턴스 초기화 (인스턴스 변수 초기화) 메서드 "

이름 때문에
인스턴스를 생성하나...? 라는 오해가 생길 수 있는데
( 진짜 생성은 연산자 new를 통해 하는 것이지
생성자가 하는게 아니라는 것을 명심해야 한다. )

주로 " 인스턴스 변수 초기화 " 작업에 사용된다.
(인스턴스 생성 시에 실행되야하는 작업을 위해서도 사용됨.)

선언하는 방법이나 구조가
메서드와 상당히 유사하다.

우선,
생성자는
클래스 내에 선언되고
구조는 비슷하나 return값이 없다는 특징이 있다.
(단, return값이 없다고 메서드처럼 앞에 void를 붙이지 않는다.)

정의하는 방법은
다음과 같다.
오버로딩도 가능하기때문에
" 한 클래스에 여러 생성자 가 존재할 수 있다. "

// 정말 메서드와 유사하다.
클래스 이름 (Type 변수명, Type 변수명,...) {
    /*
    인스턴스 생성 시 수행될 코드
    (주로 인스턴스 초기화 코드 작성)
    */
}

※ 기본 생성자 (default)

사실 클래스에 " 생성자를 정의하지 않고도 "
인스턴스를 생성할 수 있었던 이유는

컴파일러가 제공하는 이 기본 생성자를 자동으로 추가하여 컴파일하기 때문이다.
( 소스파일*.java의 클래스에 생성자가 정의되지 않으면 자동적으로 아래와 같은 기본 생성자를 추가함. )

클래스 이름() {  }
Point() {  }

보이는 것처럼
이 자동 추가된 기본 생성자는
매개변수 없고, 아무런 내용 없는 간단한 생성자이다.

단,
" 클래스 내에 별도의 생성자가 정의되어 있는 상태 "라면
컴파일 에러가 발생한다.

class Data_1 {
    int value;
}
class Data_2 {
    int value;
    
    // 인스턴스를 만들기 위해선 int x 매개변수에 인수 투입이 필요함
    Data_2(int x) { // 매개변수가 있는 별도의 생성자
        value = x;
    }
}
class Test {
    public static void main(String[] args) {
        Data_1 d1 = new Data_1();
        Data_2 d2 = new Data_2(); // 별도의 생성자가 있는 클래스 -> Compile Error
    }
}


Data_1 d1 = new Data_1();
Data_2 d2 = new Data_2(); // 에러
// 에러 발생 해결
Data_2 d2 = new Data_2(10); // 매개변수에 들어갈 값 투입 -> Error X

파이썬에 비교한다면
파이썬의 __init__의 역할과 동일하다 생각하면 쉽다.

※ 매개변수 있는 생성자

위에서 살펴봤듯
객체를 시작을 만들기 위해
즉, 초기화를 하기 위해 매개변수를 입력해야 하는 생성자라고 보면 된다.

사용자의 설계에 따라
간결하고 간편하게 인스턴스를 만들 수 있게끔 도와준다.

예를 들면

class Car {
    String color;
    String company;
    int door;
    
    Car() {} // 클래스 내 기본 생성자
    // 인수가 투입되었을 때, 인스턴스가 어떻게 생성되는지 미리 설계해놓는 것
    Car(String col, String comp, int d) {
        color = col;
        company = comp;
        door = d;
    }
}


// 기본 생성자 사용
Car c = new Car();
c.color = "white" ;
c.company = "Audi" ;
c.door = 2;

// 매개변수 있는 생성자 사용
Car c = new Car("white", "Audi", 2) ;

※ "this()" 와 "this"

◎ 생성자에서 " 다른 생성자 호출 " - this()

같은 클래스의 멤버들 간에 서로 다른 생성자를 호출할 때 사용

※ 조건

  • 생성자 이름 : this (클래스 이름 X)
  • 다른 생성자 호출할 땐, 반드시 첫 줄에서만 호출 가능
    ( 생성자 내에서 초기화 도중 다른 생성자를 호출하게 되면
    다른 생성자 내의 멤버변수들 값도 초기화 할 것이기 때문에 이전의 초기화 작업이 무의미해질 수가 있음 )

기본 값을 정하고
인스턴스를 생성할 때,
매개변수에 들어올 값들의 경우의 수에 대해 고려한다고 하면 이해하기 편할 것이다.
예시를 통해 살펴보자.

class Car2 {
    String color;
    String company;
    int door;
    
    Car2(){
        this("white", "Audi", 2);
    }
    /*
    동일하게 초기화
    Car2(){
        color = "white";
        company = "Audi";
        door = 2;
    }
    */
    
    Car2(String color){
        this(color, "Audi", 2);
    }
    
    // 이 경우는 this() 호출의 경우가 아님 _ 주의!!
    Car2(String color, String company, int door){
        this.color = color ;
        this.company = company ;
        this.door = door ;
    }
}

//기본 생성
Car2 c1 = new Car2();
//color만 따로 별도 입력
Car2 c1 = new Car2("red");
//모든 변수 별도 입력
Car2 c1 = new Car2("blue", "Benz", 4);

이렇게 같은 클래스 내의
생성자들을 서로 호출하도록 유기적으로 연결해주면

여러 옵션(경우의 수)에 대비할 수 있고
수정이 필요한 경우 효율적으로 적은 코드 변경 해결이 가능하다.

◎ 객체에서 " 객체 자신을 가르키는 참조변수 " - this

자기 자신을 가르키는 참조 변수
" 인스턴스 변수 "와 " 지역 변수/매개변수 "간의 구별에 용이하다.
(this인스턴스 멤버만 사용 가능하다.)

예시를 보면서 이해하는 것이 좋을 것 같다.

//이 경우에는 구별에 문제가 없다.
// 매개변수(Local Variable) : "col" / 인스턴스 변수(Instance Variable) : "c"
Car(String col, String comp, int d) {
        color = col;
        company = comp;
        door = d;
    }
    
// 하지만 두 변수의 이름이 같다면 구별 불가
// 매개변수(Local Variable) : "color" / 인스턴스 변수(Instance Variable) : "color"
Car(String color, String company, int door) {
        //color = color;
        this.color = color; // 구분 가능
        //company = company;
        this.company = company; // 구분 가능
        //door = door;
        this.door = door; // 구분 가능
    }

앞서 this는 인스턴스 멤버만 사용 가능하다고 설명을 해놨는데
그 이유는
static메서드(클래스메서드)에서 인스턴스 멤버들을 사용할 수 없는 이유와 동일하다.
클래스 메서드는
인스턴스 생성 없이도 호출이 가능하기 때문에

static메서드가 호출되는 상황에
" 인스턴스가 존재하지 않을 수도 있기 " 때문이다.


※ 초기화

가능하면 선언과 동시에 적절한 값으로 초기화 하는 것이 바람직하다.

  • 멤버 변수 : 초기화를 하지 않아도 자동적으로 변수 자료형에 맞는 기본값으로 초기화됨.
  • 지역 변수 : 자동 X _ 사용하기 전에 반드시 초기화해야함.
    • 멤버변수[ : 클래스변수 & 인스턴스 변수 ] or 배열 : 선택적 초기화
    • 지역변수 : 필수 초기화


      📌 각 타입 기본값
    자료형기본값
    booleanfalse
    char'\u0000'
    byte, short, int0
    long0L
    float0.0f
    double0.0d or 0.0
    참조형null

◎ 변수 초기화

class InItTest {
    int x ;	// 인스턴스 변수 : 명시적으로 지정해주지 않아도 기본값 "0"이 들어감 
    int y = x ;	// 인스턴스 변수 : x에 자동으로 기본값으로 초기화되었기 때문에 0이라는 값이 유효 -> y도 0
    
    void method1() {
        int i ; // 지역변수 : 초기화가 자동으로 되지않음.
        int k = i ; // 지역변수 : i가 초기화 되지도 않았는데 무슨... 불가능! -> 에러Error
    }
}

위 예시처럼
인스턴스 변수x는 기본값 0으로 자동 초기화가 되기때문에 에러가 발생하지 않지만
void method1()지역 변수 i는 자동 초기화가 되지 않기 때문에
컴파일 시, 에러가 발생한다.

◎ 멤버 변수 초기화

앞서 알아봤던 것처럼
지역변수와 달리 멤버변수는 각 타입의 기본값으로 자동 초기화가 된다고 했는데

전체적인 " 초기화되는 순서 "를 살펴보면

  • 클래스 변수(class variable_cv) 초기화 ▶ 인스턴스 변수(instance variable_iv) 초기화
  • 자동 초기화 ▶ 명시적 초기화 (간단) ▶ 초기화 블럭 & 생성자 (복잡)
    아무래도 간단한 순서부터 초기화하는 것이 효율적이기 때문에..
    (명시적 초기화가 가장 기본적이면서 간단하고 초기화 블럭/생성자는 복잡한 작업에 적합하다.)


📌 명시적 초기화 (explicit initialization)

" 선언과 동시에 초기화하는 것 "

📌 초기화 블럭 (initialization block)

초기화 블럭은 두 가지의 종류가 있는데
클래스인스턴스로 나뉜다.

  • 클래스 초기화 블럭 : " 클래스 변수 "의 복잡한 초기화에 사용
  • 인스턴스 초기화 블럭 : " 인스턴스 변수 "의 복잡한 초기화에 사용

이 초기화 블럭을 작성하는 방법은
기억하기 쉽다.

우선 < 인스턴스 초기화 블럭 >은
단순히 클래스 내에 블럭{}을 만들고
그 안에 코드를 작성하는 것이고

< 클래스 초기화 블럭 >은
이 인스턴스 초기화 블럭 앞에 static을 붙이면 된다.

물론 초기화 순서를 보면 알겠지만
가장 먼저 수행되는 것은 " 클래스 초기화 블럭 내 작성한 코드 "이고
그 다음으로 인스턴스 초기화 블럭, 그리고 생성자 순으로 수행된다.

순서는 위와 같은 순서이고
수행되는 경우는
클래스 초기화 블럭의 경우 처음 메모리에 로딩될 때 한 번만 수행되지만
인스턴스 초기화 블럭의 경우 인스턴스 생성 때마다 수행된다.


0개의 댓글