수업내용/Java

[2022.09.16.금] 생성자, this

주니어주니 2022. 9. 17. 03:20

 

1. 생성자(Constructor) 

 

1-1. 생성자 

  • 객체가 생성될 때 호출되는 '객체 초기화 메소드' (-> 객체 초기화 작업, 객체 생성 시 실행할 작업을 위해 사용) 
  • 생성자도 클래스 내에 선언되는 메소드
  • 생성자는 클래스 이름과 동일한 이름을 가진 메소드
  • 생성자 메소드는 반환타입 자체를 적지 않는다 ( void 도 X ) 
  • 생성자도 오버로딩(중복정의)이 가능하므로 하나의 클래스에 여러개의 생성자 가능
  • 객체 생성 직후에 실행되는 메소드
  • 정의는 그냥 하지만, 사용할 때는 반드시 new 연산자와 같이 사용
    ( new가 객체를 생성하는 것이지, 생성자가 객체를 생성하는 것이 X ) 
  • 객체의 초기화 작업과 관련된 수행문 포함
    • 객체의 초기화 작업
      • 멤버변수의 값 초기화하는 것
      • 업무로직 수행전에 실행할 전처리 작업을 수행하는 것
      • 업무로직 수행에 필요한 리소스(자원)을 연결/획득하는 것

* 생성자 정의 방법

클래스이름 (매개변수타입 매개변수명, 매개변수타입 매개변수명, ...) { 
                    // 객체 생성 시 수행될 코드
                    // 주로 객체 변수의 초기화 코드를 적는다
}


ex. 
class Card { 
         Card( ) {                                    // 매개변수가 없는 생성자 (=기본 생성자) 
}
         Card(String k, int num) {          // 매개변수가 있는 생성자



ex. 
public class Book {                            // Book 클래스
          int no;                                      // 멤버변수 (필드) 
          String title;
          String writer;

         public Book() {                          // 생성자 메소드  ( 사용 시 new 연산자랑만 사용 = 객체 생성할 때만 사용 ) 
         }

         public void printBook() {           // 멤버 메소드
         } 
}

 

Book b1 = new Book( ); 
 
new -----> Book 객체 생성
Book( ); -----> 얘가 생성자 메소드 (new로 인해 객체 생성됨과 동시에 생성자 메소드 실행됨)  

- new Book( )을 실행했을 때 자바가상머신이 수행하는 작업

1. 생성자 메소드의 이름과 동일한 자바클래스를 메모리에 로딩
    (Book.class를 메모리에 로딩)
2. new로 인해, 메모리에 로딩된 클래스를 이용해서 객체 생성
    (Book.class를 이용해서 메모리의 Heap 영역에 Book 객체 생성)
3. 생성된 객체에 포함된 생성자 메소드가 호출되어 실행
    (Book( ) 생성자 메소드 실행)
4. 생성된 객체의 주소값을 b1에 대입



* new Book( ) 에서 Book( )으로 알 수 있는 것 

   - 지금까지 객체를 생성하기 위해서 사용했던 '클래스이름()'이 바로 생성자였다

   - 객체를 생성할 때는 반드시 클래스 내에 정의된 생성자 중 하나를 선택하여 지정해야 한다. 
   - 객체 생성을 위해서 메모리에 로딩할 클래스의 이름을 알려준다
     객체 생성에 사용할 설계도를 알 수 있다.
    ( 생성자 메소드의 이름과 클래스의 이름이 동일하기 때문 )
  - 객체 생성 직후에 실행할 메소드를 알려준다 ( Book( ) 생성자 메소드가 객체 생성직후에 실행할 생성자 메소드) 
    객체 생성 직후에 객체의 초기화 작업을 수행
  ∴ 즉, new 키워드 다음에 생성자 메소드를 적으면, 객체 생성에 필요한 설계도의 이름과 객체 생성직후에 실행할 메소드의 이름을 JVM에게 알려줄 수 있다.

 

1-2. 기본 생성자 메소드 

 

  • 매개변수가 하나도 없는 생성자 메소드 
  • 기본 생성자 메소드는 다른 생성자가 하나도 없을 때 컴파일러가 자동으로 추가 
    • 개발자가 생성자를 정의하지 않았더라도, 실행파일에 기본 생성자는 포함
    • 따라서, 생성자 메소드를 정의하지 않았는데도, 객체 생성시 Person person = new Person()를 적을 수 있던 것
  • 특별히 객체 초기화 작업이 요구되지 않는다면, 생성자를 정의하지 않고 컴파일러가 제공하는 기본 생성자를 사용하는 것도 좋음

 

  • 기본생성자를 직접 정의한  Employee 메소드 정의 클래스 (직접 정의 안해도 자동으로 추가 됨) 
public class Employee {

	int no;
	String name; 
	String dept; 
	String positon;
	int salary; 
	int commission;
	boolean isExpired;
	
	// 기본 생성자 정의하기
	public Employee() {
		System.out.println("기본생성자 실행");
	}
}

 

  • EmployeeApp1 메인 클래스
public class EmployeeApp1 {

	public static void main(String[] args) {
		// Employee  객체 생성하기
		Employee empl = new Employee(); // 객체 생성하자마자 기본생성자 실행됨 
		
	}
}

 

기본생성자 실행

 

 

  • Employee 객체 생성 설명

 

 

1. 클래스 이름과 동일한 생성자 메소드를 자동으로 추가 후, Employee.class가 메모리의 클래스영역에 로딩

    Employee.java(소스파일, 우리가 입력)를 컴파일하면 Employee.class (실행파일, 컴퓨터 언어)로 됨

-> public Employee( ) { }  <- 컴파일을 하면서 실행파일 안에 컴파일러가 기본생성자 메소드를 자동으로 추가함

   (생성자가 자동으로 추가되어 있기 때문에 메인 클래스에서 new 뒤에다가 생성자를 붙여 사용할 수 있는 것 )

-> Employee.class 설계도가 메모리의 클래스영역에 로딩 

 

2. 메모리에 로딩된 클래스를 이용해서 객체 생성

    Employee emp = new Employee( ); 

-> new 연산자로 인해서, 클래스(설계도)를 이용해 Employee 객체 생성

-> 객체를 생성하면, 그 안에 변수들과 생성자 메소드가 같이 로딩됨

 

3. 생성된 객체에 포함된 생성자 메소드를 실행 ( public Employee( ) { } )

    Employee emp = new Employee( ); 

-> 생성된 객체 안에 있는 Employee( ) { } 라는 메소드를 실행         

 

4. 생성된 객체의 주소값을 참조변수 emp에 대입 

    Employee emp = new Employee( );   

-> 생성된 객체의 주소값을 변수에 대입

 

 

* 기본 생성자가 자동 추가되는 것은 '클래스에 정의된 생성자가 하나도 없을 때' 

 

// class Data1 선언클래스

class Data1 { 
	int value;
}


// class Data2 선언클래스

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(); // 컴파일 에러.
     // Data2 d2 = new Data2(10); 기본생성자 말고 선언한 생성자를 호출하는 것은 가능
    }
}

 

  • 에러의 이유 : Data2의 기본생성자를 호출했는데, Data2에는 기본생성자가 없기 때문
                         (Data2에 이미 정의된 생성자가 있기 때문에, 기본생성자가 자동으로 추가되지 않았음) 
  • 따라서, 선언클래스에서 다른 생성자 메소드를 선언했다면, 기본 생성자 메소드도 직접 추가해야 함 ! 

 

 

 

1-3. 생성자 메소드의 수행문

  • 생성자 메소드의 수행문은 객체 생성 직후에 실행된다.
  • 생성자 메소드의 수행문으로 객체의 멤버변수를 초기화할 수 있다.

 

public class Employee {		// 클래스 안에 변수 생성

	int no;
	String name; 
	String dept; 
	String position;
	int salary; 
	int commission;
	boolean isExpired;
	
	// 기본 생성자 정의하기 
	public Employee() {
		System.out.println("기본생성자 실행");	// 객체를 만들면 만든 직후 이게 실행
		//멈버변수의 값 초기화하기
		no = 1;					// 객체를 만든 직후 멤버변수의 값들이 초기화됨
		name = "홍길동"; 
		dept = "인사팀";
		position = "인턴";
		salary = 300;
		commission = 0;
		isExpired = false;
	}
    
   	// 멤버 메소드 정의하기 - 얘를 해야 위 내용들이 출력
	public void display() {
		System.out.println("사원번호: "+no);
		System.out.println("사원이름: "+name);
		System.out.println("소속부서: "+dept);
		System.out.println("직위: "+position);
		System.out.println("급여: "+salary);
		System.out.println("커미션: "+commission);
		System.out.println("퇴사여부: "+isExpired);
		System.out.println();
	}

 

public class EmployeeApp1 {

	public static void main(String[] args) {
		// Employee  객체 생성하기
		Employee empl = new Employee(); // 객체 생성 + 기본생성자 실행 
						// 여기까지만 하면 "기본생성자 실행됨" 출력
		// 사원정보 표시하기 
		empl.display(); 		// 객체 생성시점에 하고싶은 작업을 수행하는 것 
        					// display 메소드 실행(호출)
	}
}

 

기본생성자 실행됨

사원번호: 1
사원이름: 홍길동
소속부서: 인사팀
직위: 인턴
급여: 300
커미션: 0
퇴사여부: false

 

 

1-4. 매개변수가 있는 생성자

 

  • 객체마다 각기 다른 값으로 초기화되어야 하는 경우가 많기 떄문에 매개변수를 사용한 초기화가 매우 유용함
  • 객체 생성시점에 멤버변수의 값을 다 넣음으로써, 객체 생성과 동시에 원하는 값으로 쉽게 초기화 실행

 

※ 매개변수가 있는 생성자를 쉽게 생성하는법
오른쪽버튼 -> source -> generate construct using field -> 매개변수 골라서 -> generate

 

  • 이런 설계도 클래스가 있을 때, 
class Car { 
	String color; 
   	String gearType; 
  	int door; 
    
    Car() { } 	// 기본 생성자 선언
    
    
    Car(String c, String g, int d) {	// 매개변수를 갖는 생성자 선언
    	color = c;			// 매개변수 c로 받는 값을 멤버변수 color에 대입
        gearType = g;			// 매개변수 g로 받는 값을 멤버변수 gearType에 대입
        door = d;			// 매개변수 d로 받는 값을 멤버변수 door에 대입
    }
}

 

 

<매개변수가 있는 생성자의 사용유무를 비교해보기>

 

1) 객체를 생성한 다음 -> 객체의 멤버변수 값을 따로 일일이 초기화  

class CarTest { 
	public static void main(String[] args) {
    
    	Car c1 = new Car();		// 객체 생성 + 기본생성자 실행
        c1.color = "white";		// 객체의 멤버변수 초기화
        c1.gearType = "auto";
        c1.door = 4;
        System.out.println("c1의 color= "+c1.color+", gearType= "+c1.gearType+", door= "+c1.door);

 

2) 객체 생성 + 원하는 값으로 초기화 동시에 실행 ( = 매개변수를 갖는 생성자 )

    생성자 선언할 때 매개변수를 입력해놨으므로, 객체 생성할 때는 매개변수에 맞는 값만 입력하면 됨! 

class CarTest { 
	public static void main(String[] args) {
    
    	Car c2 = new Car("white", "auto", 4);	// 객체 생성과 동시에 변수 초기화
      	System.out.println("c2의 color= "+c2.color+", gearType= "+c2.gearType+", door= "+c2.door);

 

출력값은 동일

c1의 color= white, gearType= auto, door= 4
c2의 color= white, gearType= auto, door= 4

 

 

※ 설계도클래스에서 생성자를 선언할 때, 매개변수를 갖는 생성자로 선언하고
    실행클래스에서는 객체 생성 + 매개변수에 들어갈 값만 입력해주기 ! 

 

 

 

** 생성자를 쓰는 이유 : 객체 생성시점에 멤버변수의 값을 다 넣음으로써, 초기화를 훨씬 쉽게 할 수 있다.

 

<매개변수를 갖는 생성자 메소드 사용 X> 

Employee emp = new Employee();     

emp.no = 100;                                    

emp.name = "홍길동";

emp.position = "영업1팀"; 

// 먼저 객체를 생성하고, 그 객체의 주소값을 emp변수에 저장한 후

// emp변수가 바라보는 객체의 no변수에 100을 저장

// 여태까지는 이렇게 헀었는데 

 

<매개변수를 갖는 생성자 메소드 사용> 

Employee emp = new Employee(100, "홍길동", "영업1팀", 600, 100, false) ;  

// 객체 생성과 동시에 그 객체의 설계도 클래스에 있는 변수, 메소드도 불러와서 메소드의 매개변수에 알아서 딱딱 대입

// 그리고 객체의 주소값이 emp변수에 저장

// 한줄로 줄어들어버림

 

 

* Employee emp5 = new Employee(); 
  emp5.Employee(100, "류관순", 250); 
생성자메소드는 이렇게  참조변수로 실행(호출)할 수 없다 
그냥 알아서 실행되는거 

 

 

* 반환타입이 void인 멤버메소드생성자메소드의 구분 

- 생성자메소드 : 객체생성과 동시에 실행, new뒤에서만 사용 (참조변수로 실행할 수 없음)
- 반환타입이 void인 멤버메소드 : 객체생성 이후에 실행,  참조변수를 통해서만 사용

 

 

1-5. 생성자 메소드 중복정의 

 

public class Employee {

	int no;
	String name; 
	String dept; 
	String position;
	int salary; 
	int commission;
	boolean isExpired;
	
	// 기본 생성자 정의하기
	public Employee() {
		System.out.println("기본생성자 실행");
		//멈버변수의 값 초기화하기
		no = 1;
		name = "홍길동"; 
		dept = "인사팀";
		position = "인턴";
		salary = 300;
		commission = 0;
		isExpired = false;
	}
	
	// 생성자 중복정의 (매개변수 3개) 
	// 인턴사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	// 인턴은 무조건 부서(인사팀), 직위(인턴), 커미션(없음), 퇴사여부(없음)가 고정 
	// 필요한 정보만을 매개변수로 사용
	public Employee(int no, String name, int salary) {
		System.out.println("인턴 사원용 생성자 실행됨");
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 경력사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
				int salary, int commission) {
		System.out.println("경력직 사원용 생성자 실행됨");
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 모든 사원저오를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
			int salary, int commission, boolean isExpired) {
		System.out.println("모든 사원용 생성자 실행됨");
	}
 }

 

public class EmployeeApp1 {

	public static void main(String[] args) {
		// Employee  객체 생성하기 + 매개변수를 통해 멤버변수값 초기화
		Employee emp1 = new Employee(); 			// 매개변수가 없는 기본생성자로 자동연결
		Employee emp2 = new Employee(100, "류관순", 250);	// 매개변수 3개인 인턴사원용 생성자로 자동연결 
		Employee emp3 = new Employee(200, "이순신", "개발1팀", "차장", 700, 150);
		Employee emp4 = new Employee(300, "강감찬", "영업팀", "대리", 400, 200, false);
		
	}
}

 

기본생성자 실행됨
인턴 사원용 생성자 실행됨
경력직 사원용 생성자 실행됨
모든 사원용 생성자 실행됨

 

 

* 총 4개의 생성자 (기본, 1, 2, 3) 중에서 매개변수 인자에 맞게 입력한 것에 따라서 자동으로 연결됨

 

 

 

 

* 만약 기본생성자를 정의한 후에 멤버변수를 따로 초기화하지 않고, 선언클래스에서 변수를 선언할 때 바로 초기화 하면? 

변수 선언할 때 초기화한 저 값으로 계속 고정되어버림

int commission = (double) salary * 0.03  이런식으로는 가능

 

 

 

 

2. 생성자에서 다른 생성자 호출하기 - this와 this() 

 

2-1. this    (≒ 참조변수) 

  • 생성된 객체 자기 자신의 주소값을 가지고 있다 ( 자기 자신을 가리키는 키워드 ) 

  •  this를 쓰는 이유
    • 객체 멤버변수의 이름과 생성자 매개변수의 이름이 동일한 경우, 매개변수와 멤버변수를 구분하기 위해서
      - 내가 초기화한 값 -> 생성자 메소드의 매개변수 -> 객체의 멤버변수로 값을 전달할 건데
        이때 멤버변수와 매개변수가 같은 의미이므로 변수명이 겹침. 둘을 구분하기 위해서 this를 사용

 

  • 생성자의 매개변수 이름 ≠ 객체의 멤버변수 이름 
class Employee { 
	int no; 
   	String name; 
  	int salary; 
    
    Employee(int eNo, String eName, int eSalary) {	// 매개변수를 갖는 생성자 선언
    	no = eNo;					// 객체의 멤버변수 no에 생성자의 매개변수 eNo의 값 저장
        name = eName;			
        salary = eSalary;			
    }
}

 

  • 생성자의 매개변수 이름 = 객체의 멤버변수 이름
class Employee { 
	int no; 
   	String name; 
  	int salary; 
    
    Employee(int no, String name, int salary) {		// 매개변수를 갖는 생성자 선언
    	this.no = no;					// 이 객체(this)의 멤버변수 no에 생성자의 매개변수 no의 값 저장
    	this.name = name;
    	this.salary = salary;			
    }
}

 

 

 

 

  • public class Employee {                                                    // 설계도 클래스에 일단 변수들을 선언

       int no;
       String name; 
       String dept; 
       String position;
       int salary; 
       int commission;
       boolean isExpired;

  • public Employee( ) { }                                                          // 기본 생성자 생성
    public Employee(int no, String name, int salary) {       
        // 매개변수를 갖는 생성자 메소드 생성 (생성만 한 거임) 
       this.no = no;                                                                     
    // 이 객체의 no변수에 매개변수로 받은 no값을 대입
       this.name = name;
       this.salary = salary;
    }
     

  • Employee emp1 = new Employee(10, "김유신", 250);       // 객체 생성 + 생성자 메소드 실행 (동시)
    Employee emp2 = new Employee(20, "강감찬", 300);
      
    //     객체 생성 + 생성자 메소드 실행 (동시)
       -> 새로 생성된 객체 안에 설계도 클래스의 변수, 메소드들이 로딩됨
       -> 메소드의 매개변수에 내가 입력한 값 대입
       -> 메소드 매개변수에 저장된 값이 this가 참조하는 객체의 멤버변수에 대입
       -> this가 참조하는 객체의 변수에 값이 저장된 이 메소드의 상태가 emp1 변수에 저장되고 메소드 종료
          (값을 저장만 하는 메소드임. 출력x)
           * 이 때, emp1 변수가 참조하는 것은 새로 생성한 Employee객체의 주소값
                       생성자 메소드 안의 this 참조변수가 참조하는 것도 Employee객체의 주소값
           (Employee타입의 클래스를 이용해서 Employee 객체를 새로 만들고, 그 주소값을 emp1에 대입 -> emp1이 참조
            Employee 클래스를 이용해서 객체를 만들어서 변수와 생성자, 메소드도 그대로 들어가있음 
            -> 이 때 그 Employee 클래스 안에 있는 this 변수가 그 클래스를 가리키므로 그 주소값 저장 -> this가 참조) 

 

  • <this의 사용 가능한 범위>
    • emp1 변수도 0x1111 객체를 바라보고 있고, 객체 내부에 있는 this 도 자기 자신인 0x1111 객체를 바라보고 있음이 this는 내부에서만 사용 가능. 객체 밖에서 사용 불가
    • 예시)
      public class EmployeeApp {
         public static void man(String[] args) { 
             Employee emp1 = new Employee(10, "김유신", 250);  // Employee 객체를 참조하고 있는 emp1참조변수 
                this.display();                                         // 오류. this도 객체를 참조하고 있지만 객체 밖에서 접근할 수 없음           emp1.display();                                     //  emp1변수로만 접근 가능

 

 

 

 

  • 연습 (설계도 클래스)
public class Employee {

	int no;
	String name; 
	String dept; 
	String position;
	int salary; 
	int commission;
	boolean isExpired;
	
	// 기본 생성자 정의하기
	public Employee() {
		System.out.println("기본생성자 실행됨");
//		//멈버변수의 값 초기화하기
		no = 1;
		name = "홍길동"; 
		dept = "인사팀";
		position = "인턴";
		salary = 200;
		commission = 0;
		isExpired = false;
	}
	
	// 생성자 중복정의 (매개변수 3개) 
	// 인턴사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	// 인턴은 무조건 부서(인사팀), (직위)인턴, (커미션)커미션 없음, (퇴사여부)없음이 고정 
	// 필요한 정보만을 매개변수로 사용
	public Employee(int no, String name, int salary) {
		System.out.println("인턴 사원용 생성자 실행됨");
		this.no = no;			// this가 가리키는 객체의 no변수에 매개변수로 받은 no값을 대입
		this.name = name;
		this.dept = "인사팀";		// 정해져있는 값들은 고정시켜놓고
		this.position = "인턴";
		this.salary = salary;
		this.commission = 0;
		this.isExpired = false;
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 경력사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
				int salary, int commission) {
		System.out.println("경력직 사원용 생성자 실행됨");		
		this.no = no; 
		this.name = name; 
		this.dept = dept;
		this.position = position;
		this.salary = salary;
		this.commission = commission;
		this.isExpired = false;
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 모든 사원저오를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
			int salary, int commission, boolean isExpired) {
		System.out.println("모든 사원용 생성자 실행됨");
		this.no = no; 
		this.name = name; 
		this.dept = dept;
		this.position = position;
		this.salary = salary;
		this.commission = commission;
		this.isExpired = isExpired;
	}
	
	// 멤버 메소드 정의하기 (볼 수만 있게 하는 메소드) 
	public void display() {
		System.out.println("사원번호: "+no);
		System.out.println("사원이름: "+name);
		System.out.println("소속부서: "+dept);
		System.out.println("직위: "+position);
		System.out.println("급여: "+salary);
		System.out.println("커미션: "+commission);
		System.out.println("퇴사여부: "+isExpired);
		System.out.println();
	}
}

 

 

  • 연습 (실행 클래스) 
public class EmployeeApp1 {

	public static void main(String[] args) {
		// Employee  객체 생성하기
		Employee emp1 = new Employee();				// 매개변수가 없는 기본생성자로 자동연결
		Employee emp2 = new Employee(100, "류관순", 250); 	// 매개변수 3개인 인턴사원용 생성자로 연결 
		Employee emp3 = new Employee(200, "이순신", "개발1팀", "차장", 700, 150);
		Employee emp4 = new Employee(300, "강감찬", "영업팀", "대리", 400, 200, false);
		
		// 사원정보 표시하기
		emp1.display(); //객체 생성시점에 하고싶은 작업을 수행하는 것 
		emp2.display();
		emp3.display();
		emp4.display();
		
	}
}

 

기본생성자 실행됨
인턴 사원용 생성자 실행됨
경력직 사원용 생성자 실행됨
모든 사원용 생성자 실행됨
사원번호: 1
사원이름: 홍길동
소속부서: 인사팀
직위: 인턴
급여: 200
커미션: 0
퇴사여부: false

사원번호: 100
사원이름: 류관순
소속부서: 인사팀
직위: 인턴
급여: 250
커미션: 0
퇴사여부: false

사원번호: 200
사원이름: 이순신
소속부서: 개발1팀
직위: 차장
급여: 700
커미션: 150
퇴사여부: false

사원번호: 300
사원이름: 강감찬
소속부서: 영업팀
직위: 대리
급여: 400
커미션: 200
퇴사여부: false

 

* 근데 반복되는 부분이 너무 많아! 이걸 줄이기 위한게 this( ) 메소드 

 

 

 

 

2-2. this()

  • this()는 같은 클래스 내의 다른 생성자를 호출할 때 사용하는 메소드
    • 같은 클래스 내의 생성자들은 서로 관계가 깊으므로, 서로 호출하도록 연결하는 것이 좋음
      수정이 필요한 경우에도, 보다 적은 코드만 변경하면 되므로 유지보수가 용이

  • 생성자 메소드에서 다른 생성자를 호출할 때는 클래스명() 대신 this() 를 사용
  • 값을 초기화하는 코드를 한줄로 줄여줌
  • 생성자 메소드 안에서만 사용 가능
  • 생성자 메소드에서 다른 생성자메소드를 호출할 때는 반드시 수행문의 첫줄에 this()를 적어야 함
  • 생성자 메소드의 매개변수에 맞게 인자값을 지정하면, 매개변수가 일치하는 생성자 메소드를 호출

 

 

 

public class Employee {

   int no;   String name;    String dept;    String position;    int salary;    int commission;    boolean isExpired

 

   public Employee( ) {                                                           // 클래스 안에서 다른 생성자를 호출할 때 쓰는 것 this()

          this(10, "홍길동", 250);            // 이 생성자는 매개변수가 없으므로, 매개변수 3개짜리인 생성자를 호출해서 값 입력

       

   }

   public Employee(int no, String name, int salary) {                       // 이 생성자는 매개변수 3개짜리이므로

           this(no, name, "인사팀", "인턴", salary, 0, false)                  // 매개변수가 더 많은 생성자를 호출해서 값 입력

   }

 

   pubic Employee(int no, String name, String dept, String position, int salary, int commission) 

           this(no, name, dept, position, salary, commission, false);   // 매개변수가 더 많은 생성자를 호출해서 값 입력

   }

 

  public Employee(int no, String name, String dept, String position,int salary, int commission, boolean isExpired) {

          this.no = no;                                         // 맨밑에 있는 생성자를 주로 활용함(매개변수가 제일 많이 있는것?)

          this.name = name; 
          this.dept = dept;
          this.position = position;
          this.salary = salary;
          this.commission = commission;
          this.isExpired = isExpired;

   }

}

 

 

 

public class Employee {

	int no;
	String name; 
	String dept; 
	String position;
	int salary; 
	int commission;
	boolean isExpired;
	
	// 기본 생성자 정의하기
	public Employee() {
		this(1, "홍길동", 200);
	}
	
	// 생성자 중복정의 (매개변수 3개) 
	// 인턴사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	// 인턴은 무조건 부서(인사팀), (직위)인턴, (커미션)커미션 없음, (퇴사여부)없음이 고정 
	// 필요한 정보만을 매개변수로 사용
	public Employee(int no, String name, int salary) {
		this(no, name, "인사팀", "인턴", salary, 0, false); 
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 경력사원 정보를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
				int salary, int commission) {
		this(no, name, dept, position, salary, commission, false); 
	}
	
	// 생성자 중복정의 (매개변수 여러개)
	// 모든 사원저오를 전달받아서 Employee객체를 초기화하는 생성자
	public Employee(int no, String name, String dept, String position,
			int salary, int commission, boolean isExpired) {
		this.no = no; 
		this.name = name; 
		this.dept = dept;
		this.position = position;
		this.salary = salary;
		this.commission = commission;
		this.isExpired = isExpired;
	}
	
	// 멤버 메소드 정의하기
	public void display() {
		System.out.println("사원번호: "+no);
		System.out.println("사원이름: "+name);
		System.out.println("소속부서: "+dept);
		System.out.println("직위: "+position);
		System.out.println("급여: "+salary);
		System.out.println("커미션: "+commission);
		System.out.println("퇴사여부: "+isExpired);
		System.out.println();
	}
}

 

public class EmployeeApp1 {

	public static void main(String[] args) {
		// Employee  객체 생성하고 변수에 저장하기
		Employee emp1 = new Employee(); 				
		Employee emp2 = new Employee(100, "류관순", 250);  
		Employee emp3 = new Employee(200, "이순신", "개발1팀", "차장", 700, 150);
		Employee emp4 = new Employee(300, "강감찬", "영업팀", "대리", 400, 200, false);
		
		// 사원정보 표시하기 
		emp1.display(); 
		emp2.display();
		emp3.display();
		emp4.display();
		
	}
}

 

사원번호: 1
사원이름: 홍길동
소속부서: 인사팀
직위: 인턴
급여: 200
커미션: 0
퇴사여부: false

사원번호: 100
사원이름: 류관순
소속부서: 인사팀
직위: 인턴
급여: 250
커미션: 0
퇴사여부: false

사원번호: 200
사원이름: 이순신
소속부서: 개발1팀
직위: 차장
급여: 700
커미션: 150
퇴사여부: false

사원번호: 300
사원이름: 강감찬
소속부서: 영업팀
직위: 대리
급여: 400
커미션: 200
퇴사여부: false

 

 

 

 

 

* getter메소드 (은닉화) 

 

 

 

 

 

  • 학생정보 클래스
public class StudentScore {

	private String name;		//필드 은닉화
	private int kor; 
	private int eng;
	private int math;
	
	/*
	 * 개발자가 정의한 생성자가 이미 존재하기 때문에 컴파일러가 기본 생성자를 추가하지 않는다.
	 * public StudentScore() {} 생성자(기본생성자)는 정의되지 않았다.
	 */
	
	public StudentScore(String name, int kor, int eng, int math) {	//생성자
		this.name = name;
		this.kor = kor;
		this.eng = eng;
		this.math = math;
	}
	
	// 은닉화된 필드의 값을 제공(반환)하는 Getter 메소드 정의 (= 값 조회하는 메소드)
	public String getName() {
		return name;
	}
	public int getKor() {
		return kor;
	}
	public int getEng() {
		return eng;
	}
	public int getMath() {
		return math;
	}
    
	//은닉화된 필드의 값을 활용해서 계산된 결과를 제공하는 Getter메소드 정의
	public int getTotal() {
		return kor + eng + math;
	}
	public double getAverage() {
		return getTotal()/3.0;
	}
	public boolean isPassed() {
		return getAverage() >= 60;
	}
	
	public void display() {
		System.out.println("이름: "+name); //필드에 저장된 값
		System.out.println("국어: "+kor);
		System.out.println("영어: "+eng);
		System.out.println("수학: "+math);
		System.out.println("총점: "+getTotal()); //getter메소드 
		System.out.println("평균: "+getAverage());
		System.out.println("합격여부: "+isPassed());
		System.out.println();
	}
}

 

  • 학생정보 객체
public class StudentScoreApp {
//	StudentScore score = new StudentScore();	
//	오류.개발자가 정의한 생성자가 하나 이상 존재하기 때문에 기본생성자가 생기지 x, 호출불가
	
	public static void main(String[] args) {
		StudentScore score = new StudentScore("홍길동", 100, 80, 70);	//생성자
//		score. 했을때 필드들이 안뜸 (필드가 모두 은닉화되어 있기 때문)
		
		// 공개되어있는 Getter 메소드를 이용해서 총점, 평균 조회하고 출력하기
		int total = score.getTotal();
		double average = score.getAverage();
		System.out.println("총점: "+total);
		System.out.println("평균: "+average);
		
		System.out.println();
		// void display() 메소드를 실행해서 성적정보 출력하기
		score.display();
	}
}

 

총점: 250
평균: 83.33333333333333

이름: 홍길동
국어: 100
영어: 80
수학: 70
총점: 250
평균: 83.33333333333333
합격여부: true

 

 

 

  • 설계도

 

public class StudentScore { 

    private String name;                // 필드를 은닉화

    private String kor; 

    private String eng; 

    private String math; 

    private String total; 

    private String average; 

    private String name; 

 

public StudentScore(String name, int kor, int eng, int math) {     // 생성자

    this.name = name; 

    this.kor = kor; 

    this.eng = eng; 

    this.math = math; 

    this.total = kor + eng + math; 

    this.average = this.total / 3;

    this.isPassed = this.average >= 60;

 

public void display( ) {                                                                      // 보기만 하는 메소드

    s.o.p("이름: "+ name);

   s.o.p("국어점수: "+kor);

   }

}

 

 

  • 실행 클래스
  • StudentScore score = new StudentScore("홍길동", 80, 70, 70);            // 생성자 메소드 호출

생성자가 이미 있으니까 기본생성자 호출은 안되고 이미 있는 생성자를 호출

StudentScore라는 객체 생성 후 만들어진 객체 안에 private 변수들

얘네는 밖에서 접근할 수 없음. 객체 안에서만 사용할 수 있음. 

이 객체를 score 변수가 참조하고 있음 

원래 score 변수를 통해서 객체 안에 있는 변수의 값을 바꾸고 그랬는데 

private이기 때문에 객체 밖에 있는 score 변수로 객체 내에 있는 변수에 접근 불가능

score.name = "김유신";                // 이걸로 이름을 바꾸고싶어 -> 불가능 

System.out.println(score.total);    // 객체 밖에 있는 score 변수로 객체 내의 변수에 접근 불가능 

 

근데 생성자는 공개되어 있어서 사용할 수 있어

StudentScore(String name, int kor, int eng, int math) { ... }  // 생성자가 객체안에 들어가 있고 

public void display( ) { ... }   // 보기만 할 수 있는 메소드 

score.display( );    이거는 실행할 수 있다 (display가 공개되어 있는 메소드니까) 

 

근데 막 뭐 이름이나 점수는 변경할 수 있게 하고싶을 때는

생성자 메소드 밑에 Getter메소드 정의

 

  • Getter메소드  

 

- 필드 값에 부적절한 값이 대입되는 것을 막기 위해서 사용

- 은닉화된 필드의 값을 제공(반환)하는 메소드 ( get + 필드이름 = 해당 필드의 값 반환 ) 

- 은닉화된 필드의 값을 이용해서 계산된 값을 제공하는 메소드

  ( 외부에서 객체의 데이터를 읽을 때 사용. 객체 외부에서 객체의 필드값을 사용하기 부적절한 경우, 메소드로 필드값을        가공 후 외부로 전달하는 역할 )

- 은닉화된 필드의 값을 조회하는 메소드 (정보를 담아놓는 메소드) 

- 필드는 은닉화, 기능(메소드)은 공개

   private으로 외부에서 직접적인 접근을 할 수 없도록 막고,  'getter/setter메소드를 통해서만' 데이터에 접근하도록 유도

   ( 메소드는 매개값을 검증해서 유효한 값만 데이터로 저장할 수 있기 때문)

- 데이터 호출시에는 마찬가지로 필드 값을 직접 호출하는 것이 아닌 getter 메서드를 통해 해당 필드 값을 가져오는 방식

- 항상 get을 붙여야 함 

- 매개변수를 절대 갖지 않음

- 반환값이 반드시 있음 

- 일반적으로 클래스를 선언할 때 필드를 private으로 선언해서 외부로부터 보호하고 필드에 대한 getter 메소드를 작성해서 필드값을 안전하게 변경/사용하는 것이 좋음

- 외부에서 필드값을 읽을 수만 있고, 변경하지 못하도록 하려면(읽기전용) getter메소드만 선언 

- 외부에서 객체의 데이터를 읽을 때도 메소드를 사용하는 것이 좋습니다. 이런 경우에는 메소드로 필드값을 가공한 후 외부로 전달하면 됩니다. 이런 메소드가 바로 Getter() 메소드

-

 

 

public String getName( )

    return name;                        // 은닉화된 변수 name에 getName 메소드를 통해서 접근, name 변수의 값 반환

public int getKor( )

    return kor

 

 

 

 

 

public class StudentScoreApp2 {
	
	public static void main(String[] args) {
		
		// StudentScore 객체의 주소값을 5개 저장할 수 있는 배열객체를 생성하고, 그 배열객체의 주소값을 scores에 대입
		StudentScore[] scores = new StudentScore[5];
		
		// StudentScore 객체를 생성 + 멤버변수를 초기화하는 생성자를 실행하고, 그 객체의 주소값을 배열의 n번째 칸에 저장
		scores[0] = new StudentScore("김유신", 80, 80, 60); //객체를 생성하고, 멤버변수를 "김유신"으로 초기화, 그 주소값을 0번째에 저장
		scores[1] = new StudentScore("강감찬", 80, 90, 50);
		scores[2] = new StudentScore("이순신", 50, 90, 60);
		scores[3] = new StudentScore("류관순", 70, 40, 70);
		scores[4] = new StudentScore("안중근", 70, 70, 60);
		
		// 배열에 저장된 모든 성적정보 출력하기
		System.out.println("### 모든 성적정보 출력하기 ###");
		for(StudentScore score : scores) {
			// score참조변수가 참조하는 객체의 void display() 메소드를 실행해서 해당 객체의 성적정보를 화면에 출력
			score.display();	//0번째 칸에 들어있는 주소값 하나가 score에 저장되고, 그 주소값의 display 실행	
		}
		
		// 국어점수 평균 계산하기
		System.out.println("### 국어점수 평균 출력하기 ###");
		int totalKorScore = 0;
		for(StudentScore score : scores) {
			// score참조변수가 참조하는 객체의 int getKor() 메소드를 실행해서 해당 객체의 kor변수에 저장된 국어점수를 획득
			int korScore = score.getKor();
			totalKorScore += korScore;
		}
		double averageKorScore = (double)(totalKorScore / scores.length); 
		System.out.println("국어점수 평균: "+ averageKorScore);
	}

}

 

### 모든 성적정보 출력하기 ###
이름: 김유신
국어: 80
영어: 80
수학: 60
총점: 220
평균: 73.33333333333333
합격여부: true

이름: 강감찬
국어: 80
영어: 90
수학: 50
총점: 220
평균: 73.33333333333333
합격여부: true

이름: 이순신
국어: 50
영어: 90
수학: 60
총점: 200
평균: 66.66666666666667
합격여부: true

이름: 류관순
국어: 70
영어: 40
수학: 70
총점: 180
평균: 60.0
합격여부: true

이름: 안중근
국어: 70
영어: 70
수학: 60
총점: 200
평균: 66.66666666666667
합격여부: true

### 국어점수 평균 출력하기 ###
국어점수 평균: 70.0

 

 

 

앞으로 만드는 클래스의 종류 

1. 프로그래밍할 대상이 되는 정보를 표현하는 클래스 

2. 그 정보를 조작하는 클래스(기능이 구현되어 있는 클래스) (ex. 책 정보를 등록, 조회, 변경, 검색, 삭제) 

 

 

 

개발자가 직접 생성한 생성자가 하나라도 있으면, 기본생성자가 자동으로 생기지 않음 

-> main클래스에 StudentScore score = new StudentScore(); 를 하면 오류 (생성자가 없다) -> 직접 생성한 생성자가 하나 있었기 때문에 기본생성자가 자동으로 생기지 않았음