chapter 6
클래스의 구조
필드(Field)
필드(Field)는 객체의 고유데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳이다. 자동차 객체를 예로 들어보면 모델, 색깔은 고유 데이터에 해당하고, 현재 속도, 엔진 회전 수는 상태 데이터에 해당한다. 그리고 차체, 엔진, 타이어는 부품에 해당한다. 따라서 자동차의 클래스를 구현하려면 이러한 정보들을 필드로 선언해야한다.
public class Car { //클래스 Car
// 고유 데이터
String model;
String color;
// 상태 데이터
int speed;
int rpm;
//부품
Body body;
Engine engine;
Tire tire;
}
필드 선언
-
필드 선언은 클래스 중괄호 {} 블록 어디서든 존재할 수 있다. 생성자 선언과 메소드 선언 앞과 뒤 어떤 곳에서도 필드 선언이 가능하다. => 하지만 생성자와 메소드 중괄호 블록 내부에는 선언될 수 없다. 내부에 선언된다면 그건 필드가 아니라 로컬 변수(스택에 있는)이기 때문이다.
-
필드의 타입은 원시타입(primitive type)과 참조타입(reference type)이 모두 올 수 있다.
필드의 초기값은 필드 선언시 주어질 수 있고, 생략할수 있는데, 선언만 하고 초기화하지 않는다면 필드들은 객체 생성 시 자동으로 기본 초기값으로 설정된다.
분류 | 데이터타입 | 초기값 | |
---|---|---|---|
기본타입 | 정수 타입 | byte | 0 |
char | \u0000 (빈 공백) | ||
short | 0 | ||
int | 0 | ||
long | 0L | ||
실수 타입 | float | 0.0F | |
double | 0.0 | ||
논리 타입 | boolean | false | |
참조 타입 | Reference type | 배열 | null |
클래스(String 포함) | null | ||
인터페이스 | null |
필드 사용
- 외부 클래스 에선 .필드명을 이용해 필드를 사용하고 단지 필드명을 입력하여 사용한다.
//Car 클래스 (내부 클래스)
public class Car{
//필드
int speed;
// 생성자
Car (){
speed = 0; // -> 도트(.) 없이 사용, 값 변경
}
//메소드
void method(){
speed = 10; // 메소드 호출되면 필드 speed의 값이 10으로 변경.
}
}
//Person 클래스 (외부 클래스)
public class Person{
void method(){
// Car 객체 생성
Car myCar = new Car();
// 필드 사용
myCar.speed =60; // -> 도트(.)을 사용한다.
}
}
생성자(Constructor)
- 생성자(Constructor)는 new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.
(객체 초기화란 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말한다.)
=> 생성자를 실행시키지 않고 객체를 만들 수 없다. new 연산자에 의해 생성자가 성공적으로 실행되면 heap영역에 객체가 생성되고, new 연산자에 의해 객체의 주소값이 리턴되어 변수가 객체를 참조(사용)할 수 있지만, 먄약 생성자가 매개변수의 잘못된 입력으로 인해 제대로 실행되지 않으면(즉, 에러) 객체는 생성되지 않는다.
기본 생성자(Defualt Constructor)
- 모든 클래스에는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다. 클래스 내부에 생성자가 생략되었다면, 컴파일러는 기본 생성자(DefaultConstructor)를 바이트 코드에 자동 추가시킨다.
기본 생성자
[public] 클래스(){
}
=> 클래스가 public class로 선언되면 기본 생성자에도 public이 붙지만, 클래스가 public이 붙지 않으면 생성자도 public이 붙지 않는다.(명심!)
- 클래스에 명시적으로 선언한 생성자가 하나라도 있으면, 컴파일러는 기본 생성자(Defualt Constructor)를 추가하지 않는다.
- 명시적으로 생성자를 선언하는 이유는 객체를 다양하게 초기화하기 위해서다. => 생성자 오버로딩(Overloading)
생성자 선언
- 생성자는 메소드와 비슷한 모양이지만, 리턴 타입이 없고 생성자 이름은 클래스 이름과 동일하다.
- 생성자 블록 내부에는 객체 초기화 코드가 작성되는 데, 일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 준비를 한다.
생성자 선언부로 생성자가 어떻게 작성되는 지 알아보자
Car mycar = new Car("그랜저", "검정", 300);
public class Car{
// 생성자
Car(String model, String color, int maxSpeed){
//...
}
}
// 생성자는 이와 같이 매개변수가 두가지 String 변수, 하나의 int변수로 선언되었다면,(String model, String color, int maxSpeed)
// 객체를 new 연산자로 생성자를 호출할 때 각 위치에 맞게 "그랜져", "검점", 300으로 인자를 입력해야 함을 알 수 있다.
Car mycar = new Car("검정", 3000);
public class Car{
//생성자
Car(String color, int cc){
//...
}
}
// 이와 같은 경우는 String color, int cc에 맞게 생성자의 인자에 "검정", 3000을 입력함을 알 수 있다.
필드 초기화
-
클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정된다. 만약 다른 값으로 초기화를 하고 싶다면 두가지 방법이 있다. 하나는 필드를 선언할 때 초기값을 주는 방법이고, 또 다른 하나는 생성자에서 초기값을 주는 방법이다.
-
객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 한다면 생성자에서 초기화를 해야한다. 앞으로 다양하게 초기화해야 할것은 생성자를 이용해 초기화를 하자. (명심!)
//내부 클래스
public class Korean{
// 필드
String nation = "대한민국"
String name;
string ssn; // 주민번호
//생성자
public Korean(String n , String s){
name = n;
ssn = s;
}
}
// 메인
public static void main(String[] args){
Korean k1 = new Korean("이자바", 970707-1234888"); // 생성자로 다양하게 초기화...
Korean k2 = new Korean("김도형", 930928-1999999");
}
=> Korean 생성자의 매개 변수 이름으로 각각 n과 s를 사용했는데 , 매개변수의 이름이 너무 짧으면 가독성이 좋지 않기에 초기화시킬 필드와 동일한 이름을 갖는 매개변수를 사용하라. 이 경우 필드와 매개변수 이름이 동일하기에 생성자 내부에서 필드에 접근할 수 없는데(생성자의 매개변수가 생성자 내부에서 우선순위가 더 높기 때문), 해결 방법은 생성자 내부에서 필드 앞에 this.을 붙이면 필드에 접근할 수 있다. this란 객체 자신의 참조를 뜻하는 말로 객체는 객체 자신을 this라고 한다.
//생성자
public Korean(String name, String ssn){
this.name = name; // 필드, 매개변수
this.ssn = ssn; // 필드, 매개변수
}
=> 생성자로 모든 필드를 초기화한다면, 필드의 수가 많을 경우 다 입력하기엔 너무 번거롭다. 실제로는 중요한 몇 개 필드만 생성자를 통해 초기화하고, 나머지필드들은 필드 선언시에 초기화하거나 나중에 따로 메소드를 통해 초기화를 한다. 모든 필드를 생성자로 초기화하지 말자.
생성자 오버로딩(Overloading)
- 생성자 오버로딩이란 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다.(매개변수가 달라야 하는 경우가 매우 많다!)
public class Car{
Car(){...} // 기본생성자는 생성자가 아래처럼 생략되있지 않은 경우 자동 생성 x, 따라서 이렇게 명시해서 만들자.
Car(String model){...}
Car(String model, String color){...}
Car(String model, Stirng color, int maxSpeed){...}
}
public class Car {
// 고유 데이터
String model;
String color;
// 상태 데이터
int speed;
int maxspeed;
int rpm;
//부품
Body body;
Engine engine;
Tire tire;
Car(){
}
Car(String model){
this.model = model;
}
Car(String model , String color){
this.model = model;
this.color = color;
}
Car(String model, String color, int maxspeed){
this.model = model;
this.color = color;
this.maxspeed = maxspeed;
}
}
this() : 다른 생성자 호출
- 생성자 오버로딩이 많아질 경우 생성자간의 중복된 코드가 발생한다. 중복을 피하고 싶을 때 생성자에서 다른 생성자를 호출하는 방법을 이용하여 중복을 피할 수 잇는 데 , 다른 생성자를 호출할 때에는 this() 코드를 사용한다.
public class Car {
// 고유 데이터
String model;
String color;
// 상태 데이터
int speed;
int maxspeed;
int rpm;
//부품
Body body;
Engine engine;
Tire tire;
// 생성자
Car(){
}
Car(String model){
this(model,"은색", 250); // 다른 생성자 호출 (String model, String color, int maxSpeed)
}
Car(String model , String color){
this(model,color, 250);
}
Car(String model, String color, int maxspeed){
this.model = model;
this.color = color;
this.maxspeed = maxspeed; // 공통 실행 코드
}
}
메소드(Method)
- 메소드는 객체의 동작에 해당하는 중괄호 {} 블록을 말한다. 중괄호 블록은 이름을 가지고 있는데, 이것이 메소드 이름이다. 메소드는 필드를 읽고 수정하는 역할도 할 수 있고, 다른 객체를 생성해서 다양한 기능을 수행하기도 하고, 객체 간의 데이터 전달의 수단으로 사용된다. 외부로부터 매개값을 받을 수 있고, 실행후 어떤 값을 리터할 수도 있다. C언어의 함수와 같은 기능이다.
메소드 선언
- 메소드 선언은 선언부(리턴타입, 메소드 이름, 매개변수 선언)과 실행 블록으로 구성된다. 메소드 선언부를 메소드 시그니처(signiture) 라고도 한다.
리턴(return) 문
- 리턴값이 있는 메소드가 있고 리턴값이 없는 메소드(void)가 있다.
메소드 호출 : 클래스 내부의 다른 메소드에서 호출하는 경우 vs 클래스 외부의 다른 메소드에서 호출하는 경우
- 객체 내부에서 호출 ```java //메소드 선언 void run(){…} void stop(){…} void sound(){…}
//내부 메소드 void 내부메소드(){ run(); stop(); sound(); }
2. 객체 외부에서 호출
```java
//외부 메소드
void 외부메소드(){
Car car = new Car();
car.run();
car.stop();
car.sound();
}
메소드 오버로딩(Method Overloading)
- 클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩(Method Overloading)이라고 한다.
- 메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위해서이다.
int plus(int x, int y){
return x + y;
}
double plus(double x, double y){
return x + y;
}
//이처럼 plus 메소드를 사용할 때 인자를 int 형으로 넣고 int 값으로 반환하고 싶을때 위의 plus메소드를 사용하면 되고,
// 인자를 double형으로 넣고 double 값으로 반환하고 싶을 때 아래의 plus메소드를 사용하면 된다.
// 이렇게 다양하게 매개값을 줘야할때 메소드 오버로딩을 사용한다.