객체는 실재하는 어떤 대상을 의미하는 것으로, 우리 주변의 책, 볼펜, 컴퓨터 등이 객체에 해당한다. 좀더 포괄적으로는 우리가 보고 느끼고 인지할 수 있는 모든 것을 의미한다. 이러한 객체를 프로그래밍에 활용하는 것이 객체지향 프로그래밍이다. 객체지향 프로그래밍은 실제 세계를 컴퓨터상에서 활용할 수 있는 방식으로, "프로그래밍에서 필요한 데이터를 한 데 모아 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 특정 기능을 구성"하는 프로그래밍 방법론이다.
객체 하나하나가 부품이라면 객체를 조립해 만든 완성품이 하나의 프로그램이다. 객체 하나를 만들었을 때 그 객체는 하나의 독립적인 기능을 담당하고 이러한 각 기능들이 모여 하나의 프로그램이 만들어지는 것이다. 이미 만들어놓은 객체는 나중에 그 기능이 다시 필요할 때 재활용해 사용할 수 있고 새로운 기능을 만들 때에도 기존의 기능을 수정해 만들 수도 있다.
프로그램 개발 및 유지 보수에 드는 비용과 시간을 획기적으로 줄일 수 있고, 객체를 통해 데이터를 관리하여 데이터를 손실 없이 관리하기에 용이하다.
객체를 정의한 '설계도(blueprint)' 라 정의할 수 있다. 즉, 클래스는 객체를 생성하기 위한 설계이며, 객체는 설계도에 해당하는 클래스에 따라 만들어진 대상이다.
클래스를 통해 생성된 객체를 클래스의 인스턴스(instance)라 한다.
class 클래스명 { // 클래스 정의
-- 생략 --
}
클래스는 네 가지 구성요소 필드(field), 메서드(method), 생성자(constructor), 그리고 이너 클래스(inner class) 로 구성된다.
(1) 필드 - 클래스의 속성을 나타내는 변수로, 차로 예를 들면 모델명, 컬러, 바퀴의 수 등이다.
(2) 메서드 - 클래스의 기능을 나타내는 함수로, 차를 예로 들면 시동걸기, 가속하기, 정지하기 등이다.
(3) 생성자 - 클래스의 객체를 생성하는 역할을 한다.
(4) 이너 클래스 - 클래스 내부의 클래스를 말한다.
1 public class ExampleClass {
2 int x = 10; // (1)필드
3 void printX() {...} // (2)메서드
4 ExampleClass {...} // (3)생성자
5 class ExampleClass2 {...} // (4)이너 클래스
6 }
위의 구성 요소들 중 생성자를 제외한 나머지 3가지 요소를 클래스의 멤버(member)라 부른다.
클래스는 속성(state)와 기능(behavior)을 가지는데 이는 각각 필드와 메서드에 해당한다. 속성과 기능은 해당 클래스와 관련된 데이터로 구성된 집합이다.
객체는 속성과 기능이라는 두 가지 구성요소로 이뤄져있다. 일반적으로 하나의 객체는 다양한 속성과 기능의 집합으로 이뤄져 있고, 이러한 속성과 기능은 이너클래스와 함께 객체의 멤버(member)라고 한다.
클래스명 참조_변수명 = new 생성자();
new 키워드와 생성자를 통해 클래스의 객체를 생성한다는 것은 해당 객체를 힙 메모리에 넣고 그 주소값을 참조변수에 저장하는 것과 같다. 참조변수는 객체의 실제 값이 아닌 힙에 저장되어 있는 주소값을 가리키게 된다.
한편 생성자로 만들어진 인스턴스는 힙 메모리 영역에 들어간다.
또한, 메서드의 구현 코드는 클래스 영역에 저장되고 객체 안에서는 그 위치를 가리키고 있다.
즉 같은 클래스로 만든 모든 객체는 동일한 메서드 값을 공유하기 때문에 여러 번 같은 메서드를 선언해주는 것이 아니라 한번만 저장해두고 필요한 경우에만 클래스 영역에 정의된 메서드를 찾아 사용할 수 있는 것이다.
public static void main(String[] args) {
Car bmw = new Car(); // Car 클래스로 만들어진 bmw 인스턴스
Car tesla = new Car(); // Car 클래스로 만들어진 tesla 인스턴스
Car audi = new Car(); // Car 클래스로 만들어진 audi 인스턴스
}
객체의 생성과 관련해서 자바에서 매우 중요한 메모리의 개념을 포함해서 조금만 더 자세하게 풀어보겠습니다.
먼저 참조 변수는 앞서 설명한대로 실제 데이터 값을 저장하는 것이 아니라 실제 데이터가 위치해있는 힙 메모리의 주소를 저장하는 변수를 의미합니다.
따라서 우리가 new 키워드와 생성자를 통해 클래스의 객체를 생성한다는 것은 해당 객체를 힙 메모리에 넣고 그 주소값을 참조변수에 저장하는 것과 같습니다. 매우 중요한 부분이기 때문에 그림을 통해서 좀 더 살펴보도록 하겠습니다.
그림에서 클래스 Person과 참조 변수 p는 각각 클래스 영역과 스택 영역에 저장된다.
한편 생성자로 만들어진 인스턴스는 힙 메모리 영역에 들어가며 객체 내부에는 클래스의 멤버들이 위치한다. 참조변수는 객체의 실제 값이 아닌 힙에 저장되어 있는 주소값을 가리키게 된다.
메서드의 구현 코드의 위치는 클래스 영역에 저장되고 객체 안에서는 그 위치를 가리키고 있다.
즉 같은 클래스로 만든 모든 객체는 동일한 메서드 값을 공유하기 때문에 여러 번 같은 메서드를 선언해주는 것이 아니라 한번만 저장해두고 필요한 경우에만 클래스 영역에 정의된 메서드를 찾아 사용할 수 있는 것이다.
정리하면,
생성된 객체에서 필드값은 실제 저장공간이 객체 내부에 있다는 것과 메서드는 다른 영역에 하나만 저장해놓고 공유한다는 것이다.
. 은 포인트 연산자라고도 불리는데, 해당 위치에 있는 객체를 가리키는 표현이다.
이 . 을 활용하여 특정 인스턴스의 필드와 메서드, 즉 객체의 멤버들에 접근할 수 있다.
1 참조 변수명.필드명 // 필드값 불러오기
2 참조 변수명.메서드명() // 메서드 호출
public class CarTest {
public static void main(String[] args) {
Car tesla = new Car("Model 3", "빨강"); // 객체 생성.
System.out.println("내 차의 모델은 " + tesla.model + "이고 " + "색은 " + tesla.color + "입니다."); // 필드 호출
tesla.power(); // 메서드 호출
tesla.accelerate();
tesla.stop();
}
}
class Car {
public String model; // 필드 선언
public String color;
public Car(String model, String color) { // 인스턴스 초기화를 위한 생성자 함수. 이후 챕터에서 학습 예정.
this.model = model;
this.color = color;
}
void power() { // 메서드 선언
System.out.println("시동을 걸었습니다.");
}
void accelerate() {
System.out.println("더 빠르게!");
}
void stop(){
System.out.println("멈춰!!");
}
}
// 출력값
내 차의 모델은 Model 3이고 색은 빨강입니다.
시동을 걸었습니다.
더 빠르게!
멈춰!!
위의 코드에서, Car클래스에서 model과 color의 속성과 power(), accelerate(), stop() 기능을 정의했다.
그리고 CarTest 클래스 안에서 tesla 인스턴스를 만들어 앞서 정의한 속성과 기능을 println() 메서드를 통해 출력한다.