안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
생성자란?
- 객체를 생성하는 역할을 지님
생성자의 특징
- 반드시 클래스명과 동일한 이름
- 리턴 타입이 없음
- 아무 생성자도 작성하지 않은 경우, JVM이 기본 생성자를 생성하여 호출
기본 생성자가 필요한 이유
- 상속 시 자식 클래스에서 부모 클래스의 기본 생성자를 자동으로 호출 (없으면 오류!)
- spring framework에서 빈 생성 시 기본 생성자를 호출
생성자는 new 연산자를 통해 호출 되는 메소드로, 메모리에 객체 할당 후 필드 값 초기화 목적으로 사용합니다.
User u1 = new User();
User : 클래스(타입)
u1 : 참조변수명
User() : 생성자
생성자를 이용하여 객체를 생성해왔는데, 오류가 나지 않은 이유는 JVM이 기본 생성자를 자동으로 생성해주었기 때문입니다.
(모든 클래스는 생성자를 포함해야함!!!)
public class User {
//filed
private String userId;
private String userPw;
private String userName;
private boolean snsAlarm;
private Date enrollDate;
//constructor 자동 생성되는 기본 생성자
// public User() {}
//getter, setter
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserPw(String userPw) {
this.userPw = userPw;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setSnsAlarm(boolean snsAlarm) {
this.snsAlarm = snsAlarm;
}
public void setEnrollDate(Date enrollDate) {
this.enrollDate = enrollDate;
}
public String getUserId() {
return userId;
}
public String getUserPw() {
return userPw;
}
public String getUserName() {
return userName;
}
public boolean isSnsAlarm() {
return snsAlarm;
}
public Date getEnrollDate() {
return enrollDate;
}
//출력 메소드
public String printUserInfo() {
return "[" + userId + ", " + userPw + ", " + userName + ", " + snsAlarm + ", " + enrollDate + "]";
}
}
public class UserMain {
public static void main(String[] args) {
User u1 = new User();
u1.setUserId("honggd");
u1.setUserPw("1234");
u1.setUserName("홍길동");
u1.setSnsAlarm(true);
u1.setEnrollDate(new Date());
System.out.println(u1.printUserInfo());
}
}
@콘솔출력값
[honggd, 1234, 홍길동, true, Thu Mar 17 20:03:15 KST 2022]
생성자를 직접 호출해주지 않아도 JVM이 자동으로 기본 생성자를 생성해주어 문제 없이 출력할 수 있었습니다.
생성자가 호출 되는 것만으로도 객체가 내부적으로 생성됩니다.
생성자의 중괄호 안은 객체가 생성된 이후 할 일이 작성되는 부분이며, 일반적으론 여기서 필드를 초기화합니다.
물론 기본 생성자를 직접 생성해주어도 됩니다.
public class User {
//filed
private String userId;
private String userPw;
private String userName;
private boolean snsAlarm;
private Date enrollDate;
//constructor 직접 기본생성자 생성
public User() {}
//getter, setter
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserPw(String userPw) {
this.userPw = userPw;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setSnsAlarm(boolean snsAlarm) {
this.snsAlarm = snsAlarm;
}
public void setEnrollDate(Date enrollDate) {
this.enrollDate = enrollDate;
}
public String getUserId() {
return userId;
}
public String getUserPw() {
return userPw;
}
public String getUserName() {
return userName;
}
public boolean isSnsAlarm() {
return snsAlarm;
}
public Date getEnrollDate() {
return enrollDate;
}
//출력 메소드
public String printUserInfo() {
return "[" + userId + ", " + userPw + ", " + userName + ", " + snsAlarm + ", " + enrollDate + "]";
}
}
public class UserMain {
public static void main(String[] args) {
User u1 = new User();
u1.setUserId("honggd");
u1.setUserPw("1234");
u1.setUserName("홍길동");
u1.setSnsAlarm(true);
u1.setEnrollDate(new Date());
System.out.println(u1.printUserInfo());
}
}
@콘솔출력값
[honggd, 1234, 홍길동, true, Thu Mar 17 20:06:11 KST 2022]
기본생성자를 직접 생성해주어도 문제 없이 잘 출력이 됩니다.
그렇다면 파라미터(매개변수가 있는) 생성자를 만들어보겠습니다.
public class User {
//filed
private String userId;
private String userPw;
private String userName;
private boolean snsAlarm;
private Date enrollDate;
//constructor
// public User() {
// System.out.println("기본 생성자 호출!");
// }
//파라미터 생성자
public User(String userId, String userPw) {
this.userId = userId;
this.userPw = userPw;
}
//getter, setter 편의상 생략
//...
//출력 메소드
public String printUserInfo() {
return "[" + userId + ", " + userPw + ", " + userName + ", " + snsAlarm + ", " + enrollDate + "]";
}
public class UserMain {
public static void main(String[] args) {
// User u1 = new User();
// u1.setUserId("honggd");
// u1.setUserPw("1234");
// u1.setUserName("홍길동");
// u1.setSnsAlarm(true);
// u1.setEnrollDate(new Date());
// System.out.println(u1.printUserInfo());
User u2 = new User("sinsa", "1111");
System.out.println(u2.printUserInfo());
}
}
@콘솔출력값
[sinsa, 1111, null, false, null]
생성자의 매개인자를 넘겨주어 생성자 매개변수로 받아 넘겨받은 지역변수 값을 필드 변수로 대입해주었습니다.
그 후 출력하니 입력한 userId와 userPw의 값이 잘 출력 되는 것을 확인할 수 있었습니다.
그렇다면 기존에 생성했던 기본 생성자를 이용하여 만들었던 u1은 어떻게 되는 것일까요?
주석을 풀면 오류가 발생합니다. (The constructor User() is undefined)
생성자 User()가 정의되지 않았다는 오류 메세지가 뜨는 것을 알 수 있습니다.
그 이유는?
User 클래스는 생성자가 이미 정의 되어있기 때문에 생성자를 이용하여 객체 생성이 가능합니다.
따라서 JVM은 생성자를 이용해 객체 생성할 수 있는 클래스라고 인식하여 굳이 기본 생성자를 또 추가를 해주지 않는 것이죠!
u1을 사용하고 싶다면, 기본 생성자를 직접 정의 해줘야 합니다.
☆ 파라미터(매개변수가 있는) 생성자를 하나라도 작성한 경우, 기본 생성자를 명시적으로 작성해줘야 합니다.
☞ 생성자의 오버로딩
- 위에서 짐작하였겠지만, 생성자 또한 오버로딩이 가능하며 메소드 오버로딩과 동일합니다. (메소드 시그니처에 따라)
그렇다면 총 3개의 생성자를 만들어보겠습니다.
public class User {
//filed
private String userId;
private String userPw;
private String userName;
private boolean snsAlarm;
private Date enrollDate;
//constructor
public User() {
System.out.println("기본 생성자 호출!");
}
public User(String userId, String userPw) {
this.userId = userId;
this.userPw = userPw;
}
public User(String userId, String userPw, String userName, boolean snsAlarm, Date enrollDate) {
this.userId = userId;
this.userPw = userPw;
this.userName = userName;
this.snsAlarm = snsAlarm;
this.enrollDate = enrollDate;
}
//getter, setter (편의 상 생략)
//...
//출력 메소드
public String printUserInfo() {
return "[" + userId + ", " + userPw + ", " + userName + ", " + snsAlarm + ", " + enrollDate + "]";
}
}
public class UserMain {
public static void main(String[] args) {
User u1 = new User();
u1.setUserId("honggd");
u1.setUserPw("1234");
u1.setUserName("홍길동");
u1.setSnsAlarm(true);
u1.setEnrollDate(new Date());
System.out.println(u1.printUserInfo());
User u2 = new User("sinsa", "1111");
System.out.println(u2.printUserInfo());
User u3 = new User("channy", "8888", "채니", false, new Date());
System.out.println(u3.printUserInfo());
}
}
@콘솔출력값
기본 생성자 호출!
[honggd, 1234, 홍길동, true, Thu Mar 17 20:21:37 KST 2022]
[sinsa, 1111, null, false, null]
[channy, 8888, 채니, false, Thu Mar 17 20:21:37 KST 2022]
메소드 시그니처가 상이하기 때문에 문제 없이 생성자를 여러개 생성할 수 있었으며,
매개변수의 타입, 개수, 순서에 맞게 생성자의 매개인자를 입력해주어 값을 출력해보았습니다.
여기서! 중복되는 코드로 인하여 다소 걸리적 거리는 요소가 있습니다.
public User(String userId, String userPw) {
this.userId = userId;
this.userPw = userPw;
}
public User(String userId, String userPw, String userName, boolean snsAlarm, Date enrollDate) {
this.userId = userId;
this.userPw = userPw;
this.userName = userName;
this.snsAlarm = snsAlarm;
this.enrollDate = enrollDate;
}
바로 이 두 생성자 인데요,
첫번째 생성자는 userId, userPw를 매개인자로 받고
두번째 생성자는 userId, userPw, userName, snsAlarm, enrollDate를 매개인자로 받습니다.
저는 여기서 userId, userPw가 두 번이나 중복 되는 것이 거슬리게 되는데요...
이 문제를 해결하기 위해서 this() 키워드를 사용해줍니다!
☞ this() 키워드
- 생성자에서 다른 생성자 호출
- 생성자 맨 첫 줄에 단 한 번만 사용 가능!
public User(String userId, String userPw) {
this.userId = userId;
this.userPw = userPw;
}
public User(String userId, String userPw, String userName, boolean snsAlarm, Date enrollDate) {
this(userId, userPw);
// this.userId = userId;
// this.userPw = userPw;
this.userName = userName;
this.snsAlarm = snsAlarm;
this.enrollDate = enrollDate;
}
this() 키워드를 이용하여 중복 되는 코드를 제거해주었습니다.
this(userId, userPw) 는 this(String 타입, String 타입)를 받아줄 수 있는 생성자를 찾아가서 실행하라는 것입니다.
따라서 this(userId, userPw)를 실행하면,
첫번째 생성자에게 userId, userPw를 매개인자로 넘겨주어 생성자는 각각을 매개변수로 받게 되고 그 값들을 각 userId와 userPw 필드에 대입 시키게 되는 것입니다.
(대신 반드시 매개인자와 매개변수의 타입은 동일해야겠죠?)
'Java > Java' 카테고리의 다른 글
배열) 객체 배열, VO class 설계 (0) | 2022.03.18 |
---|---|
this키워드(this.)와 this()메소드 (0) | 2022.03.17 |
메소드) 재귀 메소드 (Recurison) (0) | 2022.03.17 |
메소드) call by value, call by reference (0) | 2022.03.17 |
메소드) 메소드 오버로딩, 메소드 시그니처란? (0) | 2022.03.17 |