자바에 대해 얼마나 알고 있나요, 다 안다고 생각했는데 메모리의 개념에 대해서는 놓치고 있었다.
그래서 이번 기회에 다시 처음부터 정리를 해보려고 한다.
Chapter1. 클래스와 데이터
클래스가 필요한 이유
자바 세상은 클래스와 객체로 이루어져 있다. 그만큼 클래스와 객체라는 개념은 중요하다. 그렇다면 클래스가 왜 필요할까?
학생 2명의 정보를 출력하는 프로그램을 작성하려고 하면 아래와 같이 쓸 수 있다.
String studentName1 = "학생1";
int studentAge1 = 15;
int studentGrade1 = 90;
String studentName2 = "학생2";
int studentAge2 = 16;
int studentGrade2 = 80;
배열을 사용할 수도 있다. 하지만 학생이 계속 추가 된다면? 혹은 변경된다면?
지금처럼 이름, 나이, 성적을 각각 따로 나누어서 관리하는 것은 사람이 관리하기 좋은 방식이 아니다.
사람이 관리하기 좋은 방식은 학생이라는 개념을 하나로 묶는 것이다. 여기서 클래스가 필요한 이유이다.
클래스 도입
public class Student {
String name;
int age;
int grade;
}
이렇게 클래스에 정의한 변수들을 멤버 변수, 또는 필드라 한다.
- Member Variable: 이 변수글은 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다
- Field: 데이터 항목을 가리키는 전통적인 용어이다.
- 자바에서 멤버 변수, 필드는 같은 뜻이다.
클래스와 사용자 정의 타입
- 타입은 데이터의 종류나 형태를 나타낸다.
- 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 설계도가 필요하다. 이 설계도가 바로 클래스이다.
- 설계도인 클래스를 사용해서 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.
용어: 클래스, 객체, 인스턴스
클래스는 설계도이고, 이 설계도를 기반으로 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다. 둘다 같은 의미로 사용된다. 여기서는 Student 클래스를 기반으로 student1, student2 객체 또는 인스턴스를 만들었다.
1. 변수 선언
Student student 1
- Student 타입을 받을 수 있는 변수를 선언한다.
- int는 정수를, String은 문자를 담을 수 있듯이 Student는 Student타입의 객체(인스턴스)를 받을 수 있따.
2. 객체 생성
student1 = new Student()
- new는 새로 생성한다는 뜻이다. 그래서 Student 클래스 정보를 기반으로 새로운 객체를 생성하라는 뜻이다. 이렇게 하면 메모리에 실제 Student 객체(인스턴스)를 생성한다.
- 멤버 변수를 사용하는 데 필요한 메모리 공간도 함께 확보한다.
3. 참조관 보관
student1 = x001; //Student 인스턴스 참조값 보관
- 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소)(x001)을 반환한다.
- new 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다.
순서를 그림으로 나타내면 아래와 같다.
참조값을 변수에 보관해야 하는 이유
객체를 생성하는 new Student() 코드 자체에는 아무런 이름이 없다. 이 코드는 단순히 Student 클래스를 기반으로 메모리에 실제 객체를 만드는 것이다. 따라서 생성한 객체에 접근할 수 있는 방법이 필요하다. 이런 이유로 객체를 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다.
Student s1 = new Student(); //1. Student 객체 생성
Student s1 = x001; //2. new Student()의 결과로 x001 참조값 반환
s1 = x001 //3. 최종 결과
객체 사용
클래스를 통해 생성한 객체를 사용하려면 먼저 메모리에 존재하는 객체에 접근해야 한다. 객체에 접근하려면 .을 사용하면 된다.
s1.name = "학생1" //1. s1 객체의 name 멤버 변수에 값 대입
x001.name = "학생1" //2. 변수에 있는 참조값을 통해 실제 객체에 접근, 해당 객체의 name 멤버 변수에 값 대입
클래스, 객체, 인스턴스 정리
클래스-class
클래스는 객체를 생성하기 위한 ‘틀’ 또는 ‘설계도’이다. 클래스는 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 예를 들어 학생이라는 클래스는 속성으로 name, age, grade를 가진다.
객체 - Object
객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태를 가진다. 예를 들어 위 코드에서 student1과 student2는 같은 클래스에서 만들어졌지만, 서로 다른 객체이다.
인스턴스 - Instance
인스턴스는 특정 클래스로부터 생성된 객체를 의미한다. 그래서 객체와 인스턴스라는 용어는 자주 혼용된다. 인스턴스는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용된다. 예를 들어서 student1 객체는 Student 클래스의 인스턴스다라고 표현한다.
객체 vs 인스턴스
둘다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. 보통 student1 은 Student 의 객체이다. 라고 말하는 대신 student1 은 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다. Student 의 인스턴스이다. 좀 더 쉽게 풀어보자면, 모든 인스턴스는 객체이지만, 우리가 인스턴스라고 부르는 순간은 특정 클래스로부터 그 객체가 생성되었음을 강조하고 싶을 때이다. 예를 들어 다는 점을 명확히 하기 위해 student1 student1 을 Student 은 객체이지만, 이 객체의 인스턴스라고 부른다. Student 클래스로부터 생성되 하지만 둘다 클래스에서 나온 실체라는 핵심 의미는 같기 때문에 보통 둘을 구분하지 않고 사용한다.
배열
배열을 사용하면 특정 타입을 연속한 데이터 구조로 묶어서 편리하게 관리할 수 있다.
인스턴스 생성, 배열에 참조값 대입을 할 수 있다.
1. 인스턴스를 생성
2. 배열을 만든다.
3. 배열에 아까 만든 인스턴스(참조값)을 대입한다.
인스턴스 생성 후 배열에 대입하면 배열에 그 인스턴스 값이 들어가는 것이 아니라 참조값이 들어간다.
why? 자바에서 대입은 항상 변수에 들어있는 값을 복사해서 전달한다!
자바에서 변수의 대입(=)은 모두 변수에 들어있는 값을 복사해서 전달하는 것이다. 그래서 이 값을 복사해서 왼쪽에 있는 배열에 전달한다. 따라서 기존 s1, s2에 들어있던 참조값은 당연히 그대로 유지된다.
주의! 변수에는 인스턴스 자체가 들어있는 것이 아니다. 인스턴스의 위치를 가리키는 참조값이 들어있을 뿐이다. 따라서 대입 시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.
Chapter2. 기본형 vs 참조형
기본형은 int, long, double, boolean
참조형은 기본형을 제외한 나머지다. String은 기본형처럼 문자값을 바로 대입할 수 있지만 참조형이다. 문자는 매우 자주 다루기 때문에 자바에서 특별하게 편의 기능을 제공한다.
대원칙: 자바는 항상 변수의 값을 복사해서 대입한다.
기본형은 변수에 값을 대입하더라도 실제 사용하는 값이 변수에 바로 들어있기 때문에 해당 값만 복사해서 대입한다고 생각하면 쉽게 이해할 수 있다. 그런데 참조형의 경우 실제 사용하는 객체가 아니라 객체의 위치를 가르키는 참조값만 복사된다. 쉽게 이야기해서 실제 건물이 복사가 되는 것이 아니라 건물의 위치인 주소만 복사되는 것이다.
아래 코드를 실행하면 dataA의 참조값을 복사해서 dataB에 전달한다.
Data dataA = new Data()
dataA.value=10
Data dataB = dataA
메서드 호출
메서드를 호출할 때 사용하는 매개변수도 결국 변수일 뿐이다. 따라서 메서드를 호출할 때 매개변수에 값을 전달하는 것도 값을 복사해서 전달한다.
기본형과 참조형의 메서드 호출
자바에서 메서들의 매개변수(파라미터)는 항상 값에 의해 전달된다. 그러나 이 값이 실제 값이냐, 참조(메모리 주소)값이냐에 따라 동작이 달라진다.
- 기본형: 메서드는 기본형 데이터를 전달하면, 해당 값이 복사되어 전달된다. 이 경우, 메서드 내부에서 파라미터의 값을 변경해도 호출자의 변수 값에는 영향이 없다.
- 참조형: 메서드로 참조형 데이터를 전달하면, 참조값이 복사되어 전달된다. 이 경우, 메서드 내부에서 파라미터로 전달된 댇체의 멤버 변수를 변경하면, 호출자의 객체도 변경된다.
Chapter3. 객체 지향 프로그래밍
절차 지향 프로그래밍의 한계
지금까지 클래스를 사용해서 관련된 데이터를 하나로 묶고, 또 메서드를 사용해서 각각의 기능을 모듈화했다. 덕분에 상당히 깔끔하고 읽기 좋고, 유지보수 하기 좋은 코드를 작성할 수 있었다. 하지만 여기서 더 개선할 수 없을까?
우리가 작성한 코드의 한계는 바로 데이터와 기능이 분리되어 있다는 점이다. 데이터와 그 데이처를 사용하는 기능은 매우 밀접하게 연관되어 있다.
public class ValueObject {
int value;
void add(){
value++;
System.out.println("숫자 증가 value=" + value);
}
}
인스턴스 생성
ValueObject valueObject = new ValueObject();
'개발 노트 > Java' 카테고리의 다른 글
[MVC Pattern] Model, View, Controller의 관계 (8) | 2024.10.09 |
---|