[Java] 객체지향 프로그래밍 - 생성자

최지수·2022년 4월 15일
0

Java

목록 보기
7/27
post-thumbnail

생성자(Constructor)

인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드에요. 인스턴스 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야할 작업을 위해서도 사용되요.

인스턴스 메서드처럼 클래스 내에서 선언되어, 구조도 유사하지만 반환 타입이 존재하지 않아요. 심지어 void 선언도 안해요. 생성자의 조건은 아래와 같아요.

  1. 클래스와 이름이 같아야해요
  2. 반환값이 없어요

선언은 이렇게 하면 되요.

class App{
	App(){
    	// 무언가, App 생성하기 전에 필요한 것들 초기화
    }
    App(int a, int b){
    	// 기존 메서드처럼 오버로딩이 가능해요
    }
}

'생성'자라해서 인스턴스를 생성하는 역할로 오해할 수도 있는데 new 연산자가 인스턴스를 생성하는 것이지 생성자가 인스턴스를 생성하는 건 아니에요.

App 클래스를 예로 들어 인스턴스 생성하는 과정은 아래와 같아요.

App app = new App();
1. 연산자 new에 의해 메모리heap에 클래스 인스턴스가 생성되요
2. 생성자 App()가 호출되어 수행해요
3. new의 결과로 생성된 App 인스턴스의 주소가 반환되어 참조 변수 app에 저장되요

기본 생성자(Default Constructor)

컴파일을 할 때 소스 파일*.java의 클래스가 생성자가 하나도 없다면 컴파일러는 자동적으로 아래와 같은 생성자를 추가해서 컴파일해요. 아무 기능도 수행하지 않기 때문에 생성과 동시에 초기화가 필요한 인스턴스는 반드시 생성자를 선언해줘야 해요.

class App {
	// 선언은 안되었다면 컴파일러는 자동으로 생성!
	App() {
    }
}

근데 만약에 매개변수가 있는, 기본 생성자가 아닌 생성자가 선언되어 있고, 기본 생성자가 따로 선언되어 있지 않은 상태에서 기본 생성자로 해당 인스턴스를 생성하려고 하면 컴파일러는 이를 에러 처리해요. 왜냐하면 생성자가 하나라도 생성되어 있다면 기본 생성자를 자동으로 생성하지 않기 때문이에요.

class App {
	App(int a, int b) { }
}

App a1 = new App(1, 2);
// App a2 = new App();	// 에러! 컴파일러는 기본 생성자를 만들지 않아요

컴파일러가 자동으로 기본 생성자를 추가하는 경우는 생성자가 선언되어 있지 않는 경우일 뿐이라는 걸 명심해요.

생성자에서 다른 생성자 호출하기 - this(), this

같은 클래스의 멤버들 간에 서로 호출할 수 있는 것처럼 생성자 간에도 서로 호출이 가능해요. 물론 다음 두 조건을 만족해야 해요.

  1. 생성자의 이름으로 클래스 이름대신 this를 사용해야 해요
  2. 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서 호출해야 해요
class App{
  App() {}
  App(String color){
      i = 1;
      App();	// Error : 생성자가 첫 줄이 아니에요
      			// Error : 생성자 이름이 아닌 this로 명명해야 해요
  }
}

이렇게 강제하는 이유는 생성자 내에서 초기화 작업 도중에 다른 생성자를 호출하게 되면, 호출된 다른 생성자 내에서도 멤버변수들의 값을 초기화하기 때문에 이전 초기화 작업이 무의미해질 수도 있기 때문이에요.

프로그래밍을 하다보면 인자 명과 멤버변수 명이 중복되는 경우가 있어요. 이를 처리하기 위해 멤버변수 명 앞에 this.을 붙여서 이는 클래스의 인스턴스 변수라는 것을 표시할 수 있어요. 굳이 구별을 하겠답시고 _같은 특수문자를 넣는 번거로움을 피하고 의미를 퇴색시키는 난잡한 인자 선언을 할 필요가 없게 되요.

class App{
	int a;
    App(int a/* 이름이 같다...! */){
    	this.a = a; 	// 어림없지. this로 구분한다
    }
}

💡정리

  • this : 인스턴스 자신을 가리키는 참조 변수, 인스턴스의 주소가 저장되어 있어요
  • this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용해요

생성자를 이용한 인스턴스의 복사

현재 사용하고 있는 인스턴스와 같은 상태를 가진 인스턴스를 하나 더 만들고 싶을 때 생성자를 이용할 수 있어요.

여기서 복사를 수행할 때 멤버변수가 클래스같은 참조형 변수가 존재하면 의도를 잘 생각해서 작성하셔야 해요. 참조형 변수를 그대로 =으로 처리하면 값을 초기화한 것이 아닌, 변수의 주소가 복사되요. 그러면 서로 독립된 인스턴스를 만드는 것이 목적인데 해당 클래스 변수는 공유를 하게 되요.

이렇게 참조형 변수를 그대로 = 처리해서 두 변수가 공유되는 경우를 얕은 복사Shallow copy라고 해요. 완전히 독립된 복사를 수행하는 것을 깊은 복사Deep copy라고 해요. 아래의 예제를 통해 얕은 복사에 대한 주의를 적고 깊은 복사를 수행하게끔 만들어 봤어요.

class App{
	Point point;
	int a, b, c;
    App(App app){
    	// WARNING :
        // 클래스는 값이 아닌 주소를 복사하기 때문에 새로 생성해서 기본 값들을 초기화 해줘야 
        // 두 App 인스턴스의 Point 변수들이 독립적으로 동작하게 끔 해야 해요.
    	this.point = new Point();
        this.point.x = app.point.x;
        this.point.y = app.point.y;
        
    	this.a = app.a;
    	this.b = app.b;
    	this.c = app.c;
    }
}
profile
#행복 #도전 #지속성

0개의 댓글