[자바] 생성자(Constructor)

컴공생의 코딩 일기·2021년 7월 31일
3

자바

목록 보기
4/10
post-thumbnail

목차

  • 생성자(Constructor)란
  • 생성자(Constructor) 사용 방법
  • 생성자(Constructor) 특징
  • 생성자(Constructor) 사용이유
  • this
  • this()
  • 생성자(Constructor) 오버로딩
  • 접근제한자

생성자(Constructor)란

생성자란 new 연산자에 의해서 단 한 번 호출되는 단위입니다. 우리는 그 동안 생성자를 따로 정의하지 않았습니다. 하지만 객체는 new 연산자에 의해서 무조건 단 한 번 호출됩니다.

why?

우리가 그 동안 따로 생성자를 정의하지 않고 객체가 오류 없이 동작한 이유는 객체는 정의된 생성자가 없다면 컴파일러가 자동으로 빈 생성자를 만들어 줍니다. 그렇기 때문에 우리는 그 동안 따로 생성자를 정의하지 않아도 컴파일러가 자동으로 빈 생성자를 만들어 줬기 때문에 오류 없이 사용할 수 있었던 것입니다.

주의: 클래스에 인자가 있는 생성자가 하나 이상 존재하고 객체 선언 시 생성자 호출 부분에 인자가 없을 경우 반드시 빈 생성자를 만들어 줘야 합니다.

생성자(Constructor) 사용 방법

클래스명 변수명  = new 클래스명();  // 기본 생성자
클래스명 변수명 = new 클래스(매개변수(파라미터),...);  // 생성자 
클래스명 {

클래스명(매개변수(파라미터),....){

}

생성자(Constructor) 특징

  1. 생성자는 매개변수(파라미터)가 있지만 리턴타입이 없다.
  2. 개발자가 생성자를 정의하지 않을경우 컴파일시 자동으로 빈 생성자를 만들어 준다.
  3. 생성자는 클래스 이름과 같아야 한다.
  4. 여려 개의 생성자를 만들수 있다.
  5. 생성자는 메서드인 척 한다. (리턴 타입만 없지 다른 기능은 매서드랑 같은 동작을한다.)

생성자(Constructor) 사용이유

생성자를 사용하는 이유는 멤버변수(클래스 안에 변수)에 값을 더 편하게 초기화 위해서 입니다.
글로만 봐서는 이해하기 쉽지 않습니다. 예를 하나 들어 보겠습니다.

예제)

// 생성자를 사용하지 않은 경우
class Student {
	String name; // 학생 이름
	int age; // 학생 나이
	int number; // 학생 학번
}

public class StudentMain {

	public static void main(String[] args) {

		Student st = new Student();

		st.name = "홍길동";
		st.age = 20;
		st.number = 00000000;
	}

}
// 생성자를 이용해 멤버변수를 초기화 

class Student {
	String name; // 학생 이름
	int age; // 학생 나이
	int number; // 학생 학번

	Student() {
	}

	Student(String name, int age, int number) {
		this.name = name;
		this.age = age;
		this.number = number;
	}

}

public class Test01 {

	public static void main(String[] args) {
		Student st1 = new Student(); // 생성자 호출 부분에 인자가 없고 클래스에 인자가 있는
										// 생성자가 하나 이상 존재하기 때문에 빈 생성자를
										// 만들어 줘야 합니다.
		Student st2 = new Student("홍길동", 20, 111111);
	}

}

두 코드의 차이가 보이시나요? 생성자를 사용하지 않았을때는 Main 클래스에서 클래스 변수에 값을 하나 하나씩 초기화를 해줘야 합니다. 하지만 생성자를 사용했을 때는 인스턴스 생성시 멤버변수의 값들도 한번에 초기화해 줄 수 있어서 훨씬 효율적입니다.

this

this는 클래스내의 멤버변수를 가리킬때 사용합니다. 클래스내에서 생성자나 매서드를 만들때 클래스의 멤버변수와 매개변수를 같은 이름으로 정의하는 경우가 많습니다. 그 이유는 같은 기능을 하는 변수를 같은 이름으로 묶게되면 헷갈리지 않고 여러개의 변수 이름을 정의할 번거러움을 줄이기 때문입니다. 하지만 같은 이름을 사용할 경우 컴퓨터는 어떤것이 멤버변수이고 어떤 것이 매개변수인지 모르기 때문에 this()를 사용 이게 매개변수라고 알려주는 것입니다.

this 사용시 주의할 점: static 메서드에서는 this를 사용할 수 없다.

this 사용방법

class Student {
	String name; // 학생 이름
	int age; // 학생 나이
	int number; // 학생 학번

	Student() { // 개발자가 따로 생성자를 정의했기 때문에 빈 생성자를 따로 정의해 줘야 한다.
	}

	Student(String name, int age, int number) {
		this.name = name;
		this.age = age;
		this.number = number;
	}
    

}

위에 코드를 복사한 것입니다. Student 생성자에서 매개변수와 멤버변수의 이름과 타입이 같다는 걸 알수있습니다. 이럴때 this를 사용합니다.

예제)


this()

this()는 생성자입니다. this()생성자는 자기 자신의 클래스에서 다른 생성자를 호출할 때 사용합니다. this() 생성자를 사용하는 이유는 코드의 간결성(중복 코드 제거)을 위해서입니다.

주의!:this와 this()는 완전히 다른 의미를 가집니다.

예제)

class Students {

	String name;
	int age;
	String gender;

	// 여러 개 생성자 정의
	public Students() { // 빈 생성자
	}

	public Students(String name) {
		this(name, 10, "Man");
	}

	public Students(String name, int age) {
		this(name, age, "woman");
	}

	public Students(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;
	}

}

위에 코드를 보면 this() 생성자를 이용해 이미 초기화된 변수를 다른 생성자에서 또 초기화 하지 않고 따로 초기화해야될 부분만 초기화 하기 떄문에 더 효율적인 코드라는 것을 알 수 있습니다.

생성자(Constructor) 오버로딩

생성자(Constructor) 오버로딩란 여러개의 생성자를 정의한 것을 의미합니다.

먼저 생성자 오버로딩에 정확한 사용방법을 보기 전에 잘못된 사용방법 부터 확인해 보겠습니다.

// 잘못된 생성자 오버로딩 
class Students {

	String name;
	int age;
	String gender;

	// 여러 개 생성자 정의
	public Students() { // 빈 생성자
	}

	public Students(String name) {
		this.name = name;
	}

	public Students(int age) {
		this.age = age;
	}

	public Students(String gender) {
		this.gender = gender;
	}

}

public class StudentMain {

	public static void main(String[] args) {

		Students s1 = new Students();
		System.out.println("이름: " + s1.name + " 나이: " + s1.age + " 성별: " + s1.gender);

		Students s2 = new Students("홍길동");
		System.out.println("이름: " + s2.name + " 나이: " + s2.age + " 성별: " + s2.gender);

		Students s3 = new Students(25);
		System.out.println("이름: " + s3.name + " 나이: " + s3.age + " 성별: " + s3.gender);

		Students s4 = new Students("Man");
		System.out.println("이름: " + s4.name + " 나이: " + s4.age + " 성별: " + s4.gender);

	}

}

출력 결과:

이름: null 나이: 0 성별: null
이름: 홍길동 나이: 0 성별: null
이름: null 나이: 25 성별: null
이름: Man 나이: 0 성별: null

위에 코드에 생성자를 정의한 코드를 보시면 여러개의 생성자가 정의되 있고 서로 다른 이름에 객체가 선언되어 있습니다.제가 매서드 오버로딩편에서 설명한 적이 있지만 컴퓨터가 메서드를 판단하는 조건은
1. 메서드의 이름
2. 매개변수 타입
3. 매개변수 갯수
이렇게 세 가지를 보고 이 메서드가 같은지 다른지를 판단합니다.
하지만 위에 코드를 보면 name과 gender에 타입이 같고 매개변수의 갯수도 같습니다. 또 한 생성자에 이름도 같습니다. 그렇기 때문에 컴퓨터는 하나의 생성자를 판단하기 때문에 name 매개변수가 있는 생성자만 호출하게 됩니다.(결과값을 확인해 보시면 알 수 있습니다.)

메서드 오버로딩을 이해 못하셨다면 아래 링크 참고해 주세요!
https://velog.io/@sunnamgung8/%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9-Method-Overoading

// 정확한 생성자 오버로딩(this() 생성자 사용)
class Students {

	String name;
	int age;
	String gender;

	// 여러 개 생성자 정의
	public Students() { // 빈 생성자
	}

	public Students(String name) {
		this(name, 10, "Man");
	}

	public Students(String name, int age) {
		this(name, age, "woman");
	}

	public Students(String name, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;
	}

}

public class StudentMain {

	public static void main(String[] args) {

		Students s1 = new Students();
		System.out.println("이름: " + s1.name + " 나이: " + s1.age + " 성별: " + s1.gender);

		Students s2 = new Students("홍길동");
		System.out.println("이름: " + s2.name + " 나이: " + s2.age + " 성별: " + s2.gender);

		Students s3 = new Students("김길동", 25);
		System.out.println("이름: " + s3.name + " 나이: " + s3.age + " 성별: " + s3.gender);

		Students s4 = new Students("이길동", 30, "Woman");
		System.out.println("이름: " + s4.name + " 나이: " + s4.age + " 성별: " + s4.gender);

	}

}


출력 결과:

이름: null 나이: 0 성별: null
이름: 홍길동 나이: 10 성별: Man
이름: 김길동 나이: 25 성별: woman
이름: 이길동 나이: 30 성별: Woman

생성자 오버로딩을 할 때는 매개변수의 타입과 갯수가 달라야합니다.

접근 제한자

접근제한자란 클래스, 변수, 메서드 등에 사용되면 어떤 범위까지 접근할 것인지 지정하는 예약어입니다.

  1. public: 모든 영역에 접근이 가능한 접근 제한자 입니다.
    다른 패키지에서도 접근이 가능합니다. (자바 파일 한 개당 public 클래스는 하나만 정의할 수 있고 파일명과 클래스명이 같아야 합니다.)

  2. default: 해당 단위 앞에서 제한자가 지정되 있지 않은 경우입니다.
    이 경우 기본적으로 같은 패키지 내에서만 접근이 가능합니다.

  3. private: 해당 클래스 내에서만 접근이 가능한 접근 제한자이다.
    보통 getter/setter 메서드를 사용해 값을 초기화 하고 같을 리턴하는 작업을합니다.

  4. protected: 같은 패키지내에서 접근이 허용되고 다른패키지에 경우 자식 클래스에서는 접근이 가능합니다. (많이 사용하지 않습니다.)

예시)

자주 사용하는 접근제한자 사용 예시)

public class Students {

	private String name;
	private int age;
	private String gender;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

}

보통 클래스 안에서의 멤버변수는 private로 많이 사용합니다. 그 이유는 변수가 쉽게 값이 바뀌면 안되기 때문에 값이 쉽게 바뀌지 못하게 private로 많이 사용합니다.

이상으로 생성자,this,접근제한자에 대해서 알아봤습니다. 오늘은 조금 많은 주제로 다뤄봤는데 중요한 부분이기 때문에 두 세번 복습해주시기 바랍니다! 잘못된 부분과 부족한 부분이 있다면 피드백 감사하겠습니다!!!

profile
더 좋은 개발자가 되기위한 과정

0개의 댓글