본문 바로가기

Java

[Java] 클래스에 배열 사용

아직 클래스가 어떤 것인지 왜 필요한지 모르는 것 같다 싶으시면 해당 포스팅 먼저 보시는 것을 권장드립니다!

 

 

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

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

madeprogame.tistory.com

 


 

지난 시간에 클래스가 뭐하는 것인지에 대해 알아보았습니다.

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; // 두 번째 학생을 담아둘 수 있는 변수를 선언
        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);

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

    }
}

 

 

 

클래스와 객체 덕분에 학생 데이터를 구조적으로 이해하기 쉽게 변경할 수 있었습니다.

마치 실제 학생이 있고, 그 안에 각 학생의 정보가 담겨있는 것 같지 않았습니까?

이제 각각의 학생 별로 객체를 생성하고, 해당 객체에 학생의 데이터를 관리하면 됩니다.

System.out.println("이름: " + student1.name + " 나이:" + student1.age + " 성적: " + student1.grade);
System.out.println("이름: " + student2.name + " 나이:" + student2.age + " 성적: " + student2.grade);

 

하지만 출력하는 부분을 보면 아쉬운 생각이 안 들수 없습니다.

새로운 학생들이 추가 될 때 마다 출력하는 부분도 함께 추가해줘야 한다는 점이죠..

 

배열을 사용하여 특정 타입을 연속한 데이터 구조로 묶어서 편리하게 관리할 수 있었습니다. (ex. int [ ], String [ ] )

Student 클래스를 사용한 변수들도 Student [사용자정의] 타입 이기 때문에 학생도 배열을 사용하여 하나의 데이터 구조로

묶어서 관리할 수 있지 않을까요? 이번에는 Student 타입을 사용하는 배열을 사용해보겠습니다.

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 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 클래스를 기반으로 student1, student2 인스턴스를 생성했습니다. 그리고 필요한 값들을 채워주었습니다.

배열에 참조값 대입

이번에는 Student를 담을 수 있는 배열을 생성하고, 해당 배열에 student1, student2 인스턴스를 보관하였습니다.

Student[] students = new Student[2];

  • Student 변수를 2개 보관할 수 있는 사이즈 2의 배열을 만든다.
  • Student 타입의 변수는 Student 인스턴스의 참조값을 보관한다. Student 배열의 각각의 항목도 Student 타입의 변수일 뿐이다. 따라서 Student 타입의 참조값을 보관한다.
  • student1, student2 변수를 생각해보면 Student 타입의 참조값을 보관한다.
  • 배열에는 아직 참조값을 대입하지 않았기 때문에 참조값이 없다는 의미의 null으로 초기화 된다.

이제 배열에 객체를 보관하겠습니다.

students[0] = student1;
students[1] = student2;

// 자바에서 대입은 항상 변수에 들어 있는 값을 복사한다.
student[0] = x001;
student[1] = x002;

 

student1, student2 에는 참조값이 보관되어 있다. 따라서 이 참조값이 배열에 저장된다.

또는 student1, student2 에 보관된 참조값을 읽고 복사하여 배열에 대입한다고 표현한다.

 

배열에 참조값을 대입한 이후 배열 그림

이제 배열은 x001, x002의 참조값을 가집니다.

참조값을 가지고 있기 때문에 x001(학생1), x002(학생2), Student 인스턴스에 모두 접근할 수 있습니다.

 

배열에 참조값을 대입한 이후 최종 그림

자바에서 변수의 대입( = )은 모두 변수에 들어있는 값을 복사해서 전달하는 것 입니다.

이 경우 오른쪽 변수인 student1, student2에는 참조값이 들어있습니다.

그래서 이 값을 복사해서 왼쪽에 있는 배열에 전달한다.

따라서 기존 student1, student2에 들어있던 참조값은 당연히 그대로 유지된다.

 

주의!

변수에는 인스턴스 자체가 들어있는 것이 아닙니다! 인스턴스의 위치를 가리키는 참조값이 들어있을 뿐 입니다.

따라서 대입( = )시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.

 

배열에 들어있는 객체 사용

배열에 들어있는 객체를 사용하려면 먼저 배열에 접근하고, 그 다음에 객체에 접근하면 된다.

System.out.println(students[0].name); // 배열 접근 시작
System.out.println(x004[0].name); // [0]을 사용해서 x005 배열의 0번 요소에 접근
System.out.println(x001.name); // . (점)을 사용해서 참조값으로 객체에 접근
System.out.println("학생1");

 

System.out.println(students[1].name); // 배열 접근 시작
System.out.println(x004[1].name); // [1]을 사용해서 x005 배열의 1번 요소에 접근
System.out.println(x002.name); // . (점)을 사용해서 참조값으로 객체에 접근
System.out.println("학생2");

 

배열 사용 - 리펙토링

배열을 사용한 덕분에 출력부분에서 다음과 같이 for문을 도입할 수 있었습니다.

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

        for (int i = 0; i < students.length; i++){
            System.out.println("이름: " + students[i].name + " 나이: " + students[i].age + "성적: " + students[i].grade);
        }
    }
}

 

배열 선언 최적화

저희가 직접 정의한 Student 타입도 일반적인 변수와 동일하게 배열을 생성할 때 포함할 수 있습니다.

Student[] students = new Student[]{student1, student2};

 

생성과 선언을 동시에 하는 경우에는 더욱 최적화 할 수 있습니다.

Student[] students = {student1, student2};

 

for문 최적화

배열을 사용한 덕분에 for문을 사용해서 반복 작업을 깔끔하게 처리할 수 있습니다.

 

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문

for (Student s : students){
            System.out.println("이름: " + s.name + " 나이: " + s.age + "성적: " + s.grade);;
        }