JAVA

JAVA - 클래스

jonghyeon6084 2024. 1. 1. 14:46
728x90

1. 클래스가 필요한 이유

일단 앞에서 배운 내용을 기반으로 한 예제를 만들어보겠다.


예제 : 학생 정보 출력 프로그램 만들기

 - 두 학생의 정보를 출력하는 프로그램 만들기. 각각 학생의 이름, 나이, 성적을 가지고 있다.

 - 요구사항

    - 첫 번째 학생의 이름은 학생1, 나이는 15, 성적은 90이다.

    - 두 번째 학생의 이름은 학생2, 나이는 16, 성적은 80이다.

    - 각 학생 정보를 출력해보자.

 

String student1Name = "학생1";
int student1Age = 15;
int student1Score = 90;

String student2Name = "학생2";
int student2Age = 16;
int student2Score = 80;

System.out.println("이름 : " + student1Name + ", 나이 : " + student1Age + ", 성적 : " + student1Score);
System.out.println("이름 : " + student2Name + ", 나이 : " + student2Age + ", 성적 : " + student2Score);

 

위 코드의 문제점은 학생이 추가될 때 마다 변수를 추가적으로 선언해야하고, 출력하는 코드도 추가해야한다.

 

배열을 써서 수정해보자.

 

String[] studentNames = {"학생1", "학생2", "학생3", "학생4"};
int[] studentAges = {15, 16, 10, 16};
int[] studentGrade = {90, 80, 80, 50};

for (int i = 0; i < studentNames.length; i++) {
    System.out.println("이름 : " + studentNames[i] + ", 나이 : " +
    studentAges[i] + ", 성적 : " + studentGrade[i]);
}

 

배열을 통해서 나름 정리는 되었지만, 여기서 또 문제점은 학생의 이름, 나이, 점수가 3개의 배열에 나눠져 있어 추가/수정/삭제를 할 경우 어려움이 있다.(순서에 잘 맞게 고쳐야 하기 때문이다.)

 

>> 이와 같이 이름, 나이, 성적을 따로 나눠서 관리하는 것은 사람이 관리하기 좋은 방식이 아니다. 사림이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶는 것이다. 그리고 각각의 학생 별로 본인의 이름, 나이, 성적을 관리하는 것이다.

 

2. 클래스 도입

class를 이용해서 학생 클래스를 정의해보자. 학생 클래스 내부에서는 이름, 나이, 성적 변수를 가진다.

public class Student {
    String name;
    int age;
    int grade;
}

 

위와 같이 클래스에 정의한 변수들을 멤버 변수 또는 필드라 한다.

  • 맴버 변수(Member Variable) : 이 변수들은 특정 클래스에 소속된 맴버이기 때문에 이렇게 부른다.
  • 필드(Field) : 데이터 항목을 가리키는 전통적인 용어이다. 데이터베이스, 엑셀 등에서 데이터 각각의 항목을 필드라 한다.
  • 자바에서 멤버 변수, 필드는 같은 뜻이다. 클래스에 소속된 변수를 뜻한다.

클래스는 관례상 대문자로 시작하고 낙타 표기법을 사용한다.

 

Student student1;
student1 = new Student();
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;

Student student2;
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 과 같은 타입을 직접 만들 수 있다.
  • 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 설계도가 필요하다. 이 설계도가 바로 클래스이다.
  • 설계도인 클래스를 사용해서 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.
  • 클래스를 통해 사용자가 원하는 종류의 데이터 타입을 마음껏 정의할 수 있다.

클래스, 객체, 인스턴스 라는 말이 되게 낯설다.

 

조금 뒤에서 바로 정리해보는 걸로 하자.

 

1. 변수 선언

Student student1; // 변수 선언
  • Student 타입을 받을 수 있는 변수를 선언한다.
  • int 는 정수, String은 문자를 담을 수 있듯이, Student는 Student 타입의 객체(인스턴스)를 받을 수 있다.

2. 객체 생성

student1 = new Student(); // 인스턴스 생성
  • 객체를 사용하려면 먼저 설계도인 클래스를 기반으로 객체(인스턴스)를 생성해야 한다.
  • new Student() : new 는 새로 생성한다는 뜻이다. new Student()는 Student 클래스 정보를 기반으로 새로운 객체를 생성한다는 뜻이다. 이렇게 하면 메모리에 실제 Student 객체(인스턴스)를 생성한다.
  • 객체를 생성할 때는 new 클래스명() 을 사용하면 된다.

3. 참조값 보관

 
student1 = x001 // Student 인스턴스 참조값 보관
  • 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소) x001을 반환한다.
    • 여기서 x001이라고 표현한 것이 참조값이다.(실제로는 x001처럼 표현되는 건 아니고 단지 예시일 뿐.)
  • new 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다. 앞서 선어한 변수인 Student student1 에 생성된 객체의 참조값을 보관한다.
  • Student student1 변수는 이제 메모리에 존재하는 실제 Student 객체(인스턴스)의 참조값을 가지고 있다.
    • student1 변수는 방금 만든 객체에 접근할 수 있는 참조값을 가지고 있다. 따라서 이 변수를 통해서 객체를 접근(참조)할 수 있다. 쉽기 이야기해서 student1 변수를 통해 메모리에 있는 실제 객체를 접근하고 사용할 수 있다.

3. 객체 사용

클래스를 통해 생성한 객체를 사용하려면 먼저 메모리에 존재하는 객체에 접근해야 한다. 객체에 접근하려면 .(dot)를 사용하면 된다.

// 객체 값 대입
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;

// 객체 값 사용
System.out.println("이름 : " + student1.name
	+ " 나이 : " + student1.age + " 성적 : " + student1.grade);

 

4. 클래스, 객체, 인스턴스 용어 정리

클래스 - class

 - 클래스는 객체를 생성하기 위한 '틀' 또는 '설계도'이다. 클래스는 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 

  • 틀 : 붕어빵 틀을 생각해보자. 붕어빵 틀은 붕어빵이 아니다. 이렇게 생긴 붕어빵이 나왔으면 좋겠다라고 만드는 틀일 뿐이다. 실제로 먹을 수 있는 것이 아니다. 실제 먹을 수 있는 팔 붕어빵을 객체 또는 인스턴스라 한다.(이 예시가 좀더 이해가 잘 되는 거 같다.)
  • 설계도 : 자동차 설계도를 생각해보자. 자동차 설계도는 자동차가 아니다. 설계도는 실제 존재하는 것이 아니라 개념으로만 있는 것이다. 설계도를 통해 생산한 실제 존재하는 흰색 테슬라 모델 Y 자동차를 객체 또는 인스턴스라 한다.

객체 - object

 - 객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태를 가진다.

 - 예를 들어 위 코드에서 student1 은 학생1의 속성을 가지는 객체이고, student2는 학생2의 속성을 가지는 객체이다. student1과 student2는 같은 클래스에서 만들어졌지만 서로 다른 객체이다.

 

인스턴스 - instance

 -인스턴스는 특정 클래스로부터 생성된 객체를 의미한다. 그래서 객체와 인스턴스라는 용어는 자주 혼용된다. 인스턴스 는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용한다. 예를 들어서 'student1' 객체는 'Student' 클래스의 인스턴스다. 라고 표현한다.

 

객체 vs 인스턴스

둘다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. 보통 'student1' 은 'Student' 의 객체이다. 라고 말하는 대신 'student1' 은 'Student' 의 인스턴스이다. 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.
좀 더 쉽게 풀어보자면, 모든 인스턴스는 객체이지만, 우리가 인스턴스라고 부르는 순간은 특정 클래스로부터 그 객체가 생성되었음을 강조하고 싶을 때이다. 예를 들어 'student1' 은 객체이지만, 이 객체가 'Student' 클래스로부터 생성된다는 점을 명확히 하기 위해 'student1' 을 'Student' 의 인스턴스라고 부른다.

 

5. 배열 도입 - 시작

 배열을 사용하면 특정 타입을 연속한 데이터 구조를 묶어서 편리하게 관리할 수 있다. Student 클래스를 사용한 변수들도 Student 타입이므로 학생도 배열을 사용해 하나의 데이터 구조로 묶어서 관리할 수 있다.

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);

6. 배열 도입 - 리펙토링

배열을 이용했으니 for문을 사용할 수 있다.

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 = {student1,student2};

// 첫 번째로 내가 작성한 코드
for (int i = 0; i < students.length; i++) {
    System.out.println("이름 : " + students[i].name + " 나이 : " + students[i].age + " 성적 : " + students[i].grade);
}
// 변수를 이용해서 좀 더 간결하게 사용 가능
for (int i = 0; i < students.length; i++) {
    Student s = students[i];
    System.out.println("이름 : " + s.name + " 나이 : " + s.age + " 성적 : " + s.grade);
}
// for-each문을 통해 더더 간결하게 사용 가능(참 익숙해지지 않는다..)
for (Student s : students) {
    System.out.println("이름 : " + s.name + " 나이 : " + s.age + " 성적 : " + s.grade);
}