[김영한의 실전 자바 - 기본편] 1. 클래스와 데이터, 기본형과 참조형
본 게시글은 김영한님의 인프런(Inflean)강의 김영한의 실전 자바 - 기본편 강의를 수강하고 공부한 내용을 정리한 글입니다.
1. 클래스가 필요한 이유
여러 명의 학생 정보(이름, 나이, 성적)를 저장하고 출력하는 프로그램을 만든다고 가정해보자. 학생 수 가 적을 경우에는 다른 변수를 선언하거나 배열에 저장해 출력할 수 있다. 그러나 학생수가 늘어날 수록 수정해야 할 코드가 많아지고, 데이터를 수정하며 문제가 발생할 가능성이 높다. 따라서 학생이란 개념 안에 이름, 나이, 성적을 함께 관리하는 것이 효율적이다. 이러한 이유로 만들어진 학생이란 개념이 바로 클래스이다.
1.1 클래스 도입
package class1;
public class Student {
String name;
int age;
int grade;
}
class 키워드를 사용해 학생 클래스(class)를 정의한다. 학생 클래스에는 내부에 이름(name), 나이(age), 성적(grade) 변수를 가진다.
클래스에 정의한 변수들을 멤버 변수 또는 필드라고 한다.
- 멤버 변수(Member Variable): 이 변수들을 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다.
- 클래스에 사용하면 int, String과 같은 타입을 직접 만들 수 있다.
- 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 설계도가 필요하다. 설계도 = 클래스
- 설계도인 클래스를 사용해서 실제 메모리에 만들어진 실제를 객체 또는 인스턴스라 한다.
- 클래스를 통해서 사용자가 원하는 종류의 데이터 타입을 마음껏 정의할 수 있다.
1.2 객체사용
클래스를 통해 생성한 객체를 사용하려면, 먼저 메모리에 존재하는 객체에 접근해야 한다. 객체에 접근하려면 .(점, dot)을 사용하면 된다. 이 키워드는 변수에 들어있는 참조값을 읽어서 메모리에 존재하는 객체에 접근한다.
2. 클래스, 객체, 인스턴스 정리
2.1 클래스 - Class
클래스는 객체를 생성하기 위한 '틀' 또는 '설계도'로 객체가 가져야 할 속성(변수)와 기능(메서드)를 정의한다. 다음 예시를 확인해보자.
- 틀: 붕어빵 틀을 생각해보자. 붕어빵 틀은 붕어빵이 아니다! 이렇게 생긴 붕어빵이 나왔으면 좋겠다고 만드는 틀일뿐이다. 실제 먹을 수 있는 것이 아니다. 실제 먹을 수 있는 팥 붕어빵을 객체 또는 인스턴스라 한다.
- 설계도: 자동차 설계도를 생각해보자. 자동차 설계도는 자동차가 아니다! 설계도는 실제 존재하는 것이 아니라 개념으로만 있는 것이다.
2.2 객체 - Object
객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태를 가진다.
ex) student1은 학생의 속성을 가지는 객체이고, student2는 학생2의 속성을 가지는 객체이다. student1과 stuent2는 같은 클래스에서 만들어졌지만, 서로 다른 객체이다.
2.3 인스턴스 - Instance
특정 클래스로부터 생성된 객체를 의미한다. 객체와 인스턴스라는 용어는 자주 혼용된다. 인스턴스는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용한다.
ex) student1의 객체는 Student 클래스의 인스턴스다.
2.4 객체 vs 인스턴스
용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. student1은 Student의 객체이다. 라고 말하는 대신 student1은 Student의 인스턴스이다. 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.
모든 인스턴스는 객체이지만, 인스턴스라고 부르는 순간은 특정 클래스로부터 그 객체가 사용되었음을 강조하고 싶을 때이다.
자바에서 대입(=)은 항상 모든 변수에 들어가는 값을 복사해서 전달한다.
변수에는 인스턴스 자체가 들어있는 것이 아니라 인스턴스의 위치를 가리키는 참조값이 들어있다. 따라서 대입(=)시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.
3. 기본형과 참조형
- 기본형
- int, long, double, boolean 처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
- 숫자 10, 20 과 같이 실제 사용하는 값을 변수에 담을 수 있다. 그래서 해당 값을 바로 사용할 수 있다.
- 들어있는 값을 그대로 계산에 사용할 수 있다.
- 소문자로 시작한다. ex) int, long, double, boolean
- 개발자가 직접 정의할 수 없다.
- null을 할당할 수 없다.
- 값 복사 전달
- 메서드 내부 변경 시 호출자 변수 영향 없음.
- 참조형
- Student student1, int[] students 와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입
- 실제 사용하는 값을 변수에 담는 것이 아니다. 이름 그대로 실제 객체의 위치(참조, 주소)를 저장한다. 참조형에는 객체와 배열이 있다.
- 객체는 .(dot)을 통해서 메모리 상에 생성된 객체를 찾아가야 사용할 수 있다.
- 배열은 [] 를 통해서 메모리 상에 생성된 배열을 찾아가야 사용할 수 있다.
- 참조값을 그대로 계산에 사용할 수 없다. 주소지만 가지고는 할 수 있는게 없고 주소지에 가야 실체가 있다.
- 대문자로 시작한다.
- 참조형인 클래스는 개발자가 직접 정의할 수 있다.
- null을 할당할 수 있다.
- 참조값 복사 전달
- 메서드 내부 변경 시 호출자 객체도 변경
참고: 자바에서 String은 특별하다. String은 사실은 클래스다. 따라서 참조형이다. 그런데 기본형처럼 문자 값을 바로 대입할 수 있다. 문자는 매우 자주 다루기 때문에 자바에서 특별하게 편의 기능을 제공한다.
자바의 대원칙: 자바는 항상 모든 변수에 들어가는 값을 복사해서 전달한다.
변수에는 인스턴스 자체가 들어있지 않고, 인스턴스의 위치를 가리키는 참조값만 들어있다. 따라서 대입 시 인스턴스가 아닌 참조값만 복사된다.
3.1 변수와 초기화
- 멤버 변수(필드)
- 클래스에 선언
- 자동 초기화
- 인스턴스의 멤버변수는 인스턴스를 생성할 때 자동으로 초기화된다.
- 숫자(int) = 0, boolean = false, 참조형 = null(null 값은 참조할 대상이 없다는 뜻으로 사용)
- 개발자가 초기값 직접 지정할 수 있다.
- 지역 변수
- 메서드에 선언: 매개변수도 지역 변수의 한 종류이다.
- 수동 초기화
- 항상 직접 초기화해야 한다.
3.2 null과 Garbage Collection
참조형 변수에서 아직 가리키는 대상이 없다면 null이라는 특별한 값을 넣어둘 수 있다. null은 값이 존재하지 않는 없다는 뜻이다. 참고로 0이나 공백과는 다르다.
public class NullMain1 {
public static void main(String[] args) {
Data data = null; // Data 타입 변수를 만들고 null 저장.
System.out.println("1. data = " + data);
data = new Data(); // 위에서 선언한 변수에 새로운 객체의 참조값(x001) 저장
System.out.println("2. data = " + data);
data = null; // 새로운 객체의 참조값을 null로 덮어 씌움
System.out.println("3. data = " + data);
}
}
실행결과
1. data = null
2. data = ref.Data@x001
3. data = null
- data에 null 값을 할당해 생성한 Data 인스턴스는 아무도 참조하지 않게된다.
- 아무도 사용하지 않는 인스턴스는 사용되지 않고 메모리 용량만 차지할 뿐이다.
- 자바에서는 아무도 참조하지 않는 인스턴스를 JVM의 GC(가비지 컬렉션)가 자동으로 메모리에서 제거해준다. 해당 객체를 참조하는 곳이 모두 사라지면 JVM은 필요 없는 객체로 판단다고 GC(가비지 컬렉션)를 사용해서 제거한다.
참고: JVM의 GC는 개발자가 더 이상 쓰지 않는 인스턴스를 하나하나 메모리에서 없애는 것보다 더 효율적으로 동작한다. 더 이상 쓰지 않는 인스턴스를 모아 한꺼번에 제거한다.
3.3 NullPointerException
참조값 없이 객체를 찾아가면 NullPointerException 이라는 예외가 발생한다. 이름 그대로 null 을 가리키다(Pointer)인데, 이때 발생하는 예외(Exception)다. null 은 없다는 뜻이므로 결국 주소가 없는 곳을 찾아갈 때 발생하는 예외이다.
- 객체를 참조할 때는 .(dot)을 사용한다. 이렇게 하면 참조값을 사용해서 해당 객체를 찾아갈 수 있다. 그런데 참조값이 null 이라면 값이 없다는 뜻이므로, 찾아갈 수 있는 객체(인스턴스)가 없다.
- NullPointerException은 이처럼 null 에 .(dot)을 찍었을 때 발생한다.