Class
어떠한 물체를 코드로 구현해 추상화시킨 개념.
Object
추상화시킨 개념인 Class가 구체적인 실체로 만들어진 것.
지난번 글에서는 Java 클래스와 객체에 대해 설명했고 이어서 변수의 종류와 생성 시기를 이야기했습니다. 이번 글에서는 클래스 생성자와 변수들의 초기화 과정에 대해 이야기해보겠습니다.
생성자 선언하기
생성자란 인스턴스가 생성될 때 호출되는 "초기화 메소드" 입니다. 인스턴스가 new를 통해 생성될 때 자동으로 가장 먼저 호출되는 클래스의 메소드이기 때문에 보통 초기화 과정을 작성합니다. 그렇다면 직접 코드에서 어떻게 작동을 하는지 알아보겠습니다. 이전 글에서 사용했던 Animal 클래스와 main 메소드를 참고하겠습니다. Animal 클래스의 기타 메소드들은 생략했다는 점 알아주세요.
// Animal.java
public class Animal {
static String species = "animal";
private String name = "";
private int height;
private int age;
// Overloading
// Constructor 1
Animal(){
}
// Constructor 2
Animal(int height, int age, String name){
this.height = height;
this.age = age;
this.name = name;
}
}
// Main.java
public class Main {
public static void main(String[] args) {
Animal tiger1 = new Animal();
tiger1.set_height(100);
tiger1.set_age(7);
tiger1.set_name("tiger1");
tiger1.print_info();
Animal tiger2 = new Animal(200,10,"tiger2");
tiger2.print_info();
}
}
Animal 클래스에 위와 같이 생성자들을 생성했습니다. 생성자를 만드는 방법은 클래스 이름으로 메소드를 정의한다고 생각하면 쉽게 이해할 수 있습니다. 위의 예시에서는 Animal 클래스의 이름과 동일하게 Animal 이라는 이름의 메소드처럼 정의했습니다. 생성자를 2개를 만들었는데 눈치 채신분들도 있겠지만 생성자도 overloading이 가능합니다. 그래서 1) parameter가 하나도 없는 생성자, 2) parameter가 3개로 이루어진 생성자를 동시에 선언해도 문법적으로 에러가 나지 않습니다.
main 메소드에서처럼 생성자가 있다면 new를 통한 인스턴스 생성과 동시에 인스턴스 변수들의 값을 할당할 수 있습니다. 좀 더 자세하게 보자면 tiger1 객체는 파라미터가 없는 생성자가 실행되어 아무런 코드가 실행되지 않았고 직접 메소드를 통해 인스턴스 변수들에 값을 할당시켰습니다. 하지만 tiger2 객체의 경우 3개의 argument를 생성자에 넘겨줌으로써 불필요한 메소드 사용을 생략할 수 있었습니다.
생성자의 특징
생성자는 여러가지 특징을 가지고 있습니다.
1) 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다.
모든 클래스는 하나 이상의 생성자가 있어야 하는데 이전 글을 봤다면 이러한 의문이 들 수 있습니다. 이전 글에서는 생성자 선언을 따로 하지 않았는데 잘못된 것 아닌가? 맞습니다 이전 글에서는 생성자 선언을 따로 하지 않았습니다. 그럼에도 불구하고 프로그램을 동작하는데 어떠한 에러도 발생하지 않았던 이유는 컴파일러와 관련 있습니다. 자바 컴파일러는 클래스에 생성자가 하나도 없다면 내용이 없는 기본 생성자를 추가합니다. 그래서 제가 생성자를 따로 선언하지 않았지만 실제로는 빈 내용의 생성자가 존재한겁니다.
여기서 주의할 점이 있습니다. 하나 이상의 생성자가 존재한다면 기본 생성자가 생성되지 않는다는 점입니다. 즉 코드 작성자가 생성자를 선언했다면, 실제로 클래스의 객체를 new를 통해 생성할 때 선언된 생성자 중 하나를 꼭 이용해야 한다는 점입니다. 위의 예시 코드에서도 제가 parameter도 없고 내용도 없는 기본 생성자를 굳이 선언한 이유이기도 합니다. 생성자 2를 선언하고 기본 생성자를 선언하지 않았다면 main 메소드에서 에러가 났을 겁니다.
2) 생성자에서 다른 생성자를 호출하려면 this()를 이용해야 한다.
생성자 호출은 객체를 생성할 때를 제외하고는 직접적으로 호출할 수 없습니다. 이는 생성자 내부에서도 마찬가지입니다. 하지만 그 대신에 생성자 내부에서 this()를 이용하여 호출할 수 있습니다. 간단한 예시 코드를 보며 넘어가겠습니다. ( 나중에 공부하게 될 "상속"의 내용에서도 상위 클래스의 생성자를 호출할 때 super()를 이용하는데 비슷한 이치입니다. )
참고로 클래스 내부에서 메소드 개념의 this()와 달리 참조변수로써 this를 사용할 수 있는데, 이는 실제 클래스의 코드를 실행하는 객체 자기 자신을 뜻합니다. 이전 글에서 print_info() 메소드 내용을 적었는데 인스턴스 변수들을 출력할 때 this를 사용했습니다. 즉 tiger1과 tiger2의 객체가 가지는 인스턴스 변수 값이 서로 다르기 때문에 동일한 메소드를 수행했음에도 불구하고 출력 결과가 다르게 나온 겁니다.
클래스 내부 변수 초기화
이전 글에서 공부한 클래스 변수, 인스턴스 변수들과 같이 클래스 내부의 변수들을 초기화하는 방법은 여러 가지가 있습니다. 가장 기본적으로 변수가 만들어지면서 클래스 변수와 인스턴스 변수들은 변수 타입에 따라 아래와 같이 기본 값을 다르게 가집니다.
변수들을 실제로 사용하기 이전에 미리 특정 값을 대입시키는 것을 초기화라고 하는데, 초기화의 방법은 명시적 초기화, 초기화 블럭이 있습니다. ( 인스턴스 변수의 경우 생성자를 통한 초기화 방법 추가 ) 명시적 초기화는 위의 예시 코드에서와 같이 변수 선언과 동시에 값을 대입하는 것을 말합니다. 그리고 초기화 블럭의 경우는 {} 중괄호를 통해 블럭을 만들고 그 안에서 변수의 값을 대입하는 것을 말합니다. 변수들의 각 초기화 방법에 따른 순서와 아래와 같습니다.
- 변수 생성 시 기본 값 할당
- 명시적 초기화를 통한 값 할당
- 초기화 블럭을 통한 값 할당
- 생성자를 통한 값 할당
지금까지 생성자와 클래스 내부 변수들의 초기화 방법 및 순서에 대해 알아봤습니다. 다음 글부터는 주제를 바꾸어 상속에 대한 내용을 공부하도록 하겠습니다.
'Computer Science > Java' 카테고리의 다른 글
[Java] Java Class 및 Object #1 - 변수 종류와 생성 시기 (1) | 2021.07.25 |
---|