4-1. 생성자 - 필요한 이유
객체를 생성하는 시점에 어떤 작업을 하고 싶다면 생성자(Construct)를 이용
MemberInit.java (클래스)
package construct;
public class MemberInit {
String name;
int age;
int grade;
}
MethodInitMain1.java
package construct;
public class MethodInitMain1 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
member1.name = "user1";
member1.age = 15;
member1.grade = 90;
MemberInit member2 = new MemberInit();
member2.name = "user2";
member2.age = 16;
member2.grade = 80;
MemberInit[] members = {member1, member2};
for (MemberInit s : members) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
}
- 회원 객체를 제대로 사용하기 위해서는, 객체를 생성하자 마자 name, age, grade 초기값을 설정해야 함.
- 회원의 초기값 설정하는 반복코드를 메서드를 사용해 제거할 예정
MethodInitMain2.java (반복 코드를 메서드로)
package construct;
public class MethodInitMain2 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
initMember(member1, "user1", 15, 90);
MemberInit member2 = new MemberInit();
initMember(member2, "user2", 16, 80);
MemberInit[] members = {member1, member2};
for (MemberInit s : members) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
static void initMember(MemberInit member, String name, int age, int grade) {
member.name = name;
member.age = age;
member.grade = grade;
}
}
- initMember(...) 메서드를 사용해서 반복을 제거
- initMember(...) 메서드는 대부분 MemberInit 객체의 멤버 변수를 사용
=> MemberInit이 자신의 데이터를 변경하는 기능(메서드)을 제공하는 것이 좋음. (속성과 기능을 한 곳에)
4-2. this
MemberInit.java (initMember( ) 추가)
package construct;
public class MemberInit {
String name;
int age;
int grade;
// 추가
void initMember(String name, int age, int grade) {
this.name = name; // 멤버 변수와 매개 변수의 이름이 같을 때 가까운 순으로 우선순위를 가진다.
this.age = age; // this는 인스턴스 자신(참조값)을 가리키기 때문에
this.grade = grade; // this.grade 는 x001.grade 가 된다.
}
}
MethodInitMain3.java
package construct;
public class MethodInitMain3 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
member1.initMember("user1", 15, 90);
MemberInit member2 = new MemberInit();
member2.initMember("user2", 16, 80);
MemberInit[] members = {member1, member2};
for (MemberInit s : members) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
}
- 메서드를 호출하면 객체의 멤버 변수에 인자로 넘어온 값을 채운다.
=> member1.initMember("user1", 15, 90)
this
멤버 변수와 메서드의 매개변수의 이름이 같을 때,
- 멤버 변수보다 매개변수가 코드 블럭의 더 안쪽에 있기에 매개변수가 우선순위를 가진다.
=> initMember (String name,...) 메서드 안에서 name이라고 적으면 매개변수에 접근 - 멤버 변수에 접근하려면 앞에 this.를 기입 => this는 인스턴스 자신의 참조값을 가리킴.
MethodInitMain3.java (this의 생략)
package construct;
public class MemberThis {
String nameField;
void initMember(String nameParameter) {
nameField = nameParameter; // nameField는 매개변수로 사용이 되지 않았기에 this 생량
}
}
- nameField는 initMember(...) 메서드 매개변수의 이름과 같지 않아 멤버 변수로 우선순위가 넘어가므로 생략 가능
4-3. 생성자 - 도입
생성자를 사용하면 객체를 생성하는 시점에 즉시 필요한 기능을 수행
MemberConstruct.java (생성자)
package construct;
public class MemberConstruct {
String name;
int age;
int grade;
MemberConstruct(String name, int age, int grade) {
System.out.println("생성자 호출 name=" + name + ", age=" + age + ", grade=" + grade);
this.name = name;
this.age = age;
this.grade = grade;
}
}
생성자와 메서드 차이
- 생성자의 이름은 클래스 이름과 같음 (생성자명 = 클래스명). 따라서 첫 글자도 대문자로 시작
- 생성자는 반환 타입이 없다. 비워두어야 한다.
- 나머지는 메서드와 같다.
ConstructMain1.java (생성자)
package construct;
public class ConstructMain1 {
public static void main(String[] args) {
MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
// Ctrl+P 어떤 파라미터가 필요한지 확인하는 단축키
// 객체를 생성하는 동시에 생성자를 호출함.
MemberConstruct member2 = new MemberConstruct("user2", 16, 80);
MemberConstruct[] members = {member1, member2};
for (MemberConstruct s : members) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
}
- Ctrl+P: 어떤 파라미터가 필요한지 확인하는 단축키
생성자 호출
생성자는 인스턴스를 생성하고 즉시 호출됨.
호출 방법 => new 명령어 다음에 생성자 이름과 매개변수에 맞는 인수를 전달
new 생성자이름(생성자에 맞는 인수 목록)
new 클래스이름(생성자에 맞는 인수 목록)
// 생성자이름 = 클래스이름
생성자 장점 => 중복 호출 제거
// 생성자 등장 전
MemberInit member = new MemberInit();
member.initMember("user1", 15, 90);
// 생성자 등장 후
MemberConstruct member = new MemberConstruct("user1", 15, 90);
제약(혹은 장점) => 생성자 호출 필수
생성자를 사용하지 않을 때는 initMemer(..) 메서드를 호출하지 않아도 프로그램은 작동한다.
하지만 회원의 이름, 나이, 성적 데이터가 없는 상태로 동작하기 때문에 추후 시스템에 문제가 발생할 수 있다.
생성자를 사용하면, 객체를 생성할 때 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다.
생성자를 메서드 오버로딩처럼 여러개 정의할 수 있는데, 그 중 하나만 호출하면 된다.
직접 정의한 생성자를 호출하지 않으면 컴파일 오류가 발생해, 정보가 없는 유령회원의 등장을 원천 차단
※ 좋은 프로그램은 무한한 자유도가 주어지는 프로그램이 아니라 적절한 제약이 있는 프로그램
4-4. 기본 생성자
생성자를 만들지 않았는데, 생성자를 호출했었다.
MemberInit member1 = new MemberInit();
기본 생성자
- 매개변수가 없는 생성자
- 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동 생성
- 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않음
public class MemberInit {
String name;
int age;
int grade;
public MemberInit() { // 이와 같은 기본 생성자가 자동으로 생성
}
}
MemberDefault.java
package construct;
public class MemberDefault {
String name;
// 기본 생성자
// public MemberDefault() { }
MemberDefault() {
System.out.println("생성자 호출");
}
}
자바가 자동으로 생성해주는 기본 생성자는 클래스와 같은 접근 제어자를 가진다. ex) public
MemberDefaultMain.java
package construct;
public class MemberDefaultMain {
public static void main(String[] args) {
MemberDefault memberDefault = new MemberDefault();
}
}
기본 생성자를 자동으로 만드는 이유
- 생성자는 반드시 호출되어야 하는데,
- 기본 생성자 자동 생성이 없으면,
- 생성자 기능이 필요하지 않은 경우에도 모든 클래스에 개발자가 직접 기본 생성자를 정의해야 함.
4-5. 생성자 - 오버로딩과 this( )
MemberConstruct.java (생성자 추가)
package construct;
public class MemberConstruct {
String name;
int age;
int grade;
// 추가
MemberConstruct(String name, int age) {
this.name = name;
this.age = age;
this.grade = 50;
}
MemberConstruct(String name, int age, int grade) {
System.out.println("생성자 호출 name=" + name + ", age=" + age + ", grade=" + grade);
this.name = name;
this.age = age;
this.grade = grade;
}
}
ConstructMain2.java
package construct;
public class ConstructMain2 {
public static void main(String[] args) {
MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
MemberConstruct member2 = new MemberConstruct("user2", 16);
MemberConstruct[] members = {member1, member2};
for (MemberConstruct s : members) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
}
this( )
생성자에서 중복되는 코드를 수정
this.name = name;
this.age = age;
MemberConstruct.java (this( ) 사용)
package construct;
public class MemberConstruct {
String name;
int age;
int grade;
// 추가 1
/*
MemberConstruct(String name, int age) {
this.name = name;
this.age = age;
this.grade = 50;
}
*/
// 추가 2 - this()
MemberConstruct(String name, int age) {
// System.out.println("hello"); // this()는 생성자 코드 첫줄에 입력해야함.
this(name, age, 50); // 변경
}
MemberConstruct(String name, int age, int grade) {
System.out.println("생성자 호출 name=" + name + ", age=" + age + ", grade=" + grade);
this.name = name;
this.age = age;
this.grade = grade;
}
}
- this( )를 사용하면 생성자 내부에서 다른 생성자를 호출
- this는 인스턴스 자신의 참조값을 가리킴 => 자신의 생성자를 호출한다.
this( ) 규칙
- this( )는 생성자 코드의 첫줄에만 작성 가능
- 아니면, 컴파일 오류가 발생
4-6. 문제와 풀이
Book.java
package construct.ex;
public class Book {
String title; // 제목
String author; // 저자
int page; // 쪽 수
Book(){
this("", "", 0); // => 놓침
}
Book(String title, String author) {
this.title = title;
this.author = author;
// or this(title, author, 0);
}
Book(String title, String author, int page) {
this.title = title;
this.author = author;
this.page = page;
}
void displayInfo() {
System.out.println("제목: "+title+", 저자: "+author+", 페이지: "+page);
}
}
※ 생성자는 객체 생성 직후 객체를 초기화 하기 위한 특별한 메서드