15. 생성자, 초기화블럭, this

Isaiah IM·2023년 7월 10일
0

java basic

목록 보기
17/38
post-thumbnail

1. 생성자(Constructor)

1.1 생성자란?

생성자란 인스턴스가 생성될때 자동으로 실행되는 코드이다.

생성자는 일반적으로 생성될때 인스턴스 내에 있는 변수 초기화 등의 인스턴스 생성시 실행되야할 작업을 작성할때 주로 사용된다.

생성자 역시 메소드처럼 클래스 내에 선언되며, 반환값은 없으며, 클래스 이름과 동일한 이름으로 작성할 수 있다.

public class Tv {
	
    Tv(){// 생성자
    	// 동작 코드
    }
    
    Tv(int num){// 생성자
    	// 동작 코드
    }
} 

1.2 기본 생성자

원래는 모든 클래스는 기본적으로 생성자가 하나 이상 있어야 한다. 그러나, 클래스 내에 생성자가 없을 경우 jvm에서 기본 생성자라는 것을 추가해서 컴파일을 한다. 이때, 기본생성자는 클래스 이름과 동일한 생성자이며, 아무런 동작을 하지 않는 생성자를 의미한다.

public class Tv {
	
    Tv(){// 기본 생성자(아무런 추가동작 X)
    }
    
} 

만약 클래스 내에 생성자가 있다면 jvm에서는 기본생성자를 만들지 않고 컴파일 한다.

1.3 매개변수가 있는 생성자

생성자도 메소드처럼 오버로딩이 가능해 매개변수를 입력해서 초기화를 할 수 있다. 만약 인스턴스마다 각각 다른 값으로 변수를 초기화 해야 할 경우 생성자에 매개변수를 입력하는 것이 유용하다.

tv클래스

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(double s, double sc, int p){// 매개변수가 있는 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      size=s;
      scale=sc;
      price=p;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

main 클래스

public class ClassStudy {
	public static void main(String[] args) {
		
		Tv tv1 = new Tv();// 매개변수 없는 생성자
		Tv tv2 = new Tv(50, 16.9, 80);// 매개변수 있는 생성자
	}
}

output

Tv 인스턴스 초기화1
Tv 인스턴스 초기화2

1.4 생성자를 이용한 인스턴스 복사

생성자를 이용해 인스턴스를 복사할 수 있다.

현재 사용중인 인스턴스와 상태가 동일한 인스턴스가 필요할 경우 인스턴스 변수를 일일히 복사하는 방식이 아닌, 생성자를 사용하면 보다 쉽게 복사할 수 있다.

tv클래스

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
	    cnt++;// tv수량 증가
	    serialNumber=cnt;// 시리얼 번호 입력
	    System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(Tv original){// 생성자를 이용해 인스턴스 복사
    	this.size=original.size;
    	this.scale=original.scale;
    	this.price=original.price;
    }
    
    
}

main클래스

public class ClassStudy {
	public static void main(String[] args) {
		
		Tv tv1 = new Tv(50, 16.9, 80);
		Tv tv_cpy= new Tv(tv1);// tv1과 같은 상태의 인스턴스(변수가 동일)
		
	}
}

우리가 개발을 하면서 클래스를 직접 설계하는 경우도 있지만, 미리 설계된 클래스를 사용하는 경우도 상당히 많다. 이전에 사용했던 Scanner클래스만 하더라도 우리가 직접 Scanner클래스를 설계하지 않고 미리 만들어진 클래스를 이용했다. 이러한 경우 클래스 내의 인스턴스 변수의 상태에 대해 알기 힘든 경우가 많다. 이럴때 같은 기능을 하는 인스턴스가 여러개 필요할 경우 인스턴스를 복사하면 쉽게 개발을 할 수 있다.
또한, java API의 많은 클래스들이 생성자를 이용해 인스턴스를 복사할 수 있도록 설계가 됬다.


2. this

this키워드는 인스턴스 자기 자신을 가리키는 키워드다.

this키워드는 인스턴스 자기 자신을 가리키는 키워드로, this.변수; 형태와 this(); 형태로 구분된다.

2.1 this.변수

this.변수형태는 매소드 내에서 인스턴스 변수를 가리킬때 사용한다.
주로, 메소드에서 매개변수 이름과 인스턴스 변수의 이름이 같을때 주로 사용된다.

아래와 같은 코드가 있다고 가정하자.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    void setTvInfo(double size, double scale, int price){
    ...// 코드 입력
    }
}

setTvInfo메소드와 같이 메소드의 매개변수와 인스턴스 변수의 이름이 같을때 메소드 변수와 인스턴스 변수를 구분하고자 할때 아래 코드와 같이 this.변수를 사용해 구분할 수 있다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    void setTvInfo(double size, double scale, int price){
    this.size=size;
    this.scale=scale;
    this.price=price;
    }
}

2.2 this()

this()는 생성자 내에서 다른 생성자를 호출할때 사용한다.

생성자 내에서 다른 생성자를 호출하는 것이 효율적인 경우가 있다.
예를 들어보자.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(double s, double sc, int p){// 매개변수가 있는 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      size=s;
      scale=sc;
      price=p;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

위 코드는 앞서 생성자에서 알아봤던 코드이다.
위 코드에서 매개변수가 있는 생성자 부분에서 tv수량 증가, 시리얼 번호 입력 부분이 매개변수가 없는 생성자와 중복되는 경우가 있다. 이때, 매개변수가 없는 생성자를 this()를 통해 불러오면 아래와 같이 코드가 보다 간결해진다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(double s, double sc, int p){// 매개변수가 있는 생성자
      this();// 생성자 호출
      size=s;
      scale=sc;
      price=p;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

추가적으로, 앞에서 배운 this.변수를 사용해 매개변수를 수정해주면 더 가독성이 좋아질 수 있다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(double size, double scale, int price){// 매개변수가 있는 생성자
      this();// 생성자 호출
      this.size=size;
      this.scale=scale;
      this.price=price;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

this()의 경우 역시 매개변수를 입력할 수 있으며, this(매개변수)의 경우 클래스_이름(매개변수)타입의 생성자를 불러오게 된다.


3. 초기화 블록(Initialization Block)

클래스와 인스턴스를 초기화 할 수 있는 또 다른 방법으로는 초기화 블록(initialization block)이 있다. 초기화 블록에서는 반복문, 조건문, 예외처리 등을 할 수 있기 때문에 복잡한 초기화 과정이 있는 경우에 주로 사용한다.
초기화 블록은 클래스 초기화 블록인스턴스 초기화 블록으로 나뉜다.

3.1 클래스 초기화 블록

클래스 초기화 블록은 클래스 변수의 복잡한 초기화를 할 때 사용된다.

클래스 초기화 블록은 클래스 변수를 초기화 한다. 물론, 클래스 변수를 static data=3;과 같이 단순한 초기화의 경우 초기화 블록이 없어도 되지만, 연산이 복잡해질 경우 클래스 초기화 블록을 사용해서 클래스 변수를 초기화 할 수 있다.

클래스 초기화 블록은 아래와 같이 클래스 내에 static키워드를 붙이고 중괄호를 붙여 사용할 수 있다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    static {// 클래스 초기화 블록
    	
    }
    
   
    /*******메소드*******/
    
    void setTvInfo(double size, double scale, int price){
        this.size=size;
        this.scale=scale;
        this.price=price;
        }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

클래스 초기화 블록은 클래스가 메모리에 처음 로딩될 때 한번만 수행된다.

3.2 인스턴스 초기화 블록

인스턴스 초기화 블록은 인스턴스 변수의 복잡한 초기화를 할 때 사용된다.

인스턴스 초기화 블록은 아래와 같이 클래스 내에 중괄호를 붙여 사용할 수 있다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    {// 인스턴스 초기화 블록
    	
    }
    
   
    /*******메소드*******/
    
    void setTvInfo(double size, double scale, int price){
        this.size=size;
        this.scale=scale;
        this.price=price;
        }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

인스턴스 초기화 블록은 생성자와 같이 인스턴스가 생성될 때 마다 수행된다.

일반적으로 인스턴스 변수의 초기화는 생성자를 사용하며, 인스턴스 초기화 블록은 모든 생성자에서 공통적으로 수행하는 경우에 사용한다.

예를 들어 앞에서 작성했던 아래와 같이 중복된 부분을 this()로 호출한 부분을 인스턴스 초기화 블록을 사용해 조금 더 가독성 높은 코드로 바꿀 수 있다.

public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    Tv(){// 생성자
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(double size, double scale, int price){// 매개변수가 있는 생성자
      this();// 생성자 호출
      this.size=size;
      this.scale=scale;
      this.price=price;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}
public class Tv {
	double size;// tv 크기
    double scale;// tv 비율
    int price;// tv 가격
    int serialNumber;// 시리얼 번호
    static int cnt=0;// 수량
    
    
    
    {// 인스턴스 초기화 블록
      cnt++;// tv수량 증가
      serialNumber=cnt;// 시리얼 번호 입력
      System.out.println("Tv 인스턴스 초기화1");
    }
    
    Tv(){}//  생성자
    
    Tv(double size, double scale, int price){// 매개변수가 있는 생성자
      this.size=size;
      this.scale=scale;
      this.price=price;
      System.out.println("Tv 인스턴스 초기화2");
    }
    
    public void discount(){// tv 할인 메소드
    //tv 할인 코드
    }
    
    public void sale(){// tv 판매 메소드
    // tv 판매 코드
    }
}

이렇게 매개변수 초기회 블록을 이용하면 매개변수가 있는 생성자를 분석할때 Tv()라는 매개변수가 없는 생성자를 고려하지 않아도 되기 때문에 코드 분석 시간이 절약될 수 있다.

또한, 초기화 블럭이 생성자보다 먼저 초기화가 된다.

profile
나는 생각한다. 고로 나는 코딩한다.

0개의 댓글