클래스가 필요한 이유
자바는 클래스와 객체로 구성되며, 이를 이해하는 것이 핵심이다. 클래스와 객체는 다양한 개념을 포함하고 있어 한 번에 모두 이해하기 어렵다. 따라서 클래스와 객체의 기본 개념을 시작으로, 클래스가 발전하면서 만들어진 방식까지 단계적으로 살펴보자.
학습 정보 출력 프로그램 만들기
학습에서 '왜'라는 질문은 본질을 이해하는 데 중요한 역할을 한다. 먼저, 클래스가 필요한 이유를 이해하기 위해 문제를 풀어보자.
요구 사항
1. 첫 번째 학생의 이름은 "학생 1", 나이는 15, 성적은 90입니다.
2. 두 번째 학생의 이름은 "학생2", 나이는 16, 성적은 80입니다.
3. 각 학생의 정보를 다음과 같은 형식으로 출력해야 합니다: `"이름: [이름] 나이: [나이] 성적: [성적]"`
4. 변수를 사용해서 학생 정보를 저장하고 변수를 사용해서 학생 정보를 출력해야 합니다.
1. 변수를 활용해 접근
변수를 사용해서 이 문제를 풀면 다음과 같다.
package class1;
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);
}
}
요구사항인 학생 2명을 다뤄야하기 때문에 각각의 변수를 선언하여 사용하였다. 이 코드의 문제점은 학생이 늘어날 때마다 새로운 변수를 선언해야 된다는 것이다. 또한 출력하는 코드도 추가돼야 한다.
2. 배열을 통한 접근
배열을 이용하면 변수로 작성한 코드보다 추가되는 내용을 최소화할 수 있게되었다.
package class1;
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]);
}
}
}
배열을 사용하면 학생이 추가되더라도 배열에 학생 데이터만 추가하면 된다.
학생 추가 후
String[] studentNames = {"학생1", "학생2", "학생3", "학생4", "학생5"};
int[] studentAges = {15, 16, 17, 10, 16};
int[] studentGrades = {90, 80, 100, 80, 50};
단, 배열 사용에도 한계가 있다. 코드 변경에 최소화는 성공했지만, 한 데이터가 3개의 배열 `studentNames[]`, `studentAges[]`, `studentGrades[]`로 나누어져 있다. 따라서 데이터 변경이 있을 경우 매우 신중히 처리가 돼야 한다. 예를 들어 `학생2`의 데이터를 삭제하는 경우 배열마다 정확히 `학생2`의 요소를 제거해줘야 한다. 이런 경우 코드를 작성하는 사람이 실수를 할 가능성이 커 관리하기에 좋은 코드라 볼 수 없다.
클래스의 도입
이전 예시를 통해 이름, 나이, 성적을 따로 관리하는 것에 대한 이슈를 알아봤다. 여기서 유추할 수 있듯이 사람이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶는 것이다. 그리고 학생 별로 본인의 이름, 나이, 성적을 각각 관리하는 것이다.
package class1;
public class Student {
String name;
int age;
int grade;
}
`class`라는 키워드를 사용하여 학생 클래스(`Student`)를 정의한다. 학생 클래스는 내부의 이름(`name`), 나이(`age`), 성적(`grade`)이라는 변수를 가지게 된다.
이렇게 클래스의 정의된 변수들을 멤버변수, 또는 필드라 칭한다.
- 멤버변수(Member Variable): 이 변수들은 특정 클래스에 소속된 멤버이기 때문에 이렇게 불린다.
- 필드(Field): 데이터 항목을 가리키는 전통적인 용어이다. 데이터베이스, 엑셀 등에서 데이터에 각각의 항목을 필드라 한다.
- 자바에서는 멤버변수, 필드는 같은 뜻으로 쓰인다. 클래스에 소속된 변수를 의미한다.
클래스의 네이밍은 관례상 대문자로 시작하는 낙타 표기법(Camel)을 사용한다. ex) Student, User, MemberService
학생클래스를 사용한 코드 작성
package class1;
public class ClassStart3 {
public static void main(String[] args) {
Student student1;
student1 = new Student();
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
Student student2 = new Student();
student2.name = "학생2";
student2.age = 16;
student2.grade = 80;
System.out.println("이름:" + student1.name + " 나이:" + student1.age
+ " 성적:" + student1.grade);
System.out.println("이름:" + student2.name + " 나이:" + student2.age
+ " 성적:" + student2.grade);
}
}
클래스와 사용자 정의 타입
타입은 데이터의 종류나 형태를 나타낸다. 예를 들어, `int`는 정수 타입을, `String`은 문자 타입을 의미한다.
학생(Student)과 같은 타입을 만들기 위해서는 클래스가 필요하다. 클래스는 `int`나 `String`처럼 새로운 타입을 설계하고 정의할 수 있게 한다.
즉, 사용자가 직접 정의하는 사용자 정의 타입을 생성하려면 설계도가 필요하며, 이 설계도가 바로 클래스이다. 설계도인 클래스를 통해 만들어진 실제 메모리의 실체를 객체 또는 인스턴스라고 부른다.
붕어빵을 예로 생각하면 쉽다. 붕어빵을 만들기 위한 틀을 클래스, 만들어진 붕어빵이 객체 또는 인스턴스이다.
코드 분석
학생(Student)이라는 클래스를 기반으로 학생1(student1), 학생2(student2) 객체 또는 인스턴스로 구성된 코드이다.
1. 변수 선언
Student student1;
- `Student`타입을 받을 수 있는 변수를 선언한다.
- `int`는 정수, `String`은 문자를 담을 수 있듯이, `Student`는 `Student`타입의 객체(인스턴스)를 받을 수 있다.
2. 객체 생성
student1 = new Student();
- 객체를 만들기 위해선 먼저 설계도인 클래스를 기반으로 객체(인스턴스)를 생성해야 한다.
- `new Student()`에서 `new`는 새로 생성한다는 뜻이다. 결국 `Student`라는 클래스 정보를 기반으로 새로운 객체를 생성하라는 의미이다.
- 객체를 생성하는 방법: `new 클래스명()`
- `Student` 클래스는 `String name` , `int age` , `int grade` 멤버 변수를 가지고 있다. 이 변수를 사용하는데 필요한 메모리 공간도 함께 확보한다.
3. 참조값 보관
객체를 생성하고 나면 자바는 메모리 어딘가에 이 객체가 접근할 수 있는 참조값(주소)(`x001`)을 반환한다. `x001`로 표기되는 것이 참조값이다.
`new` 키워드로 객체가 생성이 되면 참조값이 반환된다. 반환된 참조값은 앞서 선언한 `Student student1` 변수에 생성된 객체의 참조값이 보관된다.
`Student student1` 변수는 메모리에 존재하는 실제 `Student`객체(인스턴스)의 참조값을 가지고 있는 것이다. 이것은 `student1`변수를 통해 객체(또는 인스턴스)에 접근할 수 있다는 것을 의미한다. 쉽게 말해서 `student1`변수를 통해 메모리에 있는 실제 객체를 접근하고 사용할 수 있다.
참조값을 변수에 보관해야 되는 이유
`new`키워드는 특정 클래스를 기반으로 메모리에 객체를 생성하지만, 생성된 객체 자체에는 이름이 없다. 따라서 생성한 객체에 접근하기 위해 참조값을 변수에 저장해야 한다. 참조값이 변수에 저장되면, 이를 통해 메모리에 있는 객체에 접근하고 활용할 수 있다.
Student student1 = new Student(); //1. Student 객체 생성
Student student1 = x001; //2. new Student()의 결과로 x001 참조값 반환
student1 = x001; //3. 최종 결과
객체 사용
위 예시에서 클래스를 통해 생성한 객체를 사용하려면 먼저 메모리 존재하는 객체에 접근을 해야한다. 객체의 접근하는 방법은 `.`(점, dot)을 사용하면 된다.
//객체 값 대입
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
//객체 값 사용
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" +
student1.grade);
객체에 값 대입
객체가 가지고 있는 멤버 변수(name, age, grade)에 값을 대입하기 위해선 우선 객체에 접근을 해야한다. 그때 이용하는 것이 `.`(점, dot)키워드이다. 이 키워드는 변수에 들어있는 참조값을 읽어서 메모리에 존재하는 객체에 접근한다.
student1.name="학생1" //1. student1 객체의 name 멤버 변수에 값 대입
x001.name="학생1" //2.변수에 있는 참조값을 통해 실제 객체에 접근, 해당 객체의 name 멤버 변수에
값 대입
student1.` (dot)이라고 하면 `student1` 변수가 가지고 있는 참조값을 통해 실제 객체에 접근한다.
객체 값 읽기
객체의 값을 읽는 것도 앞서 설명한 내용과 같다. `.` (점, dot) 키워드를 통해 참조값을 사용해서 객체에 접근한 다음에
원하는 작업을 하면 된다.
//1. 객체 값 읽기
System.out.println("이름:" + student1.name);
//2. 변수에 있는 참조값을 통해 실제 객체에 접근하고, name 멤버 변수에 접근한다.
System.out.println("이름:" + x001.name);
//3. 객체의 멤버 변수의 값을 읽어옴
System.out.println("이름:" + "학생1");
클래스, 객체, 인스턴스 정리(중요!!!)
1. 클래스(Class)
클래스는 객체를 생성하기 위한 '틀' 또는 '설계도'이다. 클래스는 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 위에 예시로 만든 학생(Student)클래스는 속성으로 `name`, `age`, `grade`를 가진게 된다. 기능(메서드)는 이후 포스팅에서 다룰 예정이다.
예시로 정의해보면 다음과 같다.
- 틀의 경우, 붕어빵을 생각해보면 된다. 붕어빵을 만들기 위해선 붕어빵 틀이 필요하다. 붕어빵 틀은 실제 붕어빵이 아닌 그것 만들기 위한 도구이고, 실제 붕어빵은 틀을 통해 만들어진 객체 또는 인스턴스이다.
- 설계도의 경우, 자동차 설계도를 생각하면 된다. 마찬가지로 자동차 설계도는 자동차가 아니다. 설계도는 실물 자동차가 아닌 그것을 만들기 위해 개념적으로 존재한다. 설계도를 통해 만들어진 자동차를 여기선 객체 또는 인스턴스라고 부른다.
2. 객체(Object)
객체는 클래스에서 정의한 속성과 기능을 가진 실체를 의미한다. 객체는 서로 독립적인 상태를 가진다. 예를 들어 위 코드에서 `student1`은 학생1의 속성을 가지는 객체이며, `student2`는 학생2의 속성을 가지는 객체이다.
즉, `student1`과 `student2`는 같은 클래스에서 만들어졌지만, 서로 다른 객체이다.
3. 인스턴스(Instance)
인스턴스는 특정 클래스로부터 생성된 객체를 의미한다. 그래서 객체와 인스턴스라는 용어는 자주 혼용이 된다. 인스턴스는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용이 된다. 예를 들어서 `student1`객체는 `Student`클래스의 인스턴스다. 라고 표현한다.
객체 vs 인스턴스
인스턴스와 객체는 모두 클래스에서 생성된 실체를 의미하지만, 용어상의 미묘한 뉘양스 차이가 있다. 인스턴스는 객체보다 특정 클래스와의 관계를 강조할 때 사용하는 용어다. 예를 들어, `student1`은 객체라고 표현할 수 있지만, `Student` 클래스로부터 생성되었음을 강조하고 싶을 때는 `student1`을 `Student`의 인스턴스라고 부른다.
쉽게 말해, 모든 인스턴스는 객체지만, 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 사용한다. 그러나 두 용어는 클래스에서 생성된 실체라는 공통점을 가지며, 일상적으로는 구분 없이 사용되기도 한다.
참조
'Language > Java' 카테고리의 다른 글
[Java] 변수의 초기화 (0) | 2025.01.07 |
---|---|
[Java] 기본형 vs 참조형 (0) | 2025.01.04 |
[Java] 스택(Stack) (1) | 2024.11.28 |
[Java] Math 클래스 (1) | 2024.11.15 |
[Java] startsWith와 endsWith (0) | 2024.11.15 |