본 게시글은 김영한 강사님의 [김영한의 실전 자바 - 기본편]을 수강하며 작성한 글입니다.
01. 클래스가 필요한 이유
1. ClassStart1 - 변수 사용
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명을 다루기 위해 각각 다른 변수를 사용했다.
해당 코드의 문제점은 학생이 늘어날 때마다 새로운 변수를 추가로 선언해야 하고, 출력되는 코드도 추가해야 한다.
이를 for문으로 출력하지 못하는 이유는 변수 이름이 다르기 때문이다.
즉 코드의 변경이 너무 많이 발생한다. 이를 배열을 이용하여 해결해보자.
2. ClassStart2 - 배열 사용
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]);
}
}
}
배열을 사용하여 코드 변경을 최소화했다.
하지만 한 학생에 대한 데이터가 studentNames[], studentAges[], studentGrades[]라는 3개의 배열에 나누어져 있다.
따라서 데이터를 변경할 때 유의해야 한다.
즉, 특정 학생에 대해 3개 배열의 인덱스 순서를 항상 정확하게 맞추어야 한다.
정리
이름, 나이, 성적을 각각 따로 나누어서 관리하는 것은 컴퓨터가 관리하기 좋은 방식이지 사람이 관리하기 좋은 방식이 아니다.
사람이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶는 것이다. 그리고 각각의 학생 별로 이름, 나이, 성적을 관리하는 것이다.
02. 클래스 도입
1. Student 클래스
package class1;
public class Student {
String name;
int age;
int grade;
}
class 키워드를 사용하여 학생 클래스(Student)를 정의한다.
학생 클래스는 내부에 이름(name), 나이(age), 성적(grade) 변수를 가진다.
이렇게 클래스에 정의한 변수들을 멤버 변수, 또는 필드라 한다.
- 멤버 변수(Member Variable): 이 변수들은 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다.
- 필드(Field): 데이터 항목을 가르키는 전통적인 용어다. 데이터베이스, 엑셀 등에서 데이터 각각의 항목을 필드라 한다.
- 자바에서 멤버 변수, 필드는 같은 뜻이다. 클래스에 소속된 변수를 뜻한다.
클래스는 관례상 대문자로 시작하고 낙타 표기법(CamelCase)을 사용한다.
2. ClassStart3 - Student 클래스 사용
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 → 문자 타입
- 클래스를 사용하면 int, String과 같은 타입을 직접 만들 수 있다.
- 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 클래스라는 설계도가 필요하다.
- 설계도인 클래스를 이용하여 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.
클래스, 객체, 인스턴스
클래스는 설계도이고, 이 설계도를 기반으로 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.
3. 코드 분석
1. 변수 선언
- Student student1
- Student 타입을 받을 수 있는 변수를 선언한다.
2. 객체 생성
- student1 = new Student();
- new는 새로 생성한다는 뜻이다. 따라서 new Student()는 Student 클래스 정보를 기반으로 새로운 객체를 생성하라는 뜻이다. 따라서 실제 메모리에 Student 객체(인스턴스)를 생성한다.
- Student 클래스는 String name, int age, int grade 멤버 변수를 가지고 있다. 해당 변수들을 사용하는데 필요한 메모리 공간도 함께 확보한다.
3. 참조값 보관
- student1 = x001;
- 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소)(x001)을 반환한다.
- 앞서 생성한 Student student1에 참조값을 보관한다.
- Student student1 변수는 메모리에 존재하는 실제 Student 객체의 참조값을 가지고 있다. 해당 변수를 통해 객체에 접근할 수 있다.
참조값을 변수에 보관해야 하는 이유
객체를 생성하는 new Student() 코드 자체에는 아무런 이름이 없다. 이 코드는 단순히 Student 클래스를 기반으로 메모리에 실제 객체를 만드는 것이다. 따라서 생성한 객체에 접근할 수 있는 방법이 필요하다. 이러한 이유로 객체를 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다. 앞서 Student student1 변수에 참조값(x001)을 저장해두었으므로 저장한 참조값(x001)을 통해 실제 메모리에 존재하는 객체에 접근할 수 있다.
03. 객체 사용
클래스를 통해 생성한 객체를 사용하려면 메모리에 존재하는 객체에 접근해야 한다. 객체에 접근하려면 . (점, dot)을 사용하면 된다.
// 객체 값 대입
Student student1;
student1 = new Student();
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
// 객체 값 사용
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
객체에 값 대입
변수에 들어있는 참조값을 읽어서 메모리에 존재하는 객체에 접근한다.
student1.name="학생1"; // 1. student1 객체의 name 멤버 변수에 값 대입
x001.name="학생1"; // 2. 변수에 있는 참조값을 통해 실제 객체에 접근. 해당 객체의 name 멤버 변수에 값 대입
- student1.은 student1 변수가 가지고 있는 참조값을 통해 실제 객체에 접근한다.
- student1은 x001이라는 참조값을 가지고 있으므로 x001 위치에 있는 Student 객체에 접근하고 객체가 있는 곳의 name 멤버 변수에 “학생1” 데이터가 저장된다.
객체 값 읽기
객체의 값을 읽는 것도 앞서 설명한 내용과 같다.
04. 클래스, 객체 인스턴스 정리
객체 vs 인스턴스
둘 다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다.
보통 "student1은 Student의 객체이다." 라고 말하는 대신 "student1은 Student의 인스턴스이다." 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.
05. 배열 도입 - 시작
클래스와 객체 덕분에 데이터를 구조적으로 이해하기 쉽게 변경할 수 있었다.
하지만 출력하는 부분을 보면 새로운 학생이 추가될 때 마다 출력하는 부분도 새로 추가해아 한다.
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
System.out.println("이름:" + student2.name + " 나이:" + student2.age + " 성적:" + student2.grade);
이를 배열을 이용하여 해결한다.
1. ClassStart4 - 배열 사용
package class1;
public class ClassStart4 {
public static void main(String[] args) {
Student 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;
Student[] students = new Student[2];
students[0] = student1;
students[1] = student2;
System.out.println("이름:" + students[0].name + " 나이:" + students[0].age + " 성적:" + students[0].grade);
System.out.println("이름:" + students[1].name + " 나이:" + students[1].age + " 성적:" + students[1].grade);
}
}
배열에 참조값 대입
Student[] students = new Student[2];
- Student 변수를 2개 보관할 수 있는 사이즈 2의 배열을 만든다.
- Student 타입의 변수는 Student 인스턴스의 참조값을 보관한다. 마찬가지로 Student 배열의 각각의 항목도 Student 타입의 변수일 뿐이다. 따라서 Student 타입의 참조값을 보관한다.
- 배열에는 아직 참조값을 대입하지 않았기 때문에 null값으로 초기화된다.
students[0] = student1;
students[1] = student2;
// 자바에서 대입은 항상 변수에 들어있는 값을 복사한다.
students[0] = x001;
students[1] = x002;
💡 자바에서 대입은 항상 변수에 들어있는 값을 복사한다.
student1, student2에는 참조값이 보관되어 있다. 따라서 해당 참조값이 배열에 저장된다.
이 경우 오른쪽 변수인 student1, student2에는 참조값이 들어있다. 그래서 이 값을 복사해서 왼쪽에 있는 배열에 전달한다.
따라서 기존 student1, student2에 들어있던 참조값은 당연히 그대로 유지된다.
⇒ 변수에는 인스턴스 자체가 들어있는 것이 아니다. 인스턴스의 위치를 가리키는 참조값이 들어있을 뿐이다. 따라서 대입 시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.
배열에 참조값을 대입한 이후 배열 그림
배열은 x001, x002 의 참조값을 가진다. 참조값을 가지고 있기 때문에 x001(학생1), x002(학생2) Student 인스턴스에 모두 접근할 수 있다.
배열에 참조값을 대입한 이후 최종 그림
배열에 들어있는 객체 사용
배열에 들어있는 객체를 사용하려면 먼저 배열에 접근하고 이후에 객체에 접근하면 된다.
System.out.println(students[0].name); // 배열 접근
System.out.println(x005[0].name); // [0]를 사용해서 x005 배열의 0번 요소에 접근
System.out.println(x001.name); // .(dot)을 사용해서 참조값으로 객체에 접근
System.out.println("학생1");
06. 배열 도입 - 리팩토링
1. ClassStart5 - 배열 최적화
package class1;
public class ClassStart5 {
public static void main(String[] args) {
Student 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;
Student[] students = new Student[2];
students[0] = student1;
students[1] = student2;
/* 배열 선언 최적화 1 */
// Student[] students = new Student[]{student1, student2};
/* 배열 선언 최적화 2 */
// Student[] students = {student1, student2};
/* for문 */
for (int i=0; i< students.length; i++) {
System.out.println("이름:" + students[i].name + " 나이:" + students[i].age + " 성적:" + students[i].grade);
}
/* for문 - 반복 요소를 변수에 담아서 처리하기 */
for (int i=0; i< students.length; i++) {
Student s = students[i];
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
/* 향상된 for문(Enhanced For Loop) */
for (Student s : students) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
}
}
- 배열 선언 최적화
Student[] students = new Student[]{student1, student2};
Student[] students = {student1, student2};
- for문 최적화
for (int i=0; i< students.length; i++) {
Student s = students[i];
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
for (Student s : students) {
System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
}
'Courses > Java' 카테고리의 다른 글
[김영한의 실전 자바 - 기본편] 3. 객체 지향 프로그래밍 (0) | 2024.05.05 |
---|---|
[김영한의 실전 자바 - 기본편] 2. 기본형과 참조형 (0) | 2024.04.29 |