14. 생성자
Overview
클래스는 객체를 생성하기 위한 설계도, 틀이며 객체는 설계도 또는 틀로 찍어낸 실체이다.
생성자는 객체가 생성될 때 초기화를 위해 실행되는 메소드이다.
생성자 정의와 호출
생성자는 객체가 생성되는 순간에 자동으로 호출되는 메소드로서 객체에 필요한 초기화를 수행하는 코드를 포함하고 있다.
다음 코드는 생성자를 정의하고 활용하는 예이며, 생성자의 특징을 같이 설명하고 있다.
/**
* code_07
*/
public class Samp
{
int id;
public Samp(int x) { // 생성자 오버로딩 가능, 생성자 이름은 클래스 이름과 동일
this.id = x; // 생성자는 리턴타입 없음
}
public Samp() { // 생성자 오버로딩 가능
this.id = 0; // 생성자는 리턴타입 없음
}
public void set(int x) {this.id = x;}
public int get() {return this.id;}
public static void main(String[] args) {
Samp ob1 = new Samp(3); // 자동 호출
Samp ob2 = new Samp(); // 자동 호출
Samp s;
}
}
- 생성자의 이름은 클래스 이름과 동일하다
- 클래스의 이름과 동일한 메소드가 생성자이다. 아래와 같이
Samp()
메소드가 생성자이다.public class Samp { public Samp(int x) {...} // 생성자 }
- 클래스의 이름과 동일한 메소드가 생성자이다. 아래와 같이
- 생성자는
new
를 통해 객체를 생성할 때만 호출된다.- 생성자는 오직
new
를 통해 객체를 생성할 때만 한 번 자동으로 호출된다. - 호출하고 싶을 때 아무때나 호출 할 수 없다.
Samp ob1 = new Samp(3); // 생성자 메소드 Samp(int x) 자동 호출
- 생성자는 오직
- 생성자도 오버로딩이 가능하다.
- 생성자도 메소드이므로 당연히 오버로딩이 가능하며 개발자는 여러 개의 생성자를 만들 수 있다.
Samp
클래스에는 다음 두 생성자가 오버로딩 되어 있다.public Samp(int x) {...} public Samp() {...}
- 이 때 다음
new
문장은 각각 첫 번째, 두 번째 생성자를 호출한다.Samp ob1 = new Samp(3); // 첫 번째 생성자 호출 Samp ob2 = new Samp(); // 두 번째 생성자 호출
- 생성자는 리턴 타입을 지정할 수 없다.
- 생성자는 어떤 값도 리턴하지 않기 때문에 다음과 같이 어떤 리턴 타입도 선언해서는 안 된다.
public Samp(int x) {this.id = x;}
- 이것은 일반 메소드가 아무 값을 리턴하지 않을 때
void
를 리턴 타입으로 지정하는 것과 다르다.
- 생성자는 어떤 값도 리턴하지 않기 때문에 다음과 같이 어떤 리턴 타입도 선언해서는 안 된다.
생성자의 용도
생성자의 주된 용도는 필드를 초기화하거나 객체가 처음 생성되는 순간에 처리할 작업을 수행하는 데 있다.
객체를 생성하면 필드들의 메모리 공간이 할당되지만 아직 값을 가지지 못한 상태이다.
생성자를 이용하면 필드들을 생성할 당시 초깃값을 지정할 수 있다.
특별히 인자를 갖는 생성자를 이용하여 특정한 값으로 필드를 초기화할 수도 있다.
code_07
에서는 new Samp(3)
과 같이 인자를 가진 생성자를 호출하고 3을 인자로 넘겨주어 ob1
객체의 id
값을 3으로 초기화 한다.
생성자 정의와 호출
다음 코드는 클래스 Book
에 3개의 필드를 갖도록 정의한 것이다.
public class Book {
String title;
String author;
int ISBN;
public Book(String title, String author, int ISBN) {
this.title = title;
this.author = author;
this.ISBN = ISBN;
}
public static void main(String[] args) {
Book javaBook = new Book("Java JDK", "황기태", 3333);
}
}
Book
은 하나의 생성자를 가지며 이 생성자는 3개의 필드를 초기화하기 위해 3개의 인자를 가진다.main()
메소드는Book
클래스의 객체를 생성한다.- 생성자를 통해
title
필드에 “Java JDK”,author
필드에 “황기태”,ISBN
필드에 3333이 초기화 된다.
기본 생성자
기본 생성자(default constructor)란 인자도 없고 실행 내용도 없이 단순 리턴하는 생성자이며 디폴트 생성자라고도 부른다.
다음과 같이 간단히 예를 들 수 있다.
class Book {
public Book();
}
기본 생성자는 자동으로 생성된다.
생성자가 없는 클래스는 있을 수 없다.
클래스에 생성자가 하나도 선언되어 있지 않으면 컴파일러가 기본 생성자를 자동으로 생성한다.
그 이유는 객체가 생성될 때 반드시 생성자가 호출되어야 하기 때문이다.
예를 들어 생성자가 정의되지 않은 다음 코드를 보자. main()
메소드에서 다음 new
문은 인자 없는 생성자를 필요로 하고 있다.
DefaultConstructor p = new DefaultConstructor();
이를 위해 컴파일러는 code_09
과 같이 컴파일 시 기본 생성자를 삽입하여 new DefaultConstructor();
의 호출이 가능하게 한다.
컴파일러가 기본 생성자를 자동으로 생성한다고 해서 DefaultConstructor.java
소스 파일이 code_09
로 변하는 것은 아니다.
/**
* code_08
* 생성자가 정의되지 않은 클래스
*/
public class DefaultConstructor {
int x;
public void setX(int x) {this.x = x;}
public int getX() {return x;}
public static void main(String[] args) {
DefaultConstructor p = new DefaultConstructor(); // 정상 컴파일 가능
p.setX(3);
}
}
/**
* code_09
* 컴파일러에 의해 보이지 않게 자동으로 기본 생성자 삽입
*/
public class DefaultConstructor {
int x;
public void setX(int x) {this.x = x;}
public int getX() {return x;}
public DefaultConstructor() {} // 컴파일러에 의해 자동 삽입된 기본 생성자
// 사용자의 눈에는 보이지 않게 삽입된다.
public static void main(String[] args) {
DefaultConstructor p = new DefaultConstructor();
p.setX(3);
}
}
- 기본 생성자가 자동으로 생성되지 않은 경우
- 생성자가 하나라도 존재하는 클래스에는 자동으로 기본 생성자가 삽입되지 않는다.
- 기본 생성자가 자동으로 생성되는 경우는 클래스 내에 생성자가 하나도 없는 경우에만 해당한다.
- 그러므로 다음 소스는 컴파일 오류가 발생한다. 다음 코드의
main()
메소드의 다음new
문장을 보자.
/**
* code_10
* 컴파일러가 기본 생성자를 자동으로 삽입하지 않은 경우의 예
*/
public class DefaultConstructor {
int x;
public void setX(int x) {this.x = x;}
public int getX() {return x;}
public DefaultConstructor(int x) {
this.x = x;
} // 매개변수가 없는 기본 생성자를 자동생성하지 않음
public static void main(String[] args) {
DefaultConstructor p1 = new DefaultConstructor(3);
int n = p1.getX();
DefaultConstructor p2 = new DefaultConstructor(); // 컴파일 오류. 해당하는 생성자 없음
p2.setX(3);
}
}
this(), 다른 생성자 호출
this()
는 한 클래스 내에서 한 생성자에서 다른 생성자를 호출할 때 사용하는 자바 코드이다.
한 클래스 내의 어떤 메소드가 다른 메소드를 호출할 수 있는 것처럼 생성자도 중복된 다른 생성자를 호출할 수 있다.
this()
는 동일한 클래스 내의 다른 생성자의 호출이다.
3개의 생성자를 가진 다음 소스를 보자.
/**
* code_11
* Book 클래스에 this()를 사용한 예
*/
public class Book {
String title;
String author;
int ISBN;
public Book(String title, String author, int ISBN) {
this.title = title;
this.author = author;
this.ISBN = ISBN;
}
public Book(String title, int ISBN) {
this.(title, "Anonymous", ISBN);
}
public Book() {
this(null, null, 0);
System.out.println("생성자 호출 완료");
}
public static void main(String[] args) {
Book javaBook = new Book("Java JDK", "황기태", 3333);
Book holyBible = new Book("HolyBible", 1);
Book emptyBook = new Book();
}
}
main()
에서 다음 문장은Book
클래스의 두 번째 생성자를 호출한다.Book holyBible = new Book("HolyBible", 1);
- 두 번째 생성자가 호출될 때
title
과ISBN
에는 각각 “HolyBible” 문자열과 정수 1이 전달된다.- 이 생성자는 바로 다음 문장을 실행한다.
this.(title, "Anonymous", ISBN);
- 이 생성자는 바로 다음 문장을 실행한다.
- 이 문장은 다음과 같이 3개의 인자를 가진 첫 번째 생성자를 다시 호출하게 된다.
public Book(String title, String author, int ISBN) { ... }
- 이 생성자에 의해 멤버 필드
title
,author
,ISBN
은 각각 “HolyBible”, “Anonymous”, 1의 값으로 초기화된다.
- 이 생성자에 의해 멤버 필드
this()
는 다음과 같은 몇 가지 주요한 특징을 가진다.this()
는 생성자 코드에서만 사용할 수 있다.
this()
는 동일한 클래스 내의 다른 생성자를 호출할 때 사용한다.
this()
는 반드시 생성자의 첫 문장에서 사용되어야 한다.public Book() { System.out.println("생성자 호출 완료"); this(null, null, 0); // 컴파일 오류. 이 문장이 생성자의 첫 번째 문장이 아님 }