생성자 (Constructor) 란?
인스턴스 생성 시 호출되는 인스턴스 변수 초기화 '메서드'이다.
따라서 일반적인 메서드처럼 클래스 안에서 선언된다.
생성자가 인스턴스를 생성하는 것이 아니다!
연산자 new가 인스턴스를 생성한다. new 키워드를 통해 인스턴스를 생성할 때 호출되는 것이 생성자(Constructor) 메서드이고 인스턴스 변수들을 초기화시키는 특수한 목적의 메서드라고 할 수 있다.
구조도 비슷하고 클래스 내에서 선언하는 것도 같지만 생성자는 메서드와는 달리 클래스 명과 동일한 이름을 가져야 하고 '리턴 값이 없다'라는 차이점이 있다.
**생성자도 메서드 처럼 오버 로딩이 가능하기 때문에 하나의 클래스 안에 여러 개의 생성자가 존재할 수 있다.
**매개변수는 있을 수도 있고 없을 수도 있다.
생성자의 조건:
1. 생성자의 이름은 클래스의 이름과 같아야 한다.
2. 생성자는 return 값이 없다. (그렇다고 해서 앞에 void를 붙이지는 않는다)
//모든 생성자가 리턴 값이 없으므로 void를 생략 가능하다.
생성자는 아래와 같이 정의할 수 있다.
**매개변수가 있을 경우**
클래스명 (매개변수) //생성자 기본 구조
{
...body...
}
**매개변수가 없는 경우**
클래스명 ()
{
...body...
}
클래스가 인스턴스를 생성하는 과정을 통해서 본다면 아래와 같다.
iPhone i = new iPhone();
1. 연산자 new에 의해서 메모리(Heap)에 iPhone클래스의 인스턴스가 생성
2. 생성자 iPhone()이 호출되어 실행 //(필드 변수값 초기화)
3. 연산자 new의 결과 -> 생성된 iPhone인스턴스의 주소가 반환되어 참조변수 i 에 저장
기본 생성자 (Default constructor)
모든 클래스에는 반드시 하나 이상의 생성자가 정의되어있어야 한다.
클래스 내에 생성자가 없다면 컴파일 단계에서 컴파일러(javac)가 자동적으로 기본 생성자를 추가해준다. 기본 생성자는 매개변수를 갖지 않으며 그 안에 아무런 내용도 존재하지 않는다.
클래스 이름 ( ) { } //기본 생성자
iPhone ( ) { } //iPhone 클래스의 기본 생성자
만약 다른 생성자가 이미 추가되어 있는 경우에는 이미 존재하는 생성자를 먼저 사용하게 된다.
여태껏 인스턴스를 만들 당시 생성자를 생성하지 않았어도 기본 생성자를 컴파일러가 만들어주었기 때문에 정상적으로 진행이 가능했던 것이다. 따라서 특별하게 인스턴스 초기화 작업이 필요하지 않다면 생성자를 따로 정의하지 않고 기본 생성자를 이용하는 것도 좋다.
매개변수가 없는 생성자와 기본 생성자의 차이:
매개변수가 없어도 뭔가의 기능을 함 / 기본 생성자는 아무것도 안 함
매개변수를 갖는 생성자
생성자에 매개변수가 존재한다면 일반 메서드처럼 파라미터 값을 통해 인스턴스를 초기화할 수 있다.
인스턴스마다 다른 값으로 초기화를 해야 하는 경우에 매우 유용하게 사용할 수 있다.
**인스턴스를 매번 생성하고 값을 변경하는 경우**
iPhone i = new iPhone();
i.color = "Dark_Grey";
i.model = "XS";
i.damaged = false;
위의 코드는 여러 인스턴스를 만들고 각각의 인스턴스에 값을 하나씩 변경하는 경우이고,
아래의 코드는 생성자의 파라미터를 이용해 인스턴스를 생성함과 동시에 값을 초기화한다.
iPhone i = new iPhone("Dark_Grey", "XS", false);
생성자의 매개변수를 통해 한번에 초기화하는 것이 훨씬 직관적이고 편한 것을 알 수 있다. 당연하겠지만 매개변수의 타입과 개수가 일치해야 한다.
this( ), this(매개변수)
메서드를 정리할 때 적어놓았듯이, 같은 클래스 안에서 메서드끼리 서로 호출이 가능했다.
생성자도 메서드이기 때문에 같은 클래스 내에서 서로 호출이 가능하다.
예를 들어, 클래스 iPhone에서 iPhone 클래스의 생성자를 호출할 땐 iPhone( ) 이 아니라 this ( )를 써야 한다. 결과는 iPhone( ) 생성자를 호출하는 것과 같다.
사용조건은 다음과 같다.
1. 생성자 내부에서만 사용할 수 있다.
2. 생성자의 첫 줄에 위치해야 한다.
첫 줄에서 호출해야 하는 이유는 처음 생성자 안에서 값을 초기화하는 도중 다른 생성자를 호출하게 되면, 호출된 다른 생성자도 자신의 안에 있는 멤버 변수들의 값을 초기화할 것이다. 이렇게 되면 처음 생성자가 하던 초기화 작업이 무의미 해지기 때문이다.
아래의 연습 코드를 보면 클래스 Test는 2개의 생성자를 갖는다.
하나는 기본 생성자 (매개변수 X) 다른 하나는 String타입의 매개변수를 파라미터로 받는 생성자이다. Test클래스를 바탕으로 test 1과 test2라는 인스턴스가 만들어진다.
첫 번째 test1 인스턴스가 만들어지면서 첫 번째 생성자를 호출하게 되고 "test 1 is empty"이라는 문장이 출력된다.
두 번째 test2 인스턴트가 만들어지면서 "This is Test!"라는 String 타입의 값의 파라미터로 받게 되므로 String을 매개변수를 갖는 생성자를 찾아 호출을 하게 되고 먼저 this( )를 수행하게 되는데 this ( )는 같은 클래스 안에 있는 Test( )과 마찬 가지이므로 첫 번째 기본 생성자 안에 있는 "text1 is empty"를 출력한다. 그다음 아랫줄의 "Test 2"를 출력한다
public class doodle {
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test("This is Test!");
}
}
class Test
{
public Test()
{
System.out.println("test1 is empty");
}
public Test(String a)
{
this(); //같은 Test 클래스 안에 있는 Test()라는 생성자를 this()로 호출한다.
System.out.println("Test2");
}
}
test1 is empty
test1 is empty
Test2
아래의 코드로 this( 매개변수 ) 가 어떻게 작동하는지 확인 가능하다.
public class doodle {
public static void main(String[] args) {
iPhone i = new iPhone("blue", "xs", false); //클래스 내 생성자의 파라미터로 들어감
iPhone j = new iPhone("red");
System.out.println("\n***MY IPHONE***");
System.out.println("colour: " + i.colour + "\nmodel: " + i.model + "\ndamaged?: " + i.damaged);
System.out.println("colour: " + j.colour + "\nmodel: " + j.model + "\ndamaged?: " + j.damaged);
}
}
class iPhone
{ //클래스 영역
//필드 영역
String colour; //(인스턴스 변수)
String model; //(인스턴스 변수)
boolean damaged; //(인스턴스 변수)
iPhone(String colour, String model, boolean damaged) //생성자
{
this.colour = colour; //클래스명인 iPhone 대신 this를 쓴다
this.model = model; //생성자 안의 this.변수명 은 필드의 변수를 가르킨다!
this.damaged = damaged;
}
iPhone(String colour)
{
this(colour, "X", true);
//main 에서 iPhone j = new iPhone("red"); 라고 새 인스턴스를 만들었다.
// 지금 이 범위에 있는 생성자 안에서 this(colour, "X", true);를 썻는데 각각 아래와 같다.
// this() 안에 3개의 매개변수를 넣었다
-> 즉 3개의 매개변수를 갖는 생성자를 현재 클래스 내에서 호출한다
// String colour 하나만을 매개변수로 갖는 생성자의 매개변수 colour를 그대로 재사용
// X: 3개의 매개변수를 갖는 생성자의 2번째 매개변수 값 으로써 문자 "X"를 넣는다.
// true: 3개의 매개변수를 갖는 생성자의 3번째 매개변수 값 으로써 boolean 타입인 true를 넣는다.
}
}
***MY IPHONE***
colour: blue
model: xs
damaged?: false
***YOUR IPHONE***
colour: red
model: X
damaged?: true
this
this는 참조 변수로써 작동을 하며 인스턴스 자신을 가리키는 '참조 변수'이다. 따라서 인스턴스의 주소 값을 가리킨다.
주로 인스턴스 변수명과 생성자의 매개변수명을 구별할 때 쓴다.
public class doodle {
public static void main(String[] args) {
iPhone i = new iPhone("blue", "xs", false); //클래스 내 생성자의 파라미터로 들어감
System.out.println("\n***MY IPHONE***");
System.out.println("colour: " + i.colour + "\nmodel: " + i.model + "\ndamaged?: " + i.damaged);
}
}
class iPhone
{ //클래스 영역
//필드 영역
String colour; //(인스턴스 변수)
String model; //(인스턴스 변수)
boolean damaged; //(인스턴스 변수)
iPhone(String colour, String model, boolean damaged) //생성자
{
this.colour = colour; //클래스명인 iPhone 대신 this를 쓴다
this.model = model; //생성자 안의 this.변수명 은 필드의 변수를 가르킨다!
this.damaged = damaged;
}
}
---------------------------------------------------------------------
---------------------------------------------------------------------
**this를 사용하지 않는 경우**
class iPhone
{ //클래스 영역
//필드 영역
String colour; //(인스턴스 변수)
String model; //(인스턴스 변수)
boolean damaged; //(인스턴스 변수)
iPhone(String a, String b, boolean c) //생성자
{
colour = a;
model = b;
damaged = c;
}
}
위의 코드를 보면 iPhone 클래스 안에 인스턴스 변수가 선언되어있고 그 밑에 3가지의 매개 변수를 받는 생성자가 정의되어있다. 그리고 main 안에 iPhone클래스의 인스턴스를 만들고 생성자의 파라미터 값을 넣었다.
this.colour = colour를 보면 생성자의 파라미터로 들어온 colour가 필드에 선언되어있는 colour 변수(this.colour가 가리키는)에 값을 대입한다.
여기서 this의 필요성이 나오는데 만약에 this가 없다면 이름만으로 colour가 뭘 말하는 건지 매우 헷갈릴 것이다.
this를 쓰지 않고 점선 아래의 코드처럼 할 수도 있지만 생성자의 매개변수를 통해 인스턴스 변수들의 초기값을 받는 경우가 많기 때문에 차라리 this를 쓰고 변수 이름을 같게 쓰는 것이 구별하기가 더 편할 것 같다.
'programming > JAVA' 카테고리의 다른 글
Java - 캡슐화 (Encapsulation) (0) | 2022.05.12 |
---|---|
Java - 상속(Inheritance) (0) | 2022.05.12 |
Java - 메서드 (0) | 2022.05.10 |
Java - 필드와 변수 (0) | 2022.05.10 |
Java - 클래스와 객체 (0) | 2022.05.10 |