본문 바로가기
Java/Java

생성자) 기본 생성자, 파라미터 생성자, 생성자 오버로딩, this()

by 박채니 2022. 3. 17.
SMALL

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


생성자란?

- 객체를 생성하는 역할을 지님

 

생성자의 특징

- 반드시 클래스명과 동일한 이름

- 리턴 타입이 없음

- 아무 생성자도 작성하지 않은 경우, 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 필드에 대입 시키게 되는 것입니다. 
(대신 반드시 매개인자와 매개변수의 타입은 동일해야겠죠?)

 

 

 

 

LIST