1. Constructor[생성자]

  1. 생성자란?

  2. 기본생성자?

    1. 모든 Class는 생성자가 반드시 존재하고, 하나 이상을 가질 수 있음

    2. Class내부에 생성자 선언을 생략했다면, Compiler(컴파일러)는 중괄호 {} 블록 내용이 비어있는 Default Constructor(기본 생성자)를 바이트 코드에 자동 추가시킴

      // 바이트코드 내부
      [public] Class() {}
      
    3. 클래스가 public class로 선언되면 기본 생성자에도 public이 붙지만, 클래스가 public없이 class로만 선언되면 기본 생성자에도 public이 붙지 않음!

      1. [예제]

        // 소스파일 => Test.java
        public class Test {}
        
        // 바이트 코드 파일 => Test.class
        public class Test {
        	public Test() { } // 자동으로 추가됨
          //       ↑
        	//  기본 생성자
        }
        
    4. 클래스에 생성자를 선언하지 않아도, new 연산자 뒤기본 생성자를 호출해서 Object(객체)를 생성 시킬 수 있음! ⇒ Test myTest = new Test(); // Test() : 기본 생성자임

    5. 클래스에 **명시적으로 선언한 생성자(Constructor)**가 한 개라도 존재하면, Compiler(컴파일러)는 기본 생성자를 추가하지 않으며, 생성자를 선언하는 이유는 Object(객체)를 다양하게 초기화하기 위해서임

  3. 생성자 선언(생성자 명시)

    1. 기본 생성자 대신 생성자를 명시적으로 선언할려면 예제처럼 작성해야함!

    2. [예제]

      Class(매개변수선언, ...) { // 생성자 블록
      	// Object(객체)초기화 코드
      }
      // 메소드와 비슷한 모양을 가지지만, 반환 타입이
      // 없으며 Class이름과 동일함
      
      // 생성자 블록 내부에는 Object(객체)초기화 코드가
      // 작성되고, 일반적으로 필드에 초기값을 저장하거나
      // 메소드를 호출하여 Object(객체)사용 전에 필요한
      // 준비를 하고, 매개변수 선언은 생략이 가능하고,
      // 여러 개를 선언도 할 수 있음!
      
      // 매개변수는 new 연산자로 생성자 호출 시 외부의값
      // 생성자 블록 내부로 전달하는 역할을 함
      
      ex)
      Test myTest = new Test("Hello", "Black", 2);
      
    3. Class 생성자가 명시적으로 선언되었을 경우, 반드시 선언된 생성자를 호출해서 Object(객체)를 생성해야만 함!

      1. [예제]

        // 생성자 선언 => Test.java
        public class Test{
        	// Constructor
        	Test(String strTest, int iTest){ }
        }
        
        // 생성자를 호출해서 객체 생성 
        // => TestExample.java
        public class TestExample {
        	public static void main(String[] args) {
        		Test myTest = new Test("Black", 2);
        		// Test myTest : 기본 생성자는 호출 X
        	}
        }
        
  4. 필드(Field)초기화?

    1. Class로부터 Object(객체)가 생성될 때 Field(필드)는 기본 초기값으로 자동 설정됨[✔ 다른값으로 초기화시 2가지 방법]
      1. 필드를 선언할 때 초기값을 주는 방법
      2. 생성자에서 초기값을 주는 방법(매개변수)
    2. Field를 선언할 때 초기값을 주게되면, 동일한 클래스로부터 생성되는 Object(객체)들은 모두 같은 데이터를 가짐!
    3. Object(객체) 생성 후 변경할 수 있지만, Object(객체) 생성 시점에는 Field(필드) 값이 모두 같음
      1. [예제]

        // Noddle Class
        public class Noddle {
        	// Member Variable[멤버변수]
        	String noddleName = "열라면";
        	String soup;
        	String price;
        
        	// Constructor[생성자]
        	public Noddle(String soup, String price) {
        		this.soup = soup;
        		this.price = price;
        	}
        }
        
        
        1. 객체 생성시점에서 외부에서 제공되는 다양한 값들로 초기화 되어야 한다면 생성자에서 초기화를 해야함
        2. soup, price 필드 값은 클래스를 작성할 때 초기값을 줄 수 없고 객체 생성 시점에 다양한 값을 가져야 함!
        3. 생성자의 매개값으로 이 값들을 받아 초기화해야함
      2. 관례적으로 필드와 동일한 이름을 갖는 매개변수를 사용하고, 생성자 내부에서 해당 필드에 접근할 수 없음!

      3. 동일한 이름의 매개변수가 사용 우선순위가 높기 때문이고, 해결방법은 “this.”을 붙여주면 됨!

        1. this : 객체 자신을 참조한다고 생각하면 됨!
  5. 생성자 오버로딩(Overloading)

    1. 외부에서 제공되는 다양한 데이터들을 이용해서 Object(객체)를 초기화하려면, 생성자도 다양화될 필요가 있음!

    2. 생성자가 하나뿐이라면 두 가지 경우에 따라 객체를 모두 생성 할 수 없음!

    3. 매개변수를 달리는 생성자를 여러개 선언이 가능하도록 하는 것을 말함

      1. [예제]

        // Test Class에서의 생성자 오버로딩
        public class Test {
        	Test() {...}
        	Test(String one) {...}
        	Test(String one, String two){...}
        }
        
      2. [주의]

        1. 매개변수의 타입과 개수, 선언된 순서가 똑같을 경우에 매개변수 이름만 바꾸는 행위는 생성자 오버로딩으로 볼 수 가 없음!(구분 X)

        2. [예제]

          Test(String one, String two){...}
          // 오버로딩이 아님!
          Test(String one, String thrid){...}
          
    4. 생성자가 오버로딩 되어 있을 경우, new 연산자로 생성자를 호출 할때, 제공되는 매개값의 타입과 개수에 의해 호출될 생성자가 결정이 됨

      1. [예제]

        // Noddle Class
        public class Noddle {
        	// 필드
        	String noddleName = "열라면";
        	String soup;
        	String price;
        
        	// 기본생성자
        	public Noddle() {}
        
        	// 생성자1
        	public Noddle(String soup) {
        		// 필드에 매개변수 값 저장함
        		this.soup = soup;
        	}
        
        	// Constructor[생성자 오버로딩]
        	public Noddle(String soup, String price) {
        		// 필드에 매개변수 값 저장함
        		this.soup = soup;
        		this.price = price;
        	}
        }
        
        // NoddleExample Class
        public class NoddleExample {
        	public static void main(String[] args) {
        		// 기본생성자(생성자1)
        		Noddle ramen = new Noddle();
        		// 열라면
        		System.out.println(ramen.noddleName);
        
        		// 생성자2
        		Noddle ramen = new Noddle("너구리");
        		// 너구리
        		// 매콤한맛
        		System.out.println(ramen.noddleName);
        		System.out.println(ramen.soup);
        
        		// 생성자3
        		Noddle ramen = new Noddle("진라면");
        		// 진라면
        		// 순한맛
        		// 1500원
        		System.out.println(ramen.noddleName);
        		System.out.println(ramen.soup);
        		System.out.println(ramen.price);
        	}
        }
        
  6. 다른 생성자 호출 this()?

    1. 생성자 오버로딩이 많아질 경우 생성자간 중복 코드가 많아지는데, 매개변수만으로 다르게 하고 필드 초기화 내용이 비슷한 생성자에서 이런 현상이 주로 발생하며, 해결방법은 필드 초기화 내용은 한 생성자에서만 작성하고, 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있음

    2. this() : 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫 줄에서만 허용이되고, 매개값은 호출되는 생성자의 매개변수 타입에 맞게 제공해야함, 그리고 추가적으로 실행문들이 그 다음으로 들어 옴!

    3. [예제]

      // Noddle Class
      public class Noddle {
      	// 필드
      	String noddleName = "열라면";
      	String soup;
      	String price;
      	
      	// 기본생성자
      	public Noddle() {}
      
      	// 생성자1
      	public Noddle(String noddleName) {
      		// 필드에 매개변수 값 저장함
      		// 생성자1, 생성자3
      		this(noddleName, "매운맛", 1600);
      	}
      
      	// Constructor[생성자2]
      	public Noddle(String noddleName, String soup) {
      		// 필드에 매개변수 값 저장함
      		// 생성자2, 생성자3
      		this(noddleName, soup, 1800);
      	}
      
      	// Constructor[생성자3]
      	public Noddle(String noddleName, String soup, String price) {
      		// 필드에 매개변수 값 저장함
      		// 공통 실행 코드
      		this.noddleName = noddleName;
      		this.soup = soup;
      		this.price = price;
      	}
      }
      
      // NoddleExample Class
      public class NoddleExample {
      	public static void main(String[] args) {
      		// 기본생성자(생성자1)
      		Noddle ramen = new Noddle();
      		// 열라면
      		System.out.println(ramen.noddleName);
      
      		// 생성자2
      		Noddle ramen = new Noddle("너구리", "매콤한맛");
      		// 너구리
      		// 매콤한맛
      		System.out.println(ramen.noddleName);
      		System.out.println(ramen.soup);
      
      		// 생성자3
      		Noddle ramen = new Noddle("진라면", "순한맛", 1700);
      		// 진라면
      		// 순한맛
      		// 1700원
      		System.out.println(ramen.noddleName);
      		System.out.println(ramen.soup);
      		System.out.println(ramen.price);
      	}
      }