필드는 객체의 속성을 저장하는 변수입니다. 필드는 클래스 내부에 존재하며 클래스의 라이프 싸이클을 같이 합니다. 필드는 클래스에서 굉장히 중요한 부분이고 클래스를 이해하는데 필수적인 부분이기 때문에 지금부터 설명하는 부분에 대해 잘 이해를 해야합니다. 이전 포스팅에서 클래스에 대해 배워봤지만 예제없이 단순히 개념에 대한 설명이었기 때문에 이해하기 힘들었지만 클래스의 가장 중요한 필드, 생성자와 메소드를 이해함으로써 클래스에 대해 쉽게 이해할 수 있을 것입니다.
필드 선언
필드 선언은 클래스 중괄호 {} 항목 어디서든 존재할 수 있습니다. 생성자 선언과 메소드 선언의 앞과 뒤 어떤 곳에서도 필드 선언이 가능합니다. 하지만 생성자와 메소드 중괄호 {} 블록 내부에는 선언 될 수 없습니다. 생성자와 메소드 중괄호 {} 블록 내부에 선언된 것은 모두 로컬 변수가 됩니다. 필드 선언은 변수의 선언 형태와 비슷합니다. 초기값이 지정되지 않은 필드는 객체 생성 시 자동으로 기본 초기값으로 설정됩니다. 필드의 타입에 따라 기본 초기값이 다른데, 다음 표는 필드 타입별 기본 초기값을 보여줍니다.
분류 |
타입 | 초기값 |
|
기본타입 |
정수 타입 |
byte char short int long | 0 \u0000 0 0 0L |
실수 타입 |
float double | 0.0F |
|
논리 타입 |
boolean | false |
|
참조 타입 | 배열 클래스(String 포함) 인터페이스 | null null |
초기값을 외우려고 하지말고 0이 들어간다고 생각하시면 됩니다. 그냥 0이아닌 모든 bit에 0으로 초기화된다고 생각하시면 됩니다. 그게 정수에서는 0이고 boolean에서는 false이고 배열에서는 null입니다.
필드 사용
필드를 사용하는 것은 필드값을 읽고 변경하는 작업을 말합니다. 클래스 내부의 생성자나 메소드에서 사용할 경우 단순히 필드이름으로 읽고 변경하면 되지만, 클래스 외부에서 사용할 경우 우선적으로 클래스로부터 객체를 생성한 뒤 필드를 사용해야 합니다. 그 이유는 필드가 객체에 소속된 데이터이므로 객체가 존재하지 않으면 필드는 존재하지 않기 때문입니다. 예제를 통해 살펴보도록 하겠습니다.
위의 예제를 보면 2개의 소스화일이 있습니다. Car.java와 CarExample.java가 있습니다. Car.java는 Car 클래스를 선언합니다. 단순히 클래스를 선언만 하고 실행하는 코드는 없습니다. 2번째 소스화일은 첫번째 소스화일에서 선언된 Car 클래스를 이용해서 필드를사용하는 것을 나타낸 것입니다. Car 클래스는 5개의 필드가 있으며 4개는 초기값을 지정하고 마지막 speed는 초기화하지 않았습니다. 그래서 자동으로 초기값 0이 지정되었습니다. 필드값을 사용하기 위해서 myCar라는 클래스변수를 선언하고 new 연산자를 사용해서 Car 클래스를 객체화하였습니다. 이제는 객체인 myCar를 이용해서 필드에 접근할 수 있습니다. 값을 읽을 수도 쓸 수도 있습니다. 이렇듯 필드를 사용하기 위해서는 먼저 클래스를 객체로 만들고 객체를 이용해서 필드를 사용할 수 있습니다. 이는 메소드도 마찬가지입니다. 클래스는 설계도이므로 클래스 내부에 있는 것을 사용하기 위해서는 먼저 실체화를 해야합니다. new 연산자는 설계도에 불과한 클래스를 메모리에 할당하고 실제로 사용할 수 있도록 합니다. 필드는 변수와 마찬가지로 사용할 수 있지만 myCar라는 클래스변수를 이용해야합니다. 메소드도 마찬가지입니다. 도트 연산자(.)를 이용해서 필드와 메소드에 접근할 수 있습니다.
생성자는 new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당합니다. new 연산자에 의해 생성자가 성공적으로 실행되면 힙 영역에 객체가 생성되고 객체의 번지가 리턴욉니다. 리턴된 객체의 번지는 클래스 변수에 저장됩니다.
기본 생성자
모든 클래스는 생성자가 반드시 존재하며, 생성자를 하나 이상 가질 수 있습니다. 클래스 내부에 생성자 선언을 생략했다면 컴파일러는 다음과 같이 중괄호 {} 블록 내용이 비어있는 기본생성자(Default Constructor)를 바이트 코드에 자동 추가합니다.
[public] 클래스() {}
이전 Car 클래스 소스에 생성자가 없지만 컴파일러가 자동으로 기본 생성자를 넣어줍니다. 그래서 위의 Car 클래스에 다음과 같은 내용이 추가됩니다.
public Car() { }
하지만 클래스에 명시적으로 선언한 생성자가 1개라도 있으면 컴파일러는 기본 생성자를 추가하지 않습니다.
생성자 선언
기본 생성자 대신 우리가 생성자를 명시적으로 선언하려면 다음과 같은 형태로 작성하면 됩니다.
클래스(매개변수1, 매개변수2, ...) {
초기화 코드
}
생성자와 메소드는 비슷한 모양을 가지고 있습니다. 하지만 생성자는 리턴 타입이 없고 클래스 이름과 동일합니다. 생성자 블록 내부에는 객체 초기화 코드가 작성되는데, 일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 존재를 합니다. 매개 변수 선언은 생략할 수도 있고 여러 개를 선언해도 좋습니다. 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 합니다.
첫번째 소스화일을 보면 생성자를 추가해놓았습니다. 이 생성자는 color와 speed를 초기화하도록 했습니다. 필드를 선언했을 때 초기화를 한 것을 생성자 초기화로 인해 값이 바뀌게 됐습니다. 라인 5를 보면 주석으로 막아놓았는데 이는 컴파일 오류때문입니다. 왜냐하면 Car 클래스에는 기본생성자가 없기 때문입니다. 명시적으로 생성자를 선언하면 컴파일러는 더 이상 생성자를 추가하지 않습니다. 라인 5의 오류를 없애려면 Car 클래스에 기본 생성자를 추가시켜 놓으면 됩니다. 위의 예제에서 생성자 안에서 this를 사용했습니다. 이 this는 자기 객체를 가르키는 변수입니다. 위의 생성자는 color와 speed를 초기화하는데 매개변수 color와 필드 color의 이름이 같기 때문에 필드는 this.color로 사용하고 매개변수는 그냥 color를 사용했습니다. 뒤의 speed도 마찬가지 입니다. 생성자나 메소드를 선언할 때 이렇게 선언합니다. 매개변수의 이름과 필드의 이름이 같아야 변수를 이해하기 쉽기때문입니다.
필드 초기화
클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정됩니다. 만약 다른 값으로 초기화하고 싶다면 두가지 방법이 있습니다. 하나는 필드를 선언할 때 초기값을 주는 방법이고, 또 다른 하나는 생성자에서 초기값을 주는 방법입니다. 필드를 선언할 때 초기값을 주게 되면 동일한 클래스로부터 생성되는 객체들은 모두 같은 값을 갖게 됩니다. 물론 객체 생성 후 초기값을 변경할 수 있지만 생성 시점에서는 모든 필드값이 같습니다. 하지만 객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 한다면 생성자에서 초기화해야 합니다.
위의 예제에서 필드 nation은 "대한민국"으로 초기화되어있어 k1이나 k2 모두 같습니다. 하지만 생성자에서 name과 ssn을 초기화하면 값을 생성할 때마다 다른 값을 전달하여 초기화할 수 있습니다. 위의 프로그램에서 k1과 k2를 생성할 때 생성자를 통해 name과 ssn에 다른 값을 전달했습니다. 그래서 k1의 name과 ssn을 출력값이라 k2의 name과 ssn이 다릅니다.
생성자 오버로딩
외부에서 제공되는 다양한 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양화될 필요가 있습니다. 클래스에 필드가 여러 개 있을 때 다양하게 초기화하려면 여러개의 생성자가 필요합니다. 그래서 자바는 다양한 방법으로 객체를 생성할 수 있도록 생성자 오버로딩(Overloading)을 제공합니다. 생성자 오버로딩이란 매개변수를 달리하는 생성자를 여러 개 선언하는 것을 말합니다. 예제를 통해 살펴보도록 하겠습니다.
클래스 Car에서 4개의 생성자를 선언했습니다. company 필드는 선언에서 이미 초기화를 했기때문에 생성자에서 초기화를 하지 않아도 "현대자동차"로 초기화되어있습니다. 다른 필드들은 생성자를 호출할 때 초기화됩니다. 생성자별로 초기화되는 필드는 다릅니다. 필드 선언에서 초기화되지 않고 생성자에서도 초기화되지 않은 필드는 위에서 설명한 기본 초기값으로 초기화됩니다. 이 생성자 오버로딩은 굉장히 많이 쓰이며 이 오버로딩이라는 개념은 생성자가 아닌 메소드에서도 사용되니 잘 알아두시는 것이 좋습니다. 오버로딩은 기본적으로 메소드 이름은 같지만 리턴 타입, 매개변수 갯수, 매개 변수 타입 등이 다른 것을 말합니다. 자세한 내용은 나중에 오버로딩에서 설명하도록 하겠습니다.
'프로그래밍 > Java 프로그래밍' 카테고리의 다른 글
자바 인스턴스 멤버와 정적 멤버 (0) | 2020.07.10 |
---|---|
자바의 메소드 (0) | 2020.07.09 |
자바 클래스 (0) | 2020.07.06 |
자바의 열거타입 (0) | 2020.07.05 |
자바의 배열과 향상된 for문 (0) | 2020.07.04 |