티스토리 뷰

development/Java

[Java] 생성자 Constructor

Happyoon ~ 2021. 11. 2. 13:53
728x90
반응형

오늘은 Constructor, 즉, 생성자에 대해 알아보려 한다.

생성자는 new로 객체가 생성될 때 호출되는데, 반드시 클래스명과 동일해야하고 return type은 없어야 한다.
생성자를 정의하지 않아도 되는데, 그러면 매개변수를 가지지 않고, 사용자 정의 기능을 수행하지 않는 default 생성자가 알아서 사용된다.
생성자는 여러 개 정의할 수 있는데, 만약 생성자를 사용자가 하나 이상 새로 만들고 싶을 경우, default 생성자도 사용하고 싶다면 default 생성자도 꼭! 적어주어야 한다.

[생성자]

1. 클래스명과 동일하다.
2. 메소드 모양과 유사하지만 리턴 type이 없다.
3. 객체를 생성할 때(new할 때) 호출된다.
4. 객체를 생성하는 시점에 무언가 준비 작업을 할 때 유용하다.
5. 생성자를 명시적으로 정의하지 않아도 기본 생성자는 있다고 간주한다.


예제를 통해 자세히 살펴보자.

1-1) Engine.java - 클래스명이 Engine인, 비어있는 클래스

package test.mypac;

public class Engine {

}

1-2) Car.java - 두가지 생성자와 drive() 메소드를 가지는 Car 클래스

package test.mypac;

public class Car {
	//필드 정의하기
	public Engine engine;
	
	//생성자는 반드시 클래스명과 동일하고 return type은 없어야 한다.
	//객체를 new(생성)할 때 호출되는 생성자(정의해도 되고 안해도 됨)
	public Car() {
		System.out.println("Car() 생성자 호출됨");
		
	}
	
	//Engine 객체를 인자로 전달받는 생성자(생성자는 여러 개 정의할 수 있다)
	public Car(Engine engine) {
		//지역변수에 담긴 값을 필드에 저장하기 
		this.engine = engine;
	}
	
	//달리는 메소드
	public void drive() {
		if(this.engine == null) {
			System.out.println("Engine이 업어서 달릴 수가 없어요!");
			return;//메소드를 여기서 끝내기
			
		}
		System.out.println("신나게 달려요~");
	}

}


생성자 하나는 매개변수를 가지지 않고 특정 문자열을 콘솔창에 출력해주고, 다른 하나는 Engine 형태의 engine을 매개변수로 가지고 생성된 Car 객체의 engine 필드값에, 전달받은 engine을 대입해준다.

drive() 메소드는 해당 Car 객체의 engine 필드가 null이 아닐 경우 "신나게 달려요~"를, null일 경우 "Engine이 없어서 달릴 수가 없어요!"를 콘솔창에 출력하는 메소드이다.

이제, 이 클래스들을 활용한 모습을 살펴보자.


MainClass01.java - Car 객체의 drive()메소드를 호출했을 때 "신나게 달려요~"가 출력되도록 코딩하기


우선, Car()객체를 생성하고 변수에 넣어주자.

Car c1 = new Car();

"신나게 달려요~"가 출력되려면, c1의 engine필드가 null이면 안된다.
현재 객체만 생성하고, engine에 따로 값을 넣어주지 않았으니, engine에는 default인 null이 들어있다.
따라서, c1.engine에 Engine객체의 참조값을 넣어주면 null이 되지 않아 "신나게 달려요!"가 출력될 것을 예측할 수 있다.

c1.engine = new Engine();
c1.drive();

new Engine()을 해주었으니, 첫번째 생성자가 실행되어, "Car() 생성자 호출됨"이 출력된다.



전체코드
MainClass01.java

package test.main;

import test.mypac.Car;
import test.mypac.Engine;

public class MainClass01 {
	public static void main(String[] args) {
		
		/*
		 * Car 클래스를 수정하지 않고 
		 * Car 객체의 .drive() 메소드를 호출했을 때 정상적으로 달릴 수 있게 만들 수 있을까?
		 */
		Car c1 = new Car();
		//Engine 객체를 생성해서 필드에 넣어주기
		c1.engine = new Engine();
		c1.drive();
		
	}

}


1-2) MainClass02.java - 두 개의 생성자 확인해보기

package test.main;

import test.mypac.Car;
import test.mypac.Engine;

public class MainClass02 {
	public static void main(String[] args) {
		Car c1 = new Car();
		
		Car c2 = new Car(new Engine());
		
		c1.drive();
		c2.drive();
	}

}


new Car()을 할 경우, 1-1과 같은 이유로 "Car() 생성자 호출됨"이 출력된다.
c1.drive()를 호출할 경우, c1 객체의 engine 필드를 따로 설정하지 않았기 때문에 null이 들어있으므로 "Engine이 없어서 달릴 수가 없어요!"가 출력된다.

new Car(new Engine())을 할 경우, 두번째 생성자가 실행되어 this.engine = engine문이 실행되기 때문에,
c2.engine에 new Engine(), 즉, 새로 생성된 Engine 객체의 참조값이 들어간다.
따라서, c2.drive()를 호출할 경우, c2.engine은 null이 아니므로 "신나게 달려요~"가 출력된다.


2) Member.java - 두가지 형식의 생성자를 가지고 showInfo()를 메소드로 갖는 Member 클래스

package test.mypac;
/*
 * [생성자]
 * 
 * 1. 클래스명과 동일하다.
 * 2. 메소드 모양과 유사하지만 리턴 type이 없다.
 * 3. 객체를 생성할 때(new할 때) 호출된다.
 * 4. 객체를 생성하는 시점에 무언가 준비 작업을 할 때 유용하다.
 * 5. 생성자를 명시적으로 정의하지 않아도 기본 생성자는 있다고 간주한다.
 */
public class Member {
	//필드 정의하기
	public int num;
	public String name;
	public String addr;
	
	//default 생성자
	public Member() {
		
	}
	/*
	 * 생성자의 인자로 int, String, String type을 전달받는 생성자
	 * default 생성자 이외의 생성자를 하나라도 정의하면 
	 * default 생성자는 명시적으로 정의하지 않으면 없다고 간주된다.
	 * 즉, 기본 생성자 이외에 하나 더 생성자를 만들면, 기본 생성자도 꼭 써줘야한다.(기본 생성자가 필요하다면)
	 */
	public Member(int num, String name, String addr) {
		//인자로 전달받은 지역변수명이 num대신 _num이라면,
		//num = _num;//전달받은 _num을 num필드에 대입 => this.num 에서 this 생략 가능(변수명이 서로 달라서)
		//인자로 전달받은 지역변수명과 필드명이 같다면,
		this.num = num;//this필요
		this.name = name;
		this.addr = addr;
		
	}
	
	public void showInfo() {
		System.out.println("번호: "+this.num+" 이름: "+this.name+" 주소: "+addr);
	}
}

생성자로 default 생성자와 num, name, addr을 인자로 갖는 생성자를 정의했다.
두번째 생성자는, Member 클래스 객체의 num, name, addr 필드에 전달받은 인자를 각각 대입한다.
this를 활용했는데, 만약, 전달받는 변수명과 필드명과 다르다면, 즉, int _num 등의 형태로 전달받는다면, this를 생략할 수 있다. 따라서 다음과 같이 작성 가능하다.

num = _num;


showInfo() 메소드는 해당 객체의 필드들을 문자열 형태로 출력하는 기능을 한다.


MainClass07.java - 직접참조와 간접참조(?)

package test.main;

import test.mypac.Member;

public class MainClass07 {
	public static void main(String[] args) {
		Member mem1 = new Member();
		mem1.showInfo();
		System.out.println();
		
		Member mem2 = new Member();
		//Member 객체의 필드를 직접 참조해서 값 대입하기
		//(자바는 직접 참조를 별로 안 좋아함)
		mem2.num = 1;
		mem2.name="김구라";
		mem2.addr = "노량진";
		mem2.showInfo();
		
		System.out.println();
		Member mem3 = new Member(2, "해골", "행신동");
		mem3.showInfo();
	}
}

Member 객체 2개를 생성하여 각각 mem1과 mem2에 참조값을 넣어준다.
mem1.showInfo()를 호출하면, 값이 모두 null 혹은 0이므로 다음과 같이 출력된다.

번호: 0 이름: null 주소: null


mem2 객체의 필드에 직접 참조로 (.을 찍어서) 값을 대입해보자.
mem2.showInfo()를 하면 다음과 같이 출력되어, 값이 잘 들어갔음을 확인할 수 있다.


번호: 1 이름: 김구라 주소: 노량진


mem3에는 객체 생성을 함과 동시에 생성자를 활용하여 값을 넣어준다.
마찬가지로, mem2.showInfo() 메소드가 호출되면 다음과 같이 출력되어 값이 잘 들어간 모습을 확인할 수 있다.

번호: 2 이름: 해골 주소: 행신동

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함