개체 생성 시 멤버 데이터의 초기화
C
human_t* adam = (human_t*)malloc(sizeof(human_t));
// adam->name: 쓰레기 값
// adam->age: 쓰레기 값
// adam->sec: 쓰레기 값
printf("%d\n", adam->age);
- C 구조체의 변수는 선언 시 초기화가 안됨
- 메모리에 남아있던 쓰레기 값이 그대로 유지됨
Java
Human adam = new Human();
// adam.name: null
// adam.age: 0
// adam.sex: null
System.out.printf("%d", adam.age);
- Java는 0에 준하는 값으로 초기화해 줌
- int는 0
- float은 0.0
- 참조형은 null로
public class Human{
public String name;
public int age = 20;
public Sex sex;
//...
}
- 0이 아닌 다른 값으로 초기화하고 싶다면 선언문에 대입 가능
Java에는 free()가 없다
- Java는 가비지 컬렉션(GC) 기능을 지원
- JVM에 내장된 가비지 컬렉터가 알아서 가비지(쓰레기)를 지워줌
- 가비지란? 더 이상 사용되지 않는 개체(힙 메모리)
- 프로그래머가 직접 메모리를 해제하지 않는다
- C#도 가비지 컬렉션을 지원
- 매니지드(managed) 언어는 보통 자동으로 메모리를 관리해줌
GC의 단점
- GC가 메모리를 수집하는 시점을 알 수 없음
- 모든 개체의 사용 여부를 판단하는 게 그리 빠른 연산이 아님
- 이러한 이유로 자원이 한정적인 시스템에는 적합하지 않음
- 메모리 해제를 프로그래머가 직접 할 경우 이런 문제가 없음
- 자동 메모리 관리 하에서 발생하는 메모리 누수도 존재
- 즉, 자동 메모리 관리도 메모리 누수에서 100% 자유로울 수 없음
생성시 올바른 값으로 초기화하기
public class Human{
public String name;
public int age;
public Sex sex;
public Human(String name, int age, Sex sex){
this.name = name;
this.age = age;
this.sex = sex;
}
// ...
}
Human adam = new Human("adam", 20, Sex.MALE);
Human fiona = new Human("fiona", 20, Sex.FEMALE);
System.out.printf("Name: %s, Age: %d%s", adam.name, adam.age, NEW_LINE);
System.out.printf("Name: %s, Age: %d%s", fiona.name, fiona.age, NEW_LINE);
- 생성자라는 특별한 메서드가 이런 일을 담당
- 개체 생성 시에 자동으로 호출되는 특수한 함수
- 반환형: 없음(void가 아님!)
- 함수명: 클래스명과 동일
오버로딩도 가능
public Human(String name, Sex sex){
this.name = name;
this.sex = sex;
// age의 초기값은 그대로 0
}
public Human(String name, int age, Sex sex){
this.name = name;
this.age = age;
this.sex = sex;
}
코드 중복을 피하는 법
public Human(String name, Sex sex){
this(name, sex == Sex.MALE ? 1 : 5, sex);
}
- 매개변수 수가 적은 생성자에서 매개변수 수가 많은 생성자를 호출
- this()를 이용하며 다른 생성자를 호출할 수 ㅗ있음
기본 생성자(default constructor)
public <클래스명>() {...}
- 프로그래머가 생성자를 하나도 안 만들 경우 자동으로 생기는 생성자
- 컴파일러가 알아서 매개변수 없는 생성자를 만들어 줌
- 기본 생성자의 함수 바디(body)는 비어 있음
- 각 멤버 함수는 이미 0에 준하는 값으로 초기화됐기에 괜찮음
- 프로그래머가 생성자를 제공하면 기본 생성자는 생기지 않음(중요!!!)
생성자로 초기화를 해야 하는 이유
- 개념 상의 문제
- 후조건의 문제
- 생성자도 함수. 따라서 선조건과 후조건이 적용
- 생성자의 후조건: '개체의 상태는 개체 생성과 동시에 유효하다'
- 사용자를 고려 안 한 문제
- 사용자란?
- 내가 만든 클래스를 사용하는 코드 혹은 프로그래머
- 나 자신이 될 수도 남이 될 수도 있음
- 문제: 사용자의 실수를 유발
- 클래스에 있는 어떤 멤버 변수를 초기화해야 하는가?
- 어떤 값으로 초기화해야 하는가?
- 나중에 멤버 변수가 추가될 때 기존의 초기화 코드들을 업데이트 안 하면?
어떤 멤버 변수를 초기화해야 하는가?
- 클래스가 저장되어 있는 파일을 열어서 봐야 함
- 어떤 멤버 변수를 초기화해줘야 하는지 모를 수도 있음
- 나중에 멤버 변수가 추가되는 것에 대응하기 어려움
어떤 값으로 초기화해줘야 하는가?
- 그 분야를 잘 아는 사람만 알 수 있는 내용이 있음
- 초기화에 어떤 계산이 필요한 경우 코드가 중복됨
외부 라이브러리를 사용하면 더 심각한 문제
- .class 파일만 제공됨
- 클래스 선언이 있는 소스파일을 열어볼 수 없음
- 뭐든 간에 여태까지 본 문제는 모두 생성자로 해결 가능
결론: 생성자는 개체를 만들어주는 계약이다!
- 함수 시그내처와 마찬가지
- 즉, 타 과목에서 올바른 함수 작성법이라 배웠던 내용이 모두 적용
- 함수는 블랙박스
- 호출자와 함수의 분명한 책임 분리
즉, 외부에서 클래스 내부의 데이터를 알 필요가 없음
이게 바로 데이터 추상화(캡슐화의 일부이기도 함)
이 개념은 생성자 뿐만 아니라 모든 메서드에도 적용
'프로그래머 > Java Managed Programming' 카테고리의 다른 글
[개체지향 프로그래밍] 개체 모델링 | 클래스 다이어그램 | 유연성 | OOP (0) | 2021.02.13 |
---|---|
[개체지향 프로그래밍] 접근 제어자 | getter/setter | 캡슐화 | 추상화 (0) | 2021.02.07 |
[개체지향 프로그래밍] 클래스(class) | 접근 제어자(public, private) | 인스턴스(instance) (0) | 2021.02.07 |
[개체지향 프로그래밍] 개체지향 프로그래밍이란? | 개체지향 프로그래밍의 필요성 | 개체지향 프로그래밍 특성 (0) | 2021.01.17 |
[포프 tv 복습] Java 기본 문법, Java와 C,C#의 차이 (0) | 2021.01.10 |