Java

[인프런] 생성자, this

sejin2 2024. 5. 21. 14:34

생성자

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

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 s : members) {
            System.out.println("이름 : " + s.name + "나이 : " + s.age + ", 성적 : " + s.grade );
        }
    }
}

위 코드에서는 회원의 초기값을 설정하는 부분이 계속 반복된다. 메서드를 사용해 반복된 부분은 제거해보도록 한다. 

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

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

        MemberInit[] members = {member1, member2};

        for (MemberInit s : members) {
            System.out.println("이름 : " + s.name + "나이 : " + s.age + ", 성적 : " + s.grade );
        }
    }
    static void initMeber(MemberInit member, String name, int age, int grade) {
        member.name = name;
        member.age = age;
        member.grade = grade;
    }
}

initMeber ( ) 라는 메서드를 생성해 회원의 초기값을 설정하는 부분의 반복을 줄여주었다. 
이 메서드는 대부분 MemberInit 객체의 멤버 변수를 사용한다. 이런 경우 속성과 기능을 한 곳에 두는 것이 더 나은 방법이다. 즉, MemberImit이 자기 자신의 데이터를 변경하는 기능을 제공하는 것이 좋다.  

this

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

    // 추가
    void initMember(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

이름이 같을 때 멤버 변수의 값을 넣어주고 싶으므로 this를 사용해 주어야 한다. 그러면 자기 자신의 인스턴스를 가리키게 된다. 

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 s : members) {
            System.out.println("이름 : " + s.name + "나이 : " + s.age + ", 성적 : " + s.grade );
        }
    }
}

initMember( ) 메서드는 Member에 초기값 설정 기능을 제공하는 메서드로, 위와 같이 메서드를 호출하면 객체의 멤버 변수에 인자로 넘어온 값을 채우게 된다.
initMember( ) 메서드를 보면, 메서드의 매개 변수에 정의한 String name과 Member의 멤버 변수의 이름이  String name으로 둘다 똑같다. 나머지 변수들도 모두 이름이 같다.

이처럼 멤버 변수와 매개변수의 이름이 같을 때 이를 구분하기 위해 this를 사용해준다.
initMember( ) 메서드에서는 멤버 변수보다 매개변수가 우선순위를 가진다. 따라서 해당 메서드 안에서 name이라고 적으면 매개변수에 접근하게 되는데, 멤버 변수에 접근을 하고 싶으면 this.을 붙여 주어야 한다. this.을 붙이면 인스턴스 자신의 참조값을 가리키게 된다

this의 생략

this는 생략이 가능하다. 이 경우 변수를 찾을 때 가까운 지역변수 ( 매개변수도 지역변수임 )를 먼저 찾고, 없으면 그 다음으로 멤버 변수를 찾는데, 만약 멤버 변수도 없다면 오류가 발생하게 된다. 

public class MemberThis {
    String nameFiled;

    void initMember(String nameParameter) {
        nameFiled = nameParameter;
    }
}

 

nameFiled는 매개변수(지역변수)에 없기 때문에 멤버 변수에서 찾아와서 사용이 된다. 이러한 경우에 this. 가 생략되었다고 볼 수 있다. 

생성자 - 도입

대부분의 객체 지향 언어는 객체를 생성하자마자 즉시 필요한 기능을 좀 더 편리하게 수행할 수 있도록 생성자라는 기능을 제공한다. 생성자를 사용하면 객체를 생성하는 시점에 즉시 필요한 기능을 수행할 수 있다.

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;
    }
}

생성자의 이름은 클래스 이름과 같아야 한다. 따라서 첫 글자가 대문자로 시작한다.
생성자는 반환 타입이 없다. 비워두어야 한다.

public class ConstructMain1 {
    public static void main(String[] args) {
        MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
        // 객체를 생성함(메모리에 올림)과 동시에 생성자를 호출해 실행해준다.
        MemberConstruct member2 = new MemberConstruct("user2", 16, 80);

        MemberConstruct[] members = {member1, member2};

        for (MemberConstruct s : members) {
            System.out.println("이름 : " + s.name + ", 나이 : " + s.age + ", 성적 : " + s.grade );
        }
    }
}

객체가 생성되어 메모리 할당한 다음에 생성자 호출하면서 값을 세팅해준다.

생성자는 인스턴스를 생성하고나서 즉시 호출된다. 생성자를 호출하는 방법은 다음 과 같이 new 명령어 다음에 생성자 이름과 매개변수에 맞추어 인수를 전달해주면 된다.

생성자의 장점

- 중복 호출 제거
생성자가 없을 때에는 생성 직후에 어떤 작업을 수행하기 위해 메서드를 직접 한번 더 호출해야 했지만, 생성자 덕분에 객체를 생성하면서 동시에 생성 직후에 필요한 작업을 한번에 처리할 수 있게 되었다.
- 생성자 호출 필수
객체를 생성할 때 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다.
생성자를 메서드 오버로딩 처럼 여러 개 정의할 수 있는데, 이 경우에는 하나만 호출하면 된다. 
직접 정의한 생성자를 호출하지 않으면 컴파일 오류가 발생하는데, 컴파일 오류는 IDE에서 즉시 확인할 수 있는 좋은 오류이다. 이 경우에 개발자는 객체를 생성할 때, 직접 정의한 생성자를 필수로 호출해야 한다는 것을 바로 알 수 있다. 

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

기본 생성자

생성자를 생성한 적이 없는 데, 생성자를 호출한 적이 있다 ! 

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

기본 생성자를 자바에서 자동으로 만들어 주는 이유는 생성자 기능을 사용하지 않는 경우도 많기 때문에 편의 기능을 제공하는 것이다. 자바에서 생성자를 만들어주지 않으면 모든 클래스에 개발자가 직접 기본 생성자를 정의해야 한다.

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

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;
    }
}

name과 age를 가지고 있는 생성자를 하나 더 추가해준다.

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 s : members) {
            System.out.println("이름 : " + s.name + ", 나이 : " + s.age + ", 성적 : " + s.grade );
        }
    }
}

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

this를 사용하여 중복을 제거해주기 ! 

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;
    }
}

위의 코드처럼 this ( ) 라는 기능을 사용하면 생성자 내부에서 자신의 생성자를 호출할 수 있다. 
this는 인스턴스 자신의 참조값을 가리키기 때문에 자신의 생성자를 호출한다고 생각하면 된다.

this( ) 규칙 
- 생성자 코드의 첫줄에만 작성할 수 있다. 

 

 

공부 내용: [인프런] 김영한의 실전 자바 - 기본편

'Java' 카테고리의 다른 글

[인프런] 접근 제어자  (0) 2024.05.22
[인프런] 패키지  (0) 2024.05.22
[인프런] 객체 지향 프로그래밍  (0) 2024.05.21
[인프런] 클래스와 메서드  (0) 2024.05.21
[인프런] 절차 지향 프로그래밍  (0) 2024.05.21