해당 게시물은 자바의 정석을 정리한 내용 입니다.
5.1. 생성자(constructor)란?
생성자란?
- 생성자(constructor)는 인스턴스가 생성될 때 마다 호출되는 ‘인스턴스 초기화 메서드’이다.
* 인스턴스 초기화는 인스턴스 변수에 적절한 값을 저장하는 것이다.
- 인스턴스 변수의 초기화 또는 인스턴스 생성 시 수행할 작업에 사용된다.
- 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다.
생성자의 조건
① 생성자의 이름은 클래스의 이름과 같아야 한다.
② 생성자는 리턴 값이 없다. (하지만 void를 쓰지 않는다.)
클래스이름 (타입 변수명, 타입 변수명 ...){
// 인스턴스 생성 시 수행 될 코드
// 주로 인스턴스 변수의 초기화 코드를 적는다.
}
* 연산자 new가 인스턴스를 생성하는 것이지 생성자가 인스턴스를 생성하는 것은 아니다.
Card 클래스의 인스턴스를 생성하는 과정
Card 클래스의 인스턴스를 생성하는 코드를 예로 들어, 수행되는 과정을 단계 별로 나누어 보면 다음과 같다.
Card c = new Card();
① 연산자 new에 의해서 메모리(heap)에 Card 클래스의 인스턴스가 생성된다.
② 생성자 Card()가 호출되어 수행된다.
③ 연산자 new의 결과로, 생성된 Card 인스턴스의 주소가 반환되어 참조변수 c에 저장된다.
5.2. 기본 생성자(default constructor)
- 기본 생성자는 매개변수가 없는 생성자이다.
클래스이름() { }
Card() { } // 컴파일러에 의해 추가된 Card 클래스의 기본 생성자. 매개변수도 없고 아무런 내용도 없다.
- 클래스에 생성자가 하나도 없으면 컴파일러가 기본 생성자를 추가한다.
(생성자가 하나라도 있으면 컴파일러는 기본 생성자를 추가하지 않는다.)
class Data1 {
int value;
}
class Data2 {
int value;
Data2(int x) { // 매개변수가 있는 생성자.
value = x;
}
}
class ConstructorTest {
public static void main(String[] args) {
Data1 d1 = new Data1();
Data2 d2 = new Data2(); // compile error발생
}
}
위의 예제를 컴파일 하면 에러 메시지가 나타난다.
에러 발생한 이유는 Data2에는 이미 생성자 Data2(int x)가 정의되어 있으므로 기본 생성자가 추가되지 않았기 때문이다.
5.3. 매개변수가 있는 생성자
- 생성자도 메서드처럼 매개변수를 선언하여 호출 시 값을 넘겨받아서 인스턴스의 초기화 작업에 사용할 수 있다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto(자동), manual(수동)
int door; // 문의 개수
Car() {} // 생성자
Car(String c, String g, int d) { // 생성자
color = c;
gearType = g;
door = d;
}
}
class CarTest {
public static void main(String[] args) {
Car c1 = new Car();
c1.color = "white";
c1.gearType = "auto";
c1.door = 4;
Car c2 = new Car("white", "auto", 4);
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
}
}
5.4. 생성자에서 다른 생성자 호출하기 - this()
- 생성자 this()는 같은 클래스의 다른 생성자를 호출할 때 사용한다.
- 다른 생성자 호출은 생성자의 첫 문장에서만 가능하다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto(자동), manual(수동)
int door; // 문의 개수
Car() {
this("white", "auto", 4);
}
Car(String color) {
this(color, "auto", 4); // 생성자에서 다른 생성자 호출할 때는 this() 사용
}
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
class CarTest2 {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("blue");
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
}
}
5.5. 참조변수 - this
- this는 인스턴스 자신을 가리키는 참조변수이다.
- this는 인스턴스의 주소를 저장하고 있으며 모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재한다.
- static 메서드(클래스 메서드)에서는 this를 사용할 수 없다.
( 왜냐하면 static 메서드는 인스턴스를 생성하지 않고도 호출 될 수 있으므로 static 메서드가 호출된 시점에
인스턴스가 존재하지 않을 수도 있기 때문이다.)
Car(String color, String gearType, int door){
this.color = color; // this.color, this.gearType, this.door는 인스턴스 변수이다.
this.gearType = gearType; // color, gearType, door는 생성자의 매개변수로 지역 변수이다.
this.door = door;
}
5.6. 생성자를 이용한 인스턴스의 복사
현재 사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 때 생성자를 이용할 수 있다.
두 인스턴스가 같은 상태를 갖는다는 것은 두 인스턴스의 모든 이스턴스 변수가 동일한 값을 갖고 있다는 것을 뜻한다.
생성자에서 참조변수를 매개변수로 받아서 인스턴스 변수들의 값을 복사하면 같은 상태를 갖는 독립적인 인스턴스가 하나 더 만들어진다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto(자동), manual(수동)
int door; // 문의 개수
Car() {
this("white", "auto", 4);
}
Car(Car c) { // 인스턴스의 복사를 위한 생성자.
this(c.color, c.gearType, c.door);
}
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
class CarTest3 {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car(c1); // c1의 복사본 c2를 생성한다.
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
c1.door=100; // c1의 인스턴스변수 door의 값을 변경한다.
System.out.println("c1.door=100; 수행 후");
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
}
}
6.1. 변수의 초기화
변수의 초기화란?
- 변수의 초기화란 변수를 선언하고 처음으로 값을 저장하는 것을 말한다.
- 멤버 변수(인스턴스 변수, 클래스 변수)와 배열은 각 타입의 기본값으로 자동 초기화되므로 초기화를 생략할 수 있다.
- 지역변수는 사용하기 전에 반드시 초기화를 해주어야한다.
변수의 초기화 예시
int i = 10;
int j = 10;
멤버 변수의 초기화 방법
① 명시적 초기화(explicit initialization)
② 생성자(constructor)
③ 초기화 블럭(initialization block)
- 인스턴스 초기화 블럭 : { }
- 클래스 초기화 블럭 : static { }
6.2. 명시적 초기화(explicit initialization)
명시적 초기화는 변수를 선언과 동시에 초기화하는 것을 말한다.
class Car{
int door = 4; // 기본형(primitive type) 변수의 초기화
Engine e = new Engine(); // 참조형(reference type) 변수의 초기화
}
6.3. 초기화 블럭(initialization block)
클래스 초기화 블럭은 클래스 변수의 복잡한 초기화에 사용되며 클래스가 메모리에 처음 로딩될 때 단 한번만 실행된다.
class StaticBlockTest
{
static int[] arr = new int[10];
static {
for(int i=0;i<arr.length;i++) {
// 1과 10사이의 임의의 값을 배열 arr에 저장한다.
arr[i] = (int)(Math.random()*10) + 1;
}
}
public static void main(String args[]) {
for(int i=0; i<arr.length;i++)
System.out.println("arr["+i+"] :" + arr[i]);
}
}
인스턴스 초기화 블럭은 인스턴스를 생성할 때 마다 수행되며 생성자 보다 인스턴스 초기화 블럭이 먼저 수행된다.
{
count++;
serialNo = count;
}
Car() {
color = "White";
gearType = "Auto";
}
Car(String color, String gearType){
this.color = color;
this.gearType = gearType;
}
명시적 초기화를 통해 배열 arr을 생성하고, 클래스 초기화 블럭을 이용해서 배열의 각 요소들을 random()들을 사용해서 임의의 값으로 채워넣었다.
6.4. 멤버변수의 초기화 시기와 순서
클래스 변수의 초기화 시점 : 클래스가 처음 로딩될 때 단 한번 초기화 된다.
인스턴스 변수의 초기화 시점 : 인스턴스가 생성될 떄 마다 각 인스턴스 별로 초기화가 이루어진다.
클래스 변수가 인스턴스 변수 보다 항상 먼저 생성되고 초기화 된다.
클래스 변수의 초기화 순서 : 기본 값 → 명시적 초기화 → 클래스 초기화 블럭
인스턴스 변수의 초기화 순서 : 기본 값 → 명시적 초기화 → 인스턴스 초기화 블럭 → 생성자
class Product {
static int count = 0; // 생성된 인스턴스의 수를 저장하기 위한 변수
int serialNo; // 인스턴스 고유의 번호
{
++count;
serialNo = count;
}
public Product() {} // 기본생성자, 생략가능
}
class ProductTest {
public static void main(String args[]) {
Product p1 = new Product();
Product p2 = new Product();
Product p3 = new Product();
System.out.println("p1의 제품번호(serial no)는 " + p1.serialNo);
System.out.println("p2의 제품번호(serial no)는 " + p2.serialNo);
System.out.println("p3의 제품번호(serial no)는 " + p3.serialNo);
System.out.println("생산된 제품의 수는 모두 "+Product.count+"개 입니다.");
}
}
Prodect 클래스의 인스턴스를 생성할 때 마다 인스턴스 블럭이 수행 되어, 클래스 변수 count의 값을 1 증가 시킨 다음,
그 값을 인스턴스 변수 serialNo에 저장한다.
만일 count를 인스턴스 변수로 선언 했다면, 인스턴스가 생성될 때마다 0으로 초기화 될 것이므로 모든 Product 인스턴스의
serialNo 값은 항상 1이 될 것이다.
'Java > 객체 지향 개념 ~' 카테고리의 다른 글
자바의 정석 (Chapter 7_3. 객체지향개념 2) (0) | 2020.08.03 |
---|---|
자바의 정석 (Chapter 7_2. 객체지향개념 2) (0) | 2020.08.02 |
자바의 정석 (Chapter 7_1. 객체지향개념 2) (0) | 2020.08.02 |
자바의 정석 (Chapter 6_2. 객체지향개념 1) (0) | 2020.07.31 |
자바의 정석 (Chapter 6_1. 객체지향개념 1) (0) | 2020.01.21 |
댓글