1. 기본 생성자
2. 필드 초기화
3. 생성자 오버로딩
생성자(Constructor)는 new 연산자와 함께 객체를 생성할 때 사용합니다. 지금까지 우리는 생성자를 알지 못했지만, 클래스를 이용해 객체를 생성할 때 항상 생성자를 사용해 왔습니다. 생성자는 메서드와 비슷하게 생겼지만, 클래스 이름과 생성자 이름이 동일해야 하고, 리턴값이 없습니다. 리턴 타입도 아예 적어주지 않습니다.
생성자는 객체가 생성될 때 가장 먼저 실행되므로, 객체 내의 필드(변수)를 초기화하거나, 객체를 사용하기 전에 준비하는 실행문을 생성자 블록 안에 넣는 경우가 많습니다. 즉 생성자의 용도는 객체의 초기화 목적입니다.
생성자의 구조를 살펴볼까요.
클래스명 (매개변수...) {
초기화 실행문
...
}
메서드의 구조와 비슷하죠? 여기서 생성자명이 곧 클래스명이 됩니다. 생성자도 메서드와 마찬가지로 매개변수가 있을 수도 있고, 없을 수도 있습니다. 그리고 또한 중괄호로 블록이 구분되며, 리턴값은 존재하지 않습니다.
1. 기본 생성자
모든 클래스는 생성자가 반드시 하나 이상 존재합니다. 그런데 지금까지 앞에 예제들은 생성자를 만든적이 없었죠? 왜냐하면 아무 기능도 없는 빈 생성자가 컴파일 시 자동으로 추가되기 때문입니다.
Member.java
public class Member {
...
}
Member.class
public class Member {
public Member() { // 기본 생성자 자동 생성
}
}
Member라는 java 파일을 새로 만들고 생성자를 만들지 않았지만, 컴파일되어 class파일의 바이트코드로 변환되면, Member()라는 기본 생성자가 자동으로 추가됩니다. 그래서 우리는 객체를 생성할 때 기본 생성자를 실행해서 객체를 생성시킬 수 있습니다.
Member member = new Member();
new 연산자 뒤의 Member() 가 바로 기본 생성자입니다.
2. 필드 초기화
기본 생성자가 아닌 직접 생성자를 정의할 수 있는데, 생성자는 메서드와 비슷하게 생겼으나, 리턴값이 없고, 생성자명이 클래스명과 동일합니다. 생성자의 용도는 객체를 생성할 때 초기화하는 목적입니다. Student라는 클래스로 객체를 생성할 때 필드를 초기화하는 예제를 살펴보겠습니다.
public class Student {
// 필드
String name; // 학생명
int grade; // 학년
String department; // 학과
Student(String n, int g, String d) {
name = n;
grade = g;
department = d;
}
}
public class StudentMain {
public static void main(String[] args) {
Student stu = new Student("홍길동", 4, "소프트웨어공학");
System.out.println(stu.name);
System.out.println(stu.grade);
System.out.println(stu.department);
}
}
실행 결과
홍길동
4
소프트웨어공학
Student 클래스는 필드3개와 생성자 하나를 가지고 있는데, 이 생성자는 매개변수 3개를 입력받아 name, grade, department 세 개의 필드에 대입하고 있습니다. 즉 필드의 초기값을 세팅하고 있는 것이죠. 객체가 생성될 때 필드의 초기값이 없으면 기본값으로 자동 설정되는데, 이 생성자는 매개변수로 초기값을 설정해주고 있습니다.
StudentMain 클래스의 main 메서드에서는 Student 객체를 생성하고 있습니다. new 연산자 뒤에 생성자가 오는데 매개변수가 3개 있는 Student 클래스의 생성자 임을 알 수 있습니다. 이 “홍길동”과 4, “소프트웨어공학” 이 세개의 매개변수를 필드로 초기화 해줬기 때문에, 출력결과가 실행 결과와 같이 출력된 것입니다. 이번엔 StudentMain 클래스에서 새로운 객체를 추가해보겠습니다.
public class StudentMain {
public static void main(String[] args) {
Student stu = new Student("홍길동", 4, "소프트웨어공학");
System.out.println(stu.name);
System.out.println(stu.grade);
System.out.println(stu.department);
Student stu2 = new Student("이순신", 3, "디자인");
System.out.println(stu2.name);
System.out.println(stu2.grade);
System.out.println(stu2.department);
}
}
실행 결과
홍길동
4
소프트웨어공학
이순신
3
디자인
stu 객체와 stu2 객체는 독립적인 객체이며, 각 객체의 name, grade, department 필드에는 모두 다른 값들이 저장되어 있습니다.
이번엔 기본 생성자를 통해 객체를 생성해 보겠습니다.
public class StudentMain {
public static void main(String[] args) {
Student stu = new Student("홍길동", 4, "소프트웨어공학");
System.out.println(stu.name);
System.out.println(stu.grade);
System.out.println(stu.department);
Student stu2 = new Student("이순신", 3, "디자인");
System.out.println(stu2.name);
System.out.println(stu2.grade);
System.out.println(stu2.department);
// 기본 생성자로 객체 생성
Student stu0 = new Student(); // 에러 발생
}
}
main 메서드의 마지막 라인에 Student() 기본 생성자로 객체를 생성하려고 하는데, 에러가 발생합니다. 만약 매개변수가 있는 생성자를 정의한 경우는 기본 생성자가 자동으로 추가되지 않습니다. 그래서 위 예제와 같이 Student(String name, int grade, String department)라는 생성자가 정의되면 Student() 생성자(기본 생성자)는 사용할 수 없으므로 직접 정의를 해줘야만 합니다.
public class Student {
// 필드
String name; // 학생명
int grade; // 학년
String department; // 학과
Student(String n, int g, String d) {
name = n;
grade = g;
department = d;
}
// 기본 생성자
Student () {
}
}
Student 클래스에 생성자를 추가했습니다. 이제 위의 StudentMain에서 기본 생성자로 객체를 생성해도 에러가 발생하지 않게 됩니다.
3. 생성자 오버로딩
메서드 오버로딩과 동일합니다. 생성자는 객체를 초기화 할 때 필요한 다양한 매개변수들이 필요한데, 매개변수 타입이나 개수가 다른 동일한 이름의 생성자를 사용해 여러개를 정의할 수 있습니다.
Student.java
public class Student {
// 필드
String name; // 학생명
int grade; // 학년
String department; // 학과
// 1번 생성자
Student() {
}
// 2번 생성자
Student(String n) {
name = n;
}
// 3번 생성자
Student(String n, int g) {
name = n;
grade = g;
}
// 4번 생성자
Student(String n, int g, String d) {
name = n;
grade = g;
department = d;
}
}
StudentMain.java
public class StudentMain {
public static void main(String[] args) {
Student stu1 = new Student(); // 1번 생성자
Student stu2 = new Student("홍길동"); // 2번 생성자
Student stu3 = new Student("홍길동", 4); // 3번 생성자
Student stu4 = new Student("홍길동", 4, "소프트웨어공학"); // 4번 생성자
}
}
Student 클래스에서 총 4개의 생성자가 오버로딩 되어 있습니다. 매개변수에 따라 각각 다른 초기화 작업을 수행하고 있습니다. StudentMain 클래스에서 4개의 객체를 생성하고 있는데 각 생성자는 1번 ~ 4번 생성자 각각 다른 생성자를 이용해 객체를 생성하였습니다. 생성자 중에 이름과 학년을 매개변수로 받는 3번 생성자가 있는데, 이번엔 학과명과 학년을 매개변수로 받는 생성자를 추가해 보겠습니다.
public class Student {
// 필드
String name; // 학생명
int grade; // 학년
String department; // 학과
// 1번 생성자
Student() {
}
// 2번 생성자
Student(String n) {
name = n;
}
// 3번 생성자
Student(String n, int g) {
name = n;
grade = g;
}
// 4번 생성자
Student(String n, int g, String d) {
name = n;
grade = g;
department = d;
}
// 학과와 학년을 매개변수로 받는 생성자 (에러 발생)
Student(String d, int g) {
department = d;
grade = g;
}
}
학과와 학년을 매개변수로 지정한 생성자인데, 에러가 발생하게 됩니다. 이 생성자와 위 3번 생성자에 빨간 밑줄이 쳐지면서 에러 표시가 나타나게 되는데요, 분명히 이름과 학과는 다른 변수인데, 마우스를 빨간 밑줄에 갖다대보면 중복됐다고 메시지를 보여줍니다. 왜 다른 변수인데, 중복되는 것일까요?
Student(String n, int g) { ... }
Student(String d, int g) { ... }
이 두 생성자는 매개변수명은 분명히 다르지만 매개변수 타입과 순서가 완전히 동일합니다. 매개변수는 이 생성자 안에서만 사용되는 지역변수 이름일 뿐, 자바 컴파일러는 이 매개변수가 이름으로 사용되는지, 학과로 사용되는지 학년으로 사용되는지는 중요하지 않습니다. 단지 매개변수 타입이 (문자열, 정수) 이기 때문에 에러가 발생 하는 것입니다.