클래스와 객체
클래스와 객체는 객제지향 프로그래밍(OOP)에서 빠질 수 없는 개념이다. 클래스란 '객체를 정의해놓은 것' 또는 '객체의 설계도/틀'로 정의할 수 있으며, 객체는 '실제로 존재하는 것' 또는 '사물 또는 개념'으로 정의할 수 있다. 객체는 좀 더 단순하게 '다루고자 하는 대상' 정도로 생각해도 좋을 듯하다.
- 클래스(Class): 객체를 정의해놓은 것, 객체의 설계도
- 객체(Object): 실제로 존재하는 것, 사물 또는 개념
인스턴스와 객체의 관계
클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화(instantiate)라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(instance)라고 한다. 결국 인스턴스와 객체는 같은 의미이지만, 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖고 있는 반면, 인스턴스는 어떤 클래스로부터 만들어진 것인지를 강조하는 보다 구체적인 의미를 갖고 있다.
- 객체: 모든 인스턴스를 대표하는 포괄적인 의미
- 인스턴스: 어떤 클래스로부터 파생된 것인지를 강조하는 구체적인 의미
속성과 기능
객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 기능을 지닌다. 즉, 객체는 속성과 기능의 집합이라고 할 수 있다. 그리고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(member)라고 한다. 객체지향 프로그래밍에서는 이러한 속성과 기능을 각각 멤버변수와 메소드로 표현한다.
- 속성(property): 멤버변수(member variable), 특성(attribute), 필드(field), 상태(state)
- 기능(function): 메소드(method), 함수(function), 행위(behavior)
우리에게 TV를 예로 들어보자. TV의 속성과 기능은 다음과 같이 분류될 것이다.
속성 | 크기, 길이, 높이, 색상, 볼륨, 채널 등 |
기능 | 켜기, 끄기, 볼륨 높이기, 볼륨 낮추기, 채널 변경하기 등ㅍ |
클래스 정의하기
이번엔 앞서 예를 든 TV를 바탕으로 실제 클래스를 정의해보자. 다음과 같이 멤버변수와 메소드를 이용하여 클래스를 정의할 수 있다. Tv 클래스는 다음과 같이 멤버변수와 메소드. 두 가지 부분으로 구성된다.
- 멤버변수
- 색상: String color
- 전원 상태: boolean power;
- 채널: int channel;
- 메소드
- TV 전원: power()
- 채널 올리기: channelUp()
- 채널 내리기: channelDown()
class Tv {
// Tv의 속성 (멤버변수)
String color; // 색상
boolean power; // 전원 상태(on/off)
int channel; // 채널
// Tv의 기능 (메소드)
void power() {
power = !power; // TV를 켜거나 끄는 기능을 하는 메소드
}
void channelUp() {
++channel; // TV의 채널을 높이는 기능을 하는 메소드
}
void channelDown() {
--channel; // TV의 채널을 낮추는 기능을 하는 메소드
}
}
인스턴스(객체) 생성하기
다음 코드를 통해 인스턴스를 생성하는 과정을 알 수 있다.
- Tv t: Tv클래스 타입의 참조변수 t를 선언한다.
- new Tv(): new 키워드를 통해 실제 TV클래스의 인스턴스를 메모리의 빈 공간에 생성한다.
- Tv t = new Tv(): 대입연산자를 통해 생성된 객체의 주소값을 참조변수 t에 저장한다.
public class Main {
public static void main(String[] args) {
Tv t = new Tv();
t.channel = 7;
t.channelDown();
System.out.println("현재 채널은 " + t.channel + " 입니다."); // 현재 채널은 6 입니다.
}
}
class Tv {
// Tv의 속성 (멤버변수)
String color; // 색상
boolean power; // 전원 상태(on/off)
int channel; // 채널
// Tv의 기능 (메소드)
void power() {
power = !power; // TV를 켜거나 끄는 기능을 하는 메소드
}
void channelUp() {
++channel; // TV의 채널을 높이는 기능을 하는 메소드
}
void channelDown() {
--channel; // TV의 채널을 낮추는 기능을 하는 메소드
}
}
클래스 변수와 인스턴스 변수
위의 색상(color), 전원 상태(power), 채널(channel)은 각 인스턴스마다 제각기 다른 값을 지니는 '인스턴스 고유의 상태', 즉 인스턴스 변수라고 할 수 있다.
하지만, 만약 TV를 하나의 회사에서 만들어서 규격을 일치시켜야 한다면 어떨까? 회사명(companyName), 높이(height), 너비(width)는 인스턴스마다 모두 동일한 값을 가져야 할 것이다. 이럴 때 사용하는 것이 바로 클래스 변수이다.
클래스 변수는 인스턴스 변수 앞에 static을 붙이기만 하면 된다. 인스턴스마다 독립적인 저장공간을 갖는 인스턴스 변수와는 달리, 클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 된다.
- 인스턴스 변수: 인스턴스가 생성될 때마다 생성, 인스턴스마다 각기 다른 값을 유지
- 클래스 변수: 모든 인스턴스가 하나의 저장공간을 공유, 인스턴스 모두 공통된 값을 유지
public class Main {
public static void main(String[] args) {
Tv t = new Tv();
System.out.println("회사 이름은 " + t.companyName + " 입니다."); // 회사 이름은 LG 입니다.
System.out.println("높이는 " + t.height + " 입니다."); // 높이는 80 입니다.
System.out.println("너비는 " + t.width + " 입니다."); // 너비는 300 입니다.
}
}
class Tv {
// Tv의 속성 (멤버변수)
static String companyName = "LG";
static int height = 80;
static int width = 300;
String color; // 색상
boolean power; // 전원 상태(on/off)
int channel; // 채널
// Tv의 기능 (메소드)
void power() {
power = !power; // TV를 켜거나 끄는 기능을 하는 메소드
}
void channelUp() {
++channel; // TV의 채널을 높이는 기능을 하는 메소드
}
void channelDown() {
--channel; // TV의 채널을 낮추는 기능을 하는 메소드
}
}
생성자 정의하기
main함수 내에서 일일이 멤버변수의 값을 지정해주는 것은 다소 귀찮아 보인다. 처음 인스턴스를 생성할 때부터 멤버변수에 값을 지정할 순 없을까? 그럴 때 사용하는 것이 생성자(Constructor)이다.
생성자란 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메소드'이다. 따라서 인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.
생성자는 다음의 구조를 지닌다.
- 생성자의 이름은 클래스의 이름과 같아야 한다.
- 생성자는 리턴 값이 없다.
클래스명 (타입 변수명, 타입 변수명, ... ) {
// 인스턴스 생성 시 수행될 코드
// 주로 인스턴스 변수의 초기화 코드를 적는다.
}
Tv ( ) {
...
}
Tv (String color, int channel) {
...
}
이에 따라 다음과 같이 생성자를 정의해볼 수 있다.
package com.company;
public class Main {
public static void main(String[] args) {
Tv t = new Tv("Yellow", 10);
System.out.println("색상은 " + t.color + " 입니다."); // 색상은 Yellow 입니다.
System.out.println("현재 채널은 " + t.channel + " 입니다."); // 현재 채널은 10 입니다.
}
}
class Tv {
// Tv의 속성 (멤버변수)
static String companyName = "LG";
static int height = 80;
static int width = 300;
String color; // 색상
boolean power; // 전원 상태(on/off)
int channel; // 채널
Tv(String color, int channel) {
this.color = color;
this.channel = channel;
}
// Tv의 기능 (메소드)
void power() {
power = !power; // TV를 켜거나 끄는 기능을 하는 메소드
}
void channelUp() {
++channel; // TV의 채널을 높이는 기능을 하는 메소드
}
void channelDown() {
--channel; // TV의 채널을 낮추는 기능을 하는 메소드
}
}
this란?
Java에서의 this는 인스턴스 자신(self)을 가리키는 참조변수이다. this가 인스턴스 자신에 대한 참조 값을 가지고 있다는 뜻이다. 주로 매개변수(지역변수)와 인스턴스 자신이 가지고 있는 멤버변수명이 같을 경우 이를 구분하기 위해서 사용된다.
사실 이전까지는 우리가 생성자를 따로 정의하지 않았지만, 모든 클래스에는 반드시 하나 이상의 생성자가 정의되어 있어야 한다는 원칙이 있다. 그렇다면 어떻게 위의 코드들이 에러가 나지 않았을까? 그것은 바로 컴파일러가 제공하는 기본 생성자(default constructor) 덕분이었다.
컴파일러는 지금까지 다음과 같은 기본 생성자를 생성해줬다.
클래스명 () {
}
Tv ( ) {
}
그렇다면 위의 코드에서 main 함수를 아래와 같이 수정하면 어떻게 될까? 기본 생성자 덕분에 인스턴스 생성이 무사히 완료될까?
public class Main {
public static void main(String[] args) {
Tv t = new Tv();
System.out.println("색상은 " + t.color + " 입니다.");
System.out.println("현재 채널은 " + t.channel + " 입니다.");
}
}
위 코드를 실행하면 에러가 발생한다. 왜냐하면 컴파일러는 클래스에 정의된 생성자가 하나도 없을 때에만 기본 생성자를 추가하기 때문이다. 다음과 같이 기본 생성자를 추가해주면 에러 없이 프로그램이 실행된다.
public class Main {
public static void main(String[] args) {
Tv t = new Tv();
System.out.println("색상은 " + t.color + " 입니다.");
System.out.println("현재 채널은 " + t.channel + " 입니다.");
}
}
class Tv {
// Tv의 속성 (멤버변수)
static String companyName = "LG";
static int height = 80;
static int width = 300;
String color; // 색상
boolean power; // 전원 상태(on/off)
int channel; // 채널
Tv() {
}
Tv(String color, int channel) {
this.color = color;
this.channel = channel;
}
// Tv의 기능 (메소드)
void power() {
power = !power; // TV를 켜거나 끄는 기능을 하는 메소드
}
void channelUp() {
++channel; // TV의 채널을 높이는 기능을 하는 메소드
}
void channelDown() {
--channel; // TV의 채널을 낮추는 기능을 하는 메소드
}
}
참고
자바의 정석(남궁성 저)
'프로그래밍 언어 > Java + Kotlin' 카테고리의 다른 글
[Java] 스터디 7주차: 패키지 (0) | 2021.07.15 |
---|---|
[Java] 스터디 6주차: 상속 (0) | 2021.07.07 |
[Java] 스터디 4주차: 제어문 (0) | 2021.06.24 |
[Java] 스터디 3주차: 연산자 (0) | 2021.06.23 |
[Java] 스터디 2주차: 자바 데이터 타입, 변수 그리고 배열 (0) | 2021.05.27 |