자바 기본 | 4. 생성자

heige·2024년 5월 20일

Java

목록 보기
18/21
post-thumbnail

생성자 - 필요한 이유

객체를 생성하는 시점에 어떤 작업을 하고 싶다면 생성자(Constructor)를 이용하면 된다.

package construcct;

public class MemberInit {
    String name;
    int age;
    int grade;
}
package construcct;

public class MethodInitMain1 {
    public static void main(String[] args) {
        MemberInit member1 = new MemberInit();
        member1.name = "user1";
        member1.age = 15;
        member1.grade = 90;

        MemberInit member2 = new MemberInit();
        member2.name = "user2";
        member2.age = 16;
        member2.grade = 80;

        MemberInit[] members = {member1, member2};

        for (MemberInit m : members) {
            System.out.println("name : " + m.name + " age : " + m.age + " grade : " + m.grade);
        }
    }
}

위 코드는 회원의 초기값 설정하는 부분이 계속 반복되기 때문에 메서드를 사용해서 반복을 제거해본다.

package construcct;

public class MethodInitMain2 {
    public static void main(String[] args) {
        MemberInit member1 = new MemberInit();
        initMember(member1, "user1", 15, 90);

        MemberInit member2 = new MemberInit();
        initMember(member2, "user2", 16, 80);
        MemberInit[] members = {member1, member2};

        for (MemberInit m : members) {
            System.out.println("name : " + m.name + " age : " + m.age + " grade : " + m.grade);
        }
    }
    static void initMember(MemberInit member, String name, int age, int grade) {
        member.name = name;
        member.age = age;
        member.grade = grade;
    }
}

initMember 메서드를 사용해서 반복을 제거했다. 이 메서드는 MemberInit 객체의 멤버 변수를 사용한다. 이것보다, MemberInit이 자기 자신의 데이터를 변경하는 기능(메서드)를 제공하는 게 훨씬 깔끔하고 편리할 것.

this

MemberInit - initMember() 추가

package construcct;

public class MemberInit {
    String name;
    int age;
    int grade;

    void iniitMember(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}
package construcct;

public class MethodInitMain3 {
    public static void main(String[] args) {
        MemberInit member1 = new MemberInit();
        member1.initMember("user1", 15, 90);

        MemberInit member2 = new MemberInit();
        member2.initMember("user2", 16, 80);

        MemberInit[] members = {member1, member2};

        for (MemberInit m : members) {
            System.out.println("name : " + m.name + " age : " + m.age + " grade : " + m.grade);
        }

    }
}

this

(클래스 Member의 코드를 다시 보자.)

멤버 변수와 메서드의 배개변수의 이름이 같으면 둘을 어떻게 구분해야 할까?

  • 멤버 변수보다 매개변수가 코드 블럭의 더 안쪽에 있기 때문에 매개변수가 우선순위를 가진다. initMember(String name,...) 메서드 안에서 name이라고 적으면 매개변수에 접근하게 된다.
  • 멤버변수에 접근하려면 앞에 this.라고 해주면 된다.
    • this.는 인스턴스 자신의 참조값을 뜻한다.

this 제거

this를 사용하지 않으면,

this.name = name
name = name

name은 둘다 매개변수를 뜻하게 된다. 즉, 멤버변수의 갑이 변경되지 않는다.

  • 매개변수의 이름과 멤버 변수의 이름이 같은 경우 this를 사용해서 둘을 명확하게 구분해야 한다.
  • this는 인스턴스 자신을 가리킨다.

this의 생략

this는 생략할 수 있다. 변수를 찾을 때 가까운 지역변수(매개변수도 지역변수임)를 먼저 찾고 없으면 그 다음으로 멤버변수를 찾는다. 멤버변수도 없으면 오류 발생.

this와 코딩 스타일

this를 꼭 생략하지 않고 사용해도 된다. this를 사용하면 이 코드가 멤버 변수를 사용한다는 것을 눈으로 쉽게 확인할 수 있다. (매개변수와 멤버변수를 눈에 보이도록 구분)

생성자 - 도입

객체를 생성하고 이후에 바로 초기값을 할당해야 하는 경우가 많다. initMember(...)와 같은 메서드를 매번 만들어야 한다.
객체를 생성하자마자 즉시 필요한 기능을 수행할 수 있도록 생성자라는 기능을 제공한다. 생성자를 사용하면 객체를 생성하는 시점에 즉시 필요한 기능을 수행할 수 있다.

package construcct;

public class MemberConstruct {
    String name;
    int age;
    int grade;

    MemberConstruct(String name, int age, int grade) {
        System.out.println("생성자 호출 name = " + name + ", age = " + age + ", grade = " + grade);
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

다음이 생성자이다.

MemberConstruct(String name, int age, int grade) {
        System.out.println("생성자 호출 name = " + name + ", age = " + age + ", grade = " + grade);
        this.name = name;
        this.age = age;
        this.grade = grade;
}

생성자와 메서드의 차이

  • 생성자의 이름은 클래스의 이름과 같아야 한다. (첫 글자로 대문자로 시작)
  • 생성자는 반환 타입이 없다. 비워둬야 함
  • 나머지는 메서드와 같다.
package construcct;

public class ConstructMain1 {
    public static void main(String[] args) {
        MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
        MemberConstruct member2 = new MemberConstruct("user1", 16, 80);

        MemberConstruct[] members = {member1, member2};

        for (MemberConstruct m : members) {
            System.out.println("name : " + m.name + " age : " + m.age + " grade : " + m.grade);
        }
    }
}

생성자 호출

생성자는 인스턴스를 생성하고 나서 즉시 호출된다.
생성자를 호출하는 방법은 new 명령어 다음에 생성자 이름과 함께 매개변수에 맞춰 인수를 전달.
➡️ 인스턴스를 생성하고 즉시 해당 생성자르 호출한다.
참고로 new 키워드를 사용해서 객체를 생성할 때 마지막에 괄호 () 도 포함해야 하는 이유가 바로 생성자 때문이다. 객 체를 생성하면서 동시에 생성자를 호출한다는 의미를 포함한다.

생성자 장점

중복 호출 제거

생성자가 없던 시절에는 생성 직후에 어떤 작업을 수행하기 위해 다음과 같이 메서드를 직접 한번 더 호출해야 했다. 생성자 덕분에 객체를 생성하면서 동시에 생성 직후에 필요한 작업을 한번에 처리할 수 있게 되었다.

//생성자 등장 전
MemberInit member = new MemberInit(); member.initMember("user1", 15, 90);
//생성자 등장 후
MemberConstruct member = new MemberConstruct("user1", 15, 90);

제약 - 생성자 호출 필수

initMember(...) 를 실수로 호출하지 않으면 어떻게 될까? 이 메서드를 실수로 호출하지 않아도 프로그램은 작동한다. 하지만 회원의 이름과 나이, 성적 데이터가 없는 상태로 프로그 램이 동작하게 된다. 만약에 이 값들을 필수로 반드시 입력해야 한다면, 시스템에 큰 문제가 발생할 수 있다.

생성자의 진짜 장점은 객체를 생성할 때 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다는 점 이다. 참고로 생성자를 메서드 오버로딩 처럼 여러개 정의할 수 있는데, 이 경우에는 하나만 호출하면 된다.

MemberConstruct(String name, int age, int grade) {...}

직접 정의한 생성자를 호출하지 않으면 컴파일 오류가 발생한다.

생성자를 사용하면 필수값 입력을 보장할 수 있다

기본 생성자

 public class MemberInit {
     String name;
int age;
int grade;
}
 public class MethodInitMain1 {
     public static void main(String[] args) {
         MemberInit member1 = new MemberInit();
... }
}

여기서 new MemberInit() 이 부분은 매개변수가 없는 다음과 같은 생성자가 필요하다.

public class MemberInit {
	String name;
    int age;
    int grade;
    
    MemberInit() { // 기본 생성자
    }

기본 생성자

  • 매개변수가 없는 생성자를 기본 생성자라고 한다.
  • 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으로 만들어준다.
  • 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.
package construcct;

public class MemberDefault {
    String name;
}
package construcct;

public class MemberDefaultMain {
    public static void main(String[] args) {
        MemberDefault memberDefault = new MemberDefault();
    }
}

MemberDefault 클래스에는 생성자가 하나도 없으므로 자바는 자동으로 다음과 같은 기본 생성자를 만들어준다. (우리 눈에 보이지는 X)

 package construct;
 public class MemberDefault {
	String name;
    
	//기본 생성자
	public MemberDefault() { 
    }
}

c.f 자바가 자동으로 생성해주는 기본 생성자는 클래스와 같은 접근 제어자를 가진다.(public)

기본 생성자를 왜 자동으로 만들어줄까?

생성자 기능을 사용하지 않는 경우도 많기 때문이다.

정리

  • 생성자는 반드시 호출되어야 한다.
  • 생성자가 없으면 기본 생성자가 제공된다.
  • 생성자가 하나라도 있으면 기본 생성자가 제공되지 않는다.

생성자 - 오버로딩과 this()

생성자도 메서드 오버로딩처럼 매개변수만 다르게 해서 여러 생성자를 제공할 수 있다.

package construcct;

public class MemberConstruct {
    String name;
    int age;
    int grade;

    //추가
    MemberConstruct(String name, int age) {
        this.name = name;
        this.age = age;
        this.grade = 50;
    }
    
    MemberConstruct(String name, int age, int grade) {
        System.out.println("생성자 호출 name = " + name + ", age = " + age + ", grade = " + grade);
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

새로 추가한 생성자는 grade를 받지 않는다. (대신 grade는 50이 됨)

package construcct;

public class ConstructMain2 {
    public static void main(String[] args) {
        MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
        MemberConstruct member2 = new MemberConstruct("user2", 16);

        MemberConstruct[]  members = {member1, member2};

        for (MemberConstruct m : members) {
            System.out.println(" name : " + m.name + " age : " + m.age + " grade : " + m.grade);
        }
    }
}


생성자를 오버로딩 함 - 성적 입력이 꼭 필요한 경우에는 grade 가 있는 생성자를 호출, 그렇지 않은 경우에는 grade 가 없는 생성자를 호출하면 된다. grade 가 없는 생성자를 호출하면 성적은 50 점이 된다.

this()

근데 두 생성자의 코드 중복을 제거하려면?
이때 this() 라는 기능을 사용하면 생성자 내부에서 자신의 생성자를 호출할 수 있다. 참고로 this 는 인스턴스 자신 의 참조값을 가리킨다. 그래서 자신의 생성자를 호출한다고 생각하면 된다.

package construcct;

public class MemberConstruct {
    String name;
    int age;
    int grade;

    //추가
    MemberConstruct(String name, int age) {
        this(name, age, 50); // 변경
    }

    MemberConstruct(String name, int age, int grade) {
        System.out.println("생성자 호출 name = " + name + ", age = " + age + ", grade = " + grade);
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

위와 같이 첫 번째 생성자 내부에서 두 번째 생성자를 호출한다.

 MemberConstruct(String name, int age) -> MemberConstruct(String name, int age,
int grade)

this() 규칙

  • this()생성자 코드의 첫줄에만 작성할 수 있다.
    위반할시 컴파일 오류 발생!!

문제와 풀이

문제 - Book과 생성자

package construcct.ex;

public class Book {
    String title;
    String author;
    int page;

    Book() {
        this("", "", 0);
    }
    Book(String title, String author) {
        this(title, author, 0);
    }

    Book(String title, String author, int page) {
        this.title = title;
        this.author = author;
        this.page = page;
    }

    void displayInfo() {
        System.out.println("title : " + this.title + ", author : " + this.author + ", page : " + this.page);

    }
}
package construcct.ex;

public class BookMain {
    public static void main(String[] args) {
        Book book1 = new Book();
        book1.displayInfo();

        Book book2 = new Book("hello java", "seo");
        book2.displayInfo();

        Book book3 = new Book("jpa programming", "kim", 700);
        book3.displayInfo();
    }
}

정리

생성자는 객체 생성 직후 객체를 초기화 하기 위한 특별한 메서드이다.

profile
웹 백엔드와 클라우드 정복을 위해 탄탄한 기반을 쌓아가고 있는 예비개발자입니다. 'IT You Up'은 'Eat You Up'이라는 표현에서 비롯되어, IT 지식을 끝까지 먹어치운다는 담고 있습니다.

0개의 댓글