본문 바로가기

Java

[Java] 클래스가 필요한 진짜 이유 (feat.객체 vs 인스턴스)

자바는 클래스객체라는 중요한 개념이 있습니다.

그럼 오늘은 클래스와 객체라는 것이 왜 필요하고 자바의 세상을 이해해보는 시간을 가져보겠습니다.

 

먼저 클래스가 왜 필요한지 이해하기 위해서 다음 예제를 가져와보겠습니다.

 

요구사항:

  1. 첫 번째 학생의 이름은 "학생1", 나이는 15, 성적은 90입니다
  2. 두 번째 학생의 이름은 "학생2", 나이는 16, 성적은 80입니다.
  3. 각 학생의 정보를 다음과 같은 형식으로 출력해야 합니다. "이름: [이름]  나이:[나이]  성적:[성적]"
  4. 변수를 사용해서 학생 정보를 저장하고 변수를 사용해서 학생 정보를 출력해야 합니다.

예시출력:

이름:학생1 나이:15 성적:90
이름:학생2 나이:16 성적:80

 

 

package class1;

public class ClassStart1Ref {

    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명을 다루어야 하기 때문에 각각 다른 변수를 사용했습니다. 그럼 이 코드의 문제점이 무엇일까요?

이 코드의 문제점은 학생이 늘어날 때 마다 변수를 추가적으로 선언해야 하고, 또 출력하는 코드도 추가해야겠죠?

 

그럼 이런 문제를 배열을 통해 학생이 추가되어도 코드 변경이 최소화 될 수 있게 만들어볼까요?

package class1;

public class ClassStart2 {

    public static void main(String[] args) {
        String[] studentName = {"학생1", "학생2"};
        int[] studentAge = {15, 16};
        int[] studentGrade = {80, 90};

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

 

배열 사용의 한계

배열을 사용해서 코드 변경을 최소화 하는데는 성공했지만, 한 학생의 데이터가

studentName[ ], studentAge[ ], studentGrade[ ] 라는 3개의 배열로 나누어져 있습니다.

따라서 만약 2번 학생만의 데이터를 제거하려면 각각의 배열마다 학생 2의 요소를 정확하게 찾아서 제거 해줘야 합니다.

이는, 데이터를 변경할 경우 매우 조심해서 작업해야 한다는 한계가 있습니다.

 

더 자세히 말하자면 한 학생의 데이터가 3개의 배열에 나누어져 있기 때문에 3개의 배열을 각각 변경해야 합니다.

그리고 한 학생의 데이터를 관리하기 위해 3개의 배열의 인덱스 순서를 항상 정확하게 맞추어야 합니다.

지금은 학생 3명의 데이터를 관리한다고 하지만, 만약 이것이 100명, 1000명이 되면 50080% 실수가 일어날 수 있습니다.

 

아마 지금처럼 이름, 나이, 성적을 각각 따로 나누어서 관리하는 것은 사람이 관리하기 좋은 방식이 아닐 껍니다.

사람이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶고,

각각의 학생 별로 본인의 이름, 나이, 성적을 관리하는 것 아닐까요?

 

클래스 사용

앞에서 말한 문제를 클래스를 도입해서 해결해볼까요?

클래스를 사용해서 학생이라는 개념을 만들고, 각각의 학생 별로 본인의 이름, 나이, 성적을 관리해봅시다.

 

Student 클래스

package class1;

public class Student {

        String name;
        int age;
        int grade;
}

 

class 키워드를 사용해서 학생 클래스(Student)를 정의했습니다.

학생 클래스 내부에는 이름(name), 나이(age), 성적(grade) 변수를 가집니다.

 

이렇게 클래스에 정의한 변수들을 멤버 변수, 또는 필드라 합니다.

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

클래스는 관례상 대문자로 시작하고 낙타표기법(카멜) 을 사용합니다.

예) Student, User, MemberService

 

그럼 이제 학생 클래스를 어떻게 사용해야 할까요?

학생 클래스를 사용하는 코드를 작성해보겠습니다.

 

package class1;

public class ClassStart3 {

    public static void main(String[] args) {

        Student student1; // 첫 번째 학생을 담아둘 수 있는 변수를 선언
        student1 = new Student(); // student1 객체선언
        student1.name = "학생1"; // .연산자를 통해서 접근가능
        student1.age = 15;
        student1.grade = 90;

        Student student2; // 두 번째 학생을 담아둘 수 있는 변수를 선언
        student2 = new Student(); // student2 객체선언
        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 타입의 객체(인스턴스)를 받을 수 있다.

 

2. 객체 생성

student1 = new Student(); // Student 인스턴스 생성
  • 객체를 사용하려면 먼저 설계도인 클래스를 기반으로 객체(인스턴스)를 생성해야 한다.
  • new Student( ): new는 새로 생성한다는 뜻이다. new Student( )Student 클래스 정보를 기반으로 새로운 객체를 생성하라는 뜻이다. 이렇게 하면 메모리에 실제 Student 객체(인스턴스)를 생성한다.
  • 객체를 생성할 때는 new 클래스명( )을 사용하면 된다. 마지막에 ( )도 추가해야 한다.
  • Student 클래스는 String name, int age, int grade 멤버 변수(필드)를 가지고 있다. 이 변수를 사용하는데 필요한 메모리 공간도 함께 확보한다.

 

3. 참조값 보관

설명을 위해서 x001 이라고 표현한 것이 참조값이다.

student1 = x001; // Student 인스턴스 참조값 보관
  • 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소)(x001)을 반환한다.
  • new 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다. 앞서 선언한 변수인 Student student1에 생성된 객체의 참조값(x001)을 보관한다.
  • Student student1 변수는 이제 메모리에 존재하는 실제 Student 객체(인스턴스)의 참조값을 가지고 있다.
  • student1 변수는 방금 만든 객체에 접근할 수 있는 참조값을 가지고 있다. 따라서 이 변수를 통해서 객체를 접근(참조)할 수 있다.

쉽게 얘기하면 student1 변수를 통해서 메모리에 있는 실제 객체를 접근하고 사용할 수 있다는 것 입니다.

참조값을 변수에 보관해야 하는 이유

객체를 생성하는 new Student( ) 코드 자체에는 아무런 이름이 없다.
이 코드는 단순히 Student 클래스를 기반으로 메모리에 실제 객체를 만드는 것이다.
따라서 생성한 객체에 접근할 수 있는 방법이 필요하다.
이런 이유로 객체를 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다. 앞서 Student student1 변수에
참조값(x001)을 저장해두었으므로 저장한 참조값(x001)을 통해서 실제 메모리에 존재하는 객체에 접근할 수 있다.

 

Student student1 = new Student(); // 1. Student 객체 생성
Student student1 = x001; // 2. new Student()의 결과로 x001 참조값 반환
student1 = x001; // student1 변수를 통해 메모리에 있는 실제 객체를 접근, 사용가능

 

이후에 학생2(student2)까지 생성하면 다음과 같이 Student 객체(인스턴스)가 메모리에 2개 생성됩니다.

각각 참조값이 다르므로 서로 구분할 수 있습니다.

참조값이 궁금하다면 출력해보면 됩니다.

System.out.println(student1);
System.out.println(student2);

 

저의 참조값을 한번 봐볼까요?

@앞은 패키지 + 클래스 정보를 뜻합니다.&nbsp; &nbsp; @뒤에는 16진수는 참조값이라고 합니다.

 

객체 사용

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

객체에 접근하려면 .(점)을 사용하면 됩니다.

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

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

 

객체에 값 대입

객체가 가지고 있는 멤버 변수(name, age, grade)에 값을 대입하려면 먼저 객체에 접근해야 합니다.

객체에 접근하려면 .(점) 키워드를 사용하면 됩니다.

이 키워드는 변수(student1)에 들어있는 참조값(x001)을 읽어서 메모리에 존재하는 객체에 접근합니다.

student1.name = "학생1" // 1. student1 객체의 name 멤버 변수(필드)에 값 대입
x001.name = "학생1" // 2. 변수에 있는 참조값을 통해 실제 객체에 접근, 해당 객체의 name 멤버 변수에 값 대입

 

student1.(점)이라고 하면 student1 변수가 가지고 있는 참조값을 통해 실제 객체에 접근한다.

student1x001 이라는 참조값을 가지고 있으므로 x001 위치에 있는 Student 객체에 접근한다.

 

그림으로 살펴봅시다.

student1.name = "학생1" 코드 실행 전

 

student1.name = "학생1" 코드 실행 후

  • student1.name 코드를 통해 .(dot) 키워드가 사용되었다. student1 변수가 가지고 있는 참조값을 통해 실제 객체에 접근한다.
  • x001.name = "학생1" : x001 객체가 있는 곳의 name 멤버 변수에 "학생1" 데이터가 저장된다.

객체에 값 읽기

객체의 값을 읽는 것도 앞서 설명한 내용과 같습니다. 

.(점) 키워드를 통해 참조값을 사용해서 객체에 접근한 다음에 원하는 작업을 하면 됩니다.

// 1. 객체 값 읽기
System.out.println("이름: " + student1.name);
// 2. 변수에 있는 참조값을 통해 실제 객체에 접근하고, name 멤버 변수에 접근한다.
System.out.println("이름: " + x001.name);
// 3. 객체의 멤버 변수의 값을 읽어옴
System.out.println("이름: " + "학생1");

 

클래스, 객체, 인스턴스 정리

클래스: Class

 

클래스는 객체를 생성하기 위한 '틀' 또는 '설계도' 입니다.

클래스는 객체가 가져야 할 속성(변수)기능(메서드)를 정의합니다.

예를 들어 학생이라는 클래스는 속성으로 name, age, grade 를 가집니다.

  • 틀: 붕어빵 틀은 붕어빵이 아닙니다. 이렇게 생긴 붕어빵이 나왔으면 좋겠다고 만드는 틀일 뿐입니다. 실제 먹을 수 있는 것도 아니고요. 실제 먹을 수 있는 팥 붕어빵을 객체 또는 인스턴스라고 합니다.
  • 설계도: 자동차 설계도를 생각해봅시다. 자동차 설계도는 자동차가 아닙니다. 설계도는 실제 존재하는 것이 아니라 개념으로만 있는 것입니다. 설계도를 통해 생산할 실제 존재하는 자동차를 객체 또는 인스턴스라고 합니다.
객체: Object

 

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

예를 들어 위 코드에서 student1은 학생1의 속성을 가지는 객체이고, student2는 학생2의 속성을 가지는 객체입니다.

student1student2는 같은 클래스에서 만들어졌지만, 서로 다른 객체입니다.

 

인스턴스: Instance

 

인스턴스는 특정 클래스로부터 생성된 객체를 의미합니다. 그래서 객체와 인스턴스는 용어는 자주 혼용됩니다.

인스턴스는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용합니다.

예를 들어 student1 객체는 Student 클래스인스턴스이다. 라고 표현합니다.

 

객체 vs 인스턴스

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

 

하지만 둘다 클래스에서 나온 실체라는 핵심 의미를 갖기 때문에 보통 둘을 구분하지 않고 사용한다고 합니다.

 

 

'Java' 카테고리의 다른 글

[Java] 기본형 VS 참조형  (0) 2024.02.28
[Java] 클래스에 배열 사용  (0) 2024.02.26
[Java] 메서드 A 부터 Z 까지 (feat. 오버로딩)  (1) 2024.02.23
[Java] 향상된 for문  (0) 2024.02.18
Java 너 도대체 뭐니?  (0) 2024.02.17