클래스가 필요한 이유
자바 세상은 클래스와 객체로 이루어져있다. 그만큼 클래스와 객체라는 개념은 중요하다. 우선 클래스가 왜 필요한지 이해해보자
문제: 학생 정보 출력 프로그램
두 명의 학생 정보를 출력하는 프로그래밍을 작성해야 한다. 각 학생은 이름, 나이, 성적을 가지고 있다.
`"이름: [이름] 나이: [나이] 성적: [성적]"` 형식으로 출력해야 한다.
변수 사용
public class ClassStart1 {
public static void main(String[] args) {
String student1Name = "학생1";
int student1Age = 15;
int student1Grade = 90;
String student2Name = "학생2";
int student2Age = 16;
int student2Grade = 80;
System.out.println("이름: " + student1Name + " 나이: " + student1Age + " 성적: " + student1Grade);
System.out.println("이름: " + student2Name + " 나이: " + student2Age + " 성적: " + student2Grade);
}
}
문제점: 학생이 늘어날 때마다 변수를 추가로 선언해야 하고, 출력하는 코드도 추가해야 한다. → 배열 사용
배열 사용
public class ClassStart2 {
public static void main(String[] args) {
String[] studentNames = {"학생1", "학생2"};
int[] studentAges = {15, 16};
int[] studentGrades = {90, 80};
for (int i = 0; i < studentNames.length; i++){
System.out.println("이름: " + studentNames[i] + " 나이: " + studentAges[i] + " 성적: " + studentGrades[i]);
}
}
}
배열 사용의 한계
배열을 사용해서 코드 변경을 최소화하는데 성공했지만, 학 학생의 데이터가 3개의 배열에 나누어져있다. 따라서 데이터를 변경할 때 매우 조심해서 작업해야 한다. 예를 들어서 학생2의 데이터를 제거하려면 각각의 배열마다 학생2의 요소를 정확하게 찾아서 제거해주어야 한다.
한 학생의 데이터를 관리하기 위해 3개 배열의 인덱스 순서를 항상 정확하게 맞추어야 한다. 이렇게 하면 특정 학생의 데이터를 변경할 때 실수할 가능성이 매우 높다. 사람이 관리하기에는 좋은 코드가 아니다.
사람이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶는 것이다. 그리고 각각의 학생 별로 본인의 이름, 나이, 성적을 관리하는 것이다.
클래스 도입
Student 클래스
public class Student {
String name;
int age;
int grade;
}
`class` 키워드를 사용해서 학생 클래스(`Student`)를 정의한다. 학생 클래스는 내부에 이름(`name`), 나이(`age`), 성적(`grade`) 변수를 가진다.
이렇게 클래스에 정의한 변수들을 멤버 변수, 또는 필드라 한다.
- 멤버 변수(Member Variable): 이 변수들은 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다.
- 필드(Field): 데이터 항목을 가리키는 전통적인 용어이다. 데이터베이스, 엑셀 등에서 데이터 각각의 항목을 피드라 한다.
- 자바에서 멤버 변수, 필드는 같은 뜻이다. 클래스에 소속된 변수를 뜻한다.
클래스는 관례상 대문자로 시작하고 낙타 표기법을 사용한다.
예): `Student`, `User`, `MemberService`
클래스와 사용자 정의 타입
- 타입은 데이터의 종류나 형태를 나타낸다.
- `int`라고 하면 정수 타입, `String`이라고 하면 문자 타입이다.
- 클래스를 사용하면 `int`, `String`과 같은 타입을 직접 만들 수 있다. → 학생(`Student`)라는 타입을 만들면 되지 않을까?
- 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 설계도가 필요하다. 이 설계도가 바로 클래스이다.
- 설계도인 클래스를 사용해서 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.
- 클래스를 통해서 사용자가 원하는 종류의 데이터 타입을 마음껏 정의할 수 있다.
용어: 클래스, 객체, 인스턴스
클래스는 설계도이고, 이 설계도를 기반으로 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다. 둘 다 같은 의미로 사용한다.
여기서는 학생(`Student`) 클래스를 기반으로 학생1(`student1`), 학생2(`student2`) 객체 또는 인스턴스를 만들었다.
1. 변수 선언
Student student1; // Student 변수 선언
- `Student` 타입을 받을 수 있는 변수를 선언한다.
- `int`는 정수를, `String`은 문자를 담을 수 있듯이 `Student`는 `Student` 타입의 객체(인스턴스)를 받을 수 있다.
2. 객체 생성
student1 = new Student() // Student 인스턴스 생성
- `Student` 클래스 정보를 기반으로 새로운 객체를 생성하라는 뜻이다. 이렇게 하면 메모리에 실제 `Student` 객체(인스턴스)를 생성한다.
- 객체를 생성할 때는 `new 클래스명()`을 사용하면 된다.
- `Student` 클래스는 `String name`, `int age`, `int grade` 멤버 변수를 가지고 있다. 이 변수를 사용하는 데 필요한 메모리 공간도 함께 확보한다.
3. 참조값 보관
- 객체를 생성하면 자바는 메모리 어딘간에 있는 이 객체에 접근할 수 있는 참조값(주소)(`x001`)을 반환한다.
- `new` 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다. 앞서 선언한 변수인 `Student student1`에 생성된 객체의 참조값(`x001`)을 보관한다.
- `Student student1` 변수는 이제 메모리에 존재하는 실제 `Student` 객체(인스턴스)의 참조값을 가지고 있다.
- `student1` 변수는 방금 만든 객체에 접근할 수 있는 참조값을 가지고 있다.→ 이 변수를 통해서 객체를 접근(참조)할 수 있다.
- 쉽게 이야기해서 `student1` 변수를 통해 메모리에 있는 실제 객체를 접근하고 사용할 수 있다.
Student student1 = new Student(); //1. Student 객체 생성
Student student1 = x001; //2. new Student()의 결과로 x001 참조값 반환
student1 = x001; //3. 최종 결과
참조값을 변수에 보관해야 하는 이유
객체를 생성하는 `new Student()` 코드 자체에는 아무런 이름이 없다. 이 코드는 단순히 `Student` 클래스를 기반으로 메모리에 실제 객체를 만드는 것이다. → 생성한 객체에 접근할 수 있는 방법이 필요하다. 이런 이유로 객체를 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다.
앞서 `Student student1` 변수에 참조값(`x001`)을 저장해두었으므로 저장한 참조값(`x001`)을 통해서 실제 메모리에 존재하는 객체에 접근할 수 있다.
참조값을 확인하고 싶다면 객체를 담고 있는 변수를 출력해보면 된다.
System.out.println(student1); // class1.Student@7a81197d
System.out.println(student2); // class1.Student@2f2c9b19
@앞은 패키지 + 클래스 정보를 뜻하낟. @뒤에 16진수는 참조값을 뜻한다.
객체 사용
클래스를 통해 생성한 객체를 사용하려면 먼저 메모리에 존재하는 객체에 접근해야 한다. 객체에 접근하려면 `.`(점, dot)를 사용하면 된다.
// 객체 값 대입
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
// 객체 값 사용
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
클래스, 객체, 인스턴스 정리
클래스 - Class
클래스는 객체를 생성하기 위한 '틀' 또는 '설계도'이다. 클래스는 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 예를 들어 학생이라는 클래스는 속성으로 `name`, `age`, `grade`를 가진다.
실제 존재하는 것이 아니라 개념으로만 있는 것이다.
객체 - Object
객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태를 가진다.
예를 들어 위 코드에서 `student1`은 학생1의 속성을 가지는 객체이고, `student2`는 학생2의 속성을 가지는 객체이다. `student1`과 `student2`는 같은 클래스에서 만들어졌지만, 서로 다른 객체이다.
인스턴스 - Instance
인스턴스는 특정 클래스로부터 생성된 객체를 의미한다. 그래서 객체와 인스턴스라는 용어는 자주 혼용된다. 인스턴스는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용한다. 예를 들어서 `student1` 객체는 `Student` 클래스의 인스턴스다. 라고 표현한다.
하지만 둘 다 클래스에서 나온 실체라는 핵심 의미는 같기 때문에 보통 둘을 구분하지 않고 사용한다.
배열 도입
클래스와 객체 덕분에 학생 데이터를 구조적으로 이해하기 쉽게 변경할 수 있었다. 하지만 새로운 학생이 추가될 때마다 출력하는 부분도 추가해야 하기 때문에 아쉬운 부분이 있다.
배열을 사용하면 특정 타입을 연속한 데이터 구조로 묶어서 편리하게 관리할 수 있다. → `Student` 클래스를 사용한 변수들도 `Student` 타입이기 때문에 학생도 배열을 사용해서 하나의 데이터 구조로 묶어서 관리할 수 있다.
Student[] students = new Student[2];
students[0] = student1;
students[1] = student2;
Student[] students = new Student[]{student1, student2};
// Student[] students = {student1, student2}; 생성과 선언 동시에
- `Student` 변수를 2개 보관할 수 있는 사이즈 2의 배열을 만든다.
- `Student` 타입의 변수는 `Student` 인스턴스의 참조값을 보관한다. `Student` 배열의 각각의 항목도 `Student` 타입의 변수이다. → `Student` 타입의 참조값을 보관한다.
- 배열에는 아직 참조값을 대입하지 않았기 때문에 참조값이 없다는 의미의 `null` 값으로 초기화된다.
배열에 참조값을 대입한 이후 최종 그림
자바에서 대입은 항상 변수에 들어있는 값을 복사해서 전달한다.
students[0] = student1;
students[1] = student2;
자바에서 변수의 대입(`=`)은 모두 변수에 들어있는 값을 복사해서 전달하는 것이다. 이 경우 오른쪽 변수인 `student1`, `student2`에는 참조값이 들어가 있다. 그래서 이 값을 복사해서 왼쪽에 있는 배열에 전달한다. `student1`, `student2`에 들어있던 참조값은 당연히 그대로 유지된다.
변수에는 인스턴스 자체가 들어있는 것이 아니라 인스턴스의 위치를 가리키는 참조값이 들어있다. 따라서 대입(`=`)시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.
'Java' 카테고리의 다른 글
[Java/김영한] 객체 지향 프로그래밍 (0) | 2024.09.07 |
---|---|
[Java/김영한] 기본형과 참조형 (1) | 2024.09.07 |
[Java/김영한] 메서드 (0) | 2024.08.15 |
[Java/김영한] 배열 (0) | 2024.08.14 |
[Java/김영한] 스코프, 형변환 (0) | 2024.08.13 |