본문 바로가기
개발 관련 지식/JAVA

객체와 클래스

by 권태일1147 2020. 3. 30.

클래스

메모리에서 사용하고 싶은 객체가 있다면 우선 설계도로 해당 객체를 만드는 작업이 필요하다.

객체를 만들기 위한 설계도가 클래스이다.

클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어 있다.

클래스를 통해 생성된 객체를 클래스의 인스턴스라고 한다.

하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있는데, 이것은 동일한 설계도로부터 이러 대의 자동차를 만드는 것과 동일하다.

main() 메소드가 없는 클래스는 객체 생성 과ㅏ정을 거쳐 사용해야 한다.

 

일반적으로 파일당 하나의 클래스를 선언하긴 하는데, 하나의 파일에 두 개의 클래스 선언도 가능하다.

주의할 점은 파일 이름과 동일한 이름의 클래스에만 public 접근 제한자를 붙일 수 있다.

// Car.java

public class Car {

}

class Tire {

}

만약 파일 이름과 일치 하지 않는 클래스에 public 접근 제한자를 붙인다면 컴파일 에러가 발생한다.

가급적이면 파일 하나당 동일한 이름의 클래스 하나를 만드는 것이 좋다.

 

 

객체 생성

클래스를 만들고 컴파일(저장) 했다면 설계도를 만든것이기 때문에, 클래스를 통해 객체를 만들 수 있다.

객체 new 연산자를 사용해서 생성할 수 있다.

new 연산자로 생성된 객체는 메모리 힙(heap) 영역에 생성된다.

new 연산자는 힙 영역에 객체를 생성시킨 후, 객체의 주소를 리턴하도록 되어 있다. 이 주소를 참조 타입인 클래스 변수에 저장하면 변수를 통해 객체를 사용할 수 있다.

클래스 변수이름 = new 클래스()
 Car  car   = new  Car()

 

클래스의 구성 멤버

클래스에는 객체가 가져야할 구성 멤버가 선언된다. 구성 멤버는 필드, 생성자, 메소드가 있다.

필드 : 객체의 데이터가 저장되는 곳

생성자 : 객체 생성 시 초기화 역할

메소드 : 객체의 동작에 해당하는 실행 블록

 

필드

필드는 선언 형태가 변수와 비슷하지만 필드를 변수라고 부르지 않는다.

변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸된다.

필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.

필드는 클래스 중괄호 {} 블록 안이라면 어디서든 선언이 가능하다. 하지만 생성자와 메소드 중괄호 {} 블록 내부에서는 선언될 수 없다.

생성자와 메소드 안에서 선언된 것은 모두 로컬 변수이다.

필드의 타입으로는 기본타입(int, string, byte, boolean....) 과 참조타입(배열, 클래스, 인터페이스)이 올 수 있다.

외부 클래스에서 필드를 사용하려면 객체를 생성하고 필드를 사용해야한다. 필드를 가지고 있는 객체가 없으면 필드 또한 없는 것이기 때문.

 

생성자

생성자는 new 연산자로 호출되는 특별한 중괄호{} 블록이다.

생성자는 객체 생성 시 초기화를 담당한다. 생성자에서 필드를 초기화 하거나, 메소드를 호출해서 객체를 사용할 준비를 한다. 생성자는 메소드와 비슷하게 생겼지만, 클래스 이름과 동일한 이름으로 되어 있고 리턴 타입이 없다.

모든 클래스는 생성자가 반드시 존재하며, 하나 이상 가질 수 있다. 우리가 클래스 내부에 생성자를 생략했다면 컴파일러는 기본 생성자를 바이트 코드에 자동으로 추가시킨다. 그러나 클래스에 선언한 생성자가 한 개라도 있으면, 컴파일러는 기본 생성자를 추가하지 않는다.

생성자 내부에는 일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 준비를 한다.

// Car.java

public class Car {
	Car(String color, int cc) {
    
    }
}
// CarExam.java

public Class CarExam {
    public static void main(String[] args){
    	Car car = new Car("검정", 3000);
        // Car car = new Car()는 사용 불가능 (Car class에서 생성자를 선언했기 때문에 기본 생성자가 생성되지 않음)
    }
}

 

필드를 초기화 하는 방법으로는 두 가지가 있다. 첫번째는 필드를 선언할 때 초기값을 주는 방법이고, 다른 방법은 생성자에서 초기값을 주는 방법이다.

필드를 선언할 때 초기값을 주면 객체 생성 시에 필드의 값은 모두 동일하다. 물론 객체 생성 후에 필드 값을 변경 할 수 있다.

하지만, 객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화 되어야 한다면 생성자에서 초기화 해야한다. 

// Korean.java

public class Korean {
	
    // 필드
    String nation = "대한민국";
    String name;
    String ph;
    
    // 생성자
    public Korean(String n, String p){
    	name = n;
        ph = p;
    }
}
// KoreanExam.java

public class Korean{
    public static void main(String[] args){
        Korean korean1 = new Korean("신태일", "010-0000-0000");
        System.out.println(korean1.name, korean1.ph);
        
        Korean korean2 = new Korean("아구몬", "010-3333-3333");
        System.out.println(korean2.name, korean2.ph);
    }
}

관례적으로는 필드와 동일한 이름을 갖는 매개변수를 생성자에 사용한다. 필드와 매개변수의 이름이 같을 때는 매개변수의 사용 우선순위가 높아서 필드에 접근할 수가 없다. 이 때 필드 앞에 'this.' 을 붙이면 된다. this는 객체 자신의 참조라서 this. 을 붙이면 객체.필드로 해석 된다.

 

생성자 오버로딩 : 매개변수를 달리해서 같은 이름의 생성자를 여러 개 선언하는 것 (매개변수의 타입, 개수, 순서가 다르면 오버로딩 가능)

매개 변수의 타입과 개수, 선언된 순서가 똑같을 경우 매개 변수 이름만 바꾸는 것은 생성자 오버로딩이라고 볼 수 없다.

Car(String model, String color){...};
Car(String color, String model){...}; // 오버로딩 아님.

this()를 사용해서 생성자에서 다른 생성자를 불러올 수 있다.

생성자의 내용이 비슷할 때는 this()를 이용해서 다른 생성자를 불러오면 중복 코드를 최소화 할 수 있다.

// 필드
String model;
String color;
int maxSpeed;

Car(String model){
    // 매개변수 3개짜리 다른 생성자
    this(model, "은색", 250);
}

Car(String model, String color){
    // 매개변수 3개짜리 다른 생성자
    this(model, color, 300);
}

Car(String model, String color, int maxSpeed){
    // 필드       매개변수
    this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}
Car car1 = new Car("택시"); // 매개변수 1개짜리 생성자
System.out.println(car1.model); // 택시
System.out.println(car1.color); // 은색
System.out.println(car1.maxSpeed); // 250

Car car2 = new Car("버스", "초록"); // 매개변수 2개짜리 생성자
System.out.println(car2.model); // 버스
System.out.println(car2.color); // 초록
System.out.println(car2.maxSpeed); // 300

Car car3 = new Car("스포츠카", "빨강", 450); // 매개변수 3개짜리 생성자
System.out.println(car3.model); // 스포츠카
System.out.println(car3.model); // 빨강
System.out.println(car3.model); // 450

 

메소드

메소드는 객체의 동작에 해당하는 중괄호 {} 블록이다.

메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행하기 한다. 

메소드는 리턴 타입이 있어야 한다. 리턴 타입이란 메소드가 실행 후 리턴하는 값의 타입이다. 리턴값이 없는 경우 void를 사용하고, 리턴 값이 있는 경우 리턴값의 타입이 메소드 앞에 적혀있어야 한다.

리턴값이 없는 메소드의 경우 호출만 하면 된다. 하지만 리턴 값이 있는 메소드의 경우 리턴값을 저장하기 위한 리턴값과 같은 타입의 변수가 필요하다. 그렇다고 반드시 저장할 필요는 없다. 필요하면 저장하고 필요하지 않으면 변수 선언 없이 호출만 해도 된다.

리턴문 이후에 실행문이 오면 에러가 난다.

리턴값이 없는 메소드(void)는 return; 를 사용하면 메소드를 강제 종료한다.

 

메소드 오버로딩

클래스 내에서 같은 이름의 메소드를 여러 개 선언하는 것.

매개 변수의 타입, 개수, 순서 중 하나가 달라야 오버로딩이 가능하다.

'개발 관련 지식 > JAVA' 카테고리의 다른 글

import문  (0) 2020.03.31
싱글톤(Singleton)  (0) 2020.03.31
객체 지향 프로그래밍  (0) 2020.03.29
Spring boot - 5. JPA test CRUD 만들기  (1) 2020.03.23
Spring boot - 4. JPA 설정  (0) 2020.03.22