728x90
참조 자료형이란?
- 크기가 정해진 기본 자료형(int, char, float, double 등) 으로 선언하는 변수 뿐만 아니라 클래스 자료형으로 선언하는 참조 자료형 변수가 있다.
- 예를 들어보면서 알아보겠습니다.
- 어떤 학생이 국어와 수학 과목을 수강하는데, 시험을 본 후 국어 성적과 수학 성적 정보를 저장하는 프로그램을 만들려고 합니다.
- 객체 지향 프로그래밍을 시작할 때는 일단 클래스를 어떻게 만들지 생각해야합니다.
package reference;
public class Student1 {
int studentID;
String studentName;
int koreaScore;
int mathScore;
}
- 위의 예제에는 String 이 JDK(Java Development Kit)에서 제공하는 참조 자료형입니다.
- 나머지 변수는 기본 자료형입니다.
- 그런데, 다음과 같은 경우가 있을 수 있습니다.
- 성적을 저장하는 변수가 두 개 있는데, 만약 성적뿐만 아니라 이 학생이 수강하는 과목의 이름도 함께 저장해야 한다면 어떻게 할까요? 지금까지 아는 방법으로는 String 을 사용해서 과목 이름 변수까지 추가할 수 있습니다.
package reference;
public class Student2 {
int studentID;
String studentName;
int koreaScore;
int mathScore;
String koreaSubject;
String mathSubject;
}
- 이렇게 구현하고 보니, 맘에 들지 않습니다.
- 왜냐하면, 이 클래스는 student 클래스인데도 불구하고 과목에 대한 변수가 생겨났기 때문입니다.
- 이 문제를 해결하기 위해 과목의 이름과 성적을 Subject 라는 클래스로 분리하고, 학생에 Subject 변수를 각 과목별로 추가해 보겠습니다.
package reference;
public class Subject {
String subjectName;
int scorePoint;
}
package reference;
public class Student3 {
int studentID;
String studentName;
Subject korean;
Subject math;
}
- 과목을 의미하는 Subject라는 클래스를 만들었습니다.
- Subject 클래스는 과목의 이름과 점수를 멤버 변수로 가지고 있습니다.
- 또한 Student 클래스는 Subject 클래스를 멤버 변수로 가지면 됩니다.
- 이것을 그림으로 표현하면 다음과 같습니다.

- 이렇게 구현하면 달라지는 것이 무엇일까요?
- 기존의 Student2 클래스에 과목 이름을 추가해야 한다면, koreanSubjectName, mathSubjectName 이렇게 두 개의 변수를 추가해야 할 것입니다. 하지만 Subject로 클래스를 분리하면 subjectName 은 Subject 클래스에 선언하면 됩니다.
헷갈렸던 점 (전반부)
- 참조 자료형을 만든 다음, 참조 자료형 안에 담겨 있는 멤버 변수와 멤버 메소드를 어떻게 사용하는 것인지 헷갈렸다.
- 특히, main 함수를 별도의 test 파일을 만들어서 실행시킬 때를 연습했는데, 처음에는 이게 어떻게 해야 작동하는지 잘 이해하지 못했다.
- 아래 코드는 내가 이해한 것들을 바탕으로 연습하면서 작성한 코드다. 총 3개 파일로 구성되어 있다.
package reference;
public class Student3 {
int studentID;
String studentName;
Subject korean;
Subject math;
public Student3(int id, String name) {
studentID = id;
studentName = name;
}
public void showStudent3Info() {
System.out.println("학번 : " + this.studentID);
System.out.println("이름 : " + this.studentName);
System.out.println("과목명 :" + this.korean.subjectName);
System.out.println("점수 :" + this.korean.scorePoint);
System.out.println("과목명 :" + this.math.subjectName);
System.out.println("점수 :" + this.math.scorePoint);
}
}
package reference;
public class Subject {
String subjectName;
int scorePoint = 0;
public Subject(String name, int score) {
subjectName = name;
scorePoint = score;
}
}
package reference;
public class StudentTest1 {
public static void main(String[] args) {
Student3 kimStudent3 = new Student3(2017105249, "KIM Byung");
kimStudent3.korean = new Subject("korean", 80);
kimStudent3.math = new Subject("math", 80);
kimStudent3.showStudent3Info();
}
}
- 생성자와 참조 자료형을 활용하여 객체 지향 프로그램을 하나 만들었다.
헷갈렸던 점 (후반부)
- 나는 Student3 클래스의 인스턴스인 Kim를 우선 만들고, Kim 안에 Subject 의 인스턴스인 math 와 korean 을 생성하는 순서로 작성했다. 이 순서를 그림으로 표현하면 아래와 같다.
Student3 Kim [인스턴스 생성]
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
kim.math = new Subject [인스턴스 생성]
- 이런 방식으로 내가 코드를 작성했던 이유를 생각해 보자면, 지금 예시가 학생과 학생의 성적이다 보니까, 모든 경우가 고유한 케이스이고 그에 따라서 재사용을 전혀 염두에 두지 않고 작성을 해서 그렇게 생각을 했다.
- 무슨 말이냐면, 학생A 가 수학 80점을 받았다. 이것을 나는 아주 고유한 일이라고 생각했는데, 그렇지 않고 학생B가 수학 80점을 받았다면 수학 80점을 받은 그 자체가 재사용이 가능한 것이다.
- 이런 점을 고려하면 다음과 같이 코드를 수정할 수 있었다.
package reference;
public class Subject {
String subjectName;
int scorePoint;
public Subject(String subjName, int scorePoint) {
this.subjectName = subjName;
this.scorePoint = scorePoint;
}
}
package reference;
public class Student3 {
int studentID;
String studentName;
Subject korean;
Subject math;
public Student3(int studentId, String studentName, Subject korean, Subject math) {
this.studentID = studentId;
this.studentName = studentName;
this.korean = korean;
this.math = math;
}
@Override
public String toString() {
return "Student3 [studentID=" + studentID + ", studentName=" + studentName + ", korean=" + korean + ", math="
+ math + "]";
}
}
package reference;
public class StudentTest1 {
public static void main(String[] args) {
Subject math = new Subject("math", 80);
Subject korean = new Subject("korean", 75);
Student3 kim = new Student3(2011102546, "Kim Byungsun", korean, math);
System.out.println(kim.toString());
Student3 kim2 = new Student3(2011102546, "Kim2 Byungsun", korean, math); //korean 과 math 는 kim 과 kim2 가 동일하므로 해당 참조변수를 그대로 상요하면 된다.
System.out.println(kim2.toString());
Subject math2 = new Subject("math", 70);
Subject korean2 = new Subject("korean", 75);
Student3 kim3 = new Student3(2011102546, "Kim3 Byungsun", korean2, math2);
System.out.println(kim3.toString());
}
}
- StudentTest1 클래스에서 kim 과 kim2 인스턴스는 math 라는 Subject 의 인스턴스를 동일하게 가져가도 문제가 없다.
- 이런 경우 kim2 는 kim 이전에 만들어 두었던 math 와 korean을 그대로 사용하면 된다.
- 참조 자료형을 먼저 만들어야 하므로 생성의 순서도 위와 달리 아래의 그림과 같이 바뀌었다.
Subject math = new Subject("math", 80);
Subject korean = new Subject("korean", 75);
[참조 자료형의 인스턴스 먼저 생성]
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Student3 kim = new Student3(2011102546, "Kim Byungsun", korean, math);
[참조 자료형을 멤버 변수로 갖는 클래스의 인스턴스를 나중에 생성]
추가 이해 자료
- 이해를 돕기 위해 추가 실습 자료를 만들었습니다.
package reference.quiz;
class Department {
String boss;
String researcher;
String headResearcher;
public Department(String boss, String researcher, String headResearcher) {
super();
this.boss = boss;
this.researcher = researcher;
this.headResearcher = headResearcher;
}
}
class Employee {
String name;
int age;
int wage;
int workingYear;
Department managing;
public Employee(String name, int age, int wage, int workingYear, Department managing) {
super();
this.name = name;
this.age = age;
this.wage = wage;
this.workingYear = workingYear;
this.managing = managing;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", wage=" + wage + ", workingYear=" + workingYear
+ ", managing=" + managing + "]";
}
}
public class Quiz2 {
public static void main(String[] args) {
Department managing = new Department("경영 보스", "경영 연구원", "경영 수석 연구원");
Employee shin = new Employee("SHIN HANBEEN", 26, 5000000, 10, managing);
System.out.println(shin.toString());
}
}