- Java 세팅 및 실습은 Windows 환경에서 IntelliJ를 통해 진행되었습니다.
2. 자바의 변수와 메모리 구조 (응용편)
- Java에서 변수는 크게 기본형 변수(Primitive Type)와 참조형 변수(Reference Type)로 나뉩니다.
- 이 두 가지는 메모리 구조, 사용 방법, 그리고 메서드와 클래스에서의 특징 등에서 차이가 있습니다.
2-1. 기본형 변수와 참조형 변수
기본형 변수 (Primitive Type)
- 기본형 변수는 Java에서 가장 기본적인 데이터 타입입니다.
- Java는 총 8가지의 기본형 타입을 제공합니다
- 정수형:
byte
, short
, int
, long
- 실수형:
float
, double
- 문자형:
char
- 논리형:
boolean
- 기본형 변수는 실제 값을 직접 저장하며, 메모리의 스택(Stack) 영역에 저장됩니다.
- 메모리 영역에 대해선 밑에서 다시 정리할 예정입니다.
int age = 25;
double salary = 3000.50;
char grade = 'A';
boolean isStudent = true;
- 위 예시에서, age, salary, grade, isStudent 변수는 각각 스택에 실제 값을 저장합니다.
참조형 변수 (Reference Type)
- 참조형 변수는 기본형 변수와 달리, 객체의 주소(참조)를 저장하는 변수입니다.
- 참조형 변수는 클래스, 배열, 인터페이스, 열거형 등으로 생성된 객체를 가리킵니다.
- 실제 데이터는 힙(Heap) 메모리 영역에 저장되고, 참조형 변수는 이 데이터를 가리키는 주소값을 스택(Stack) 영역에 저장합니다.
- 결국 기본형 변수가 아닌 변수는 모두 참조형 변수라 생각하시면 됩니다.
String name = "John Doe";
int[] scores = {85, 90, 78};
Student student = new Student("Jane Doe", 3);
- 위 예시에서, name, scores, student 변수는 모두 참조형 변수입니다.
- name 변수는 String 객체를 참조하고, scores 변수는 int 배열을 참조하며, student 변수는 Student 객체를 참조합니다.
2-2. Java의 메모리 구조
- Java의 메모리 구조는 크게 세 가지로 나눌 수 있습니다
- 몇개 더 있지만, 지금 단계에서 다룰 내용은 아닌듯하여 생략합니다.
- Java의 메모리 구조
- 메서드 영역(Method Area): 클래스 정보, 상수, static 변수, 메서드 코드 등을 저장합니다.
- static에 관해선 추후 제어자를 다룰때 다시 정리 예정입니다.
- 스택(Stack): 기본형 변수와 메서드 호출 시 생성되는 지역 변수들이 저장됩니다.
- 힙(Heap): 객체와 배열이 저장됩니다. 참조형 변수가 가리키는 실제 데이터가 위치합니다.
- 메모리 관리는 가비지 컬렉터(Garbage Collector)가 담당합니다.

- 참고 할만한 자료 링크 : JAVA-☕-그림으로-보는-자바-코드의-메모리-영역스택-힙
2-3. 변수 선언 위치에 따른 변수 분류
- Java에서 변수는 선언 위치에 따라 크게는 지역 변수(Local Variable)와 멤버 변수(Member Variable)로 분류됩니다.
- 이들 변수는 선언 위치에 따라 메모리 할당 시점, 유효 범위, 접근 방법 등이 달라집니다.
2-3-1. 지역 변수 (Local Variable)
지역 변수
는 메서드나 생성자, 초기화 블록 내에서 선언된 변수로, 해당 블록 내에서만 유효합니다. 메서드나 블록이 끝나면 지역 변수는 메모리에서 사라집니다.
- 선언 위치: 메서드, 생성자, 또는 초기화 블록 내부
- 유효 범위: 해당 메서드나 블록 내에서만 사용 가능
- 메모리 할당 시점: 메서드나 블록이 호출될 때 스택(Stack)에 메모리 할당
- 기본값: 자동으로 초기화되지 않으므로 반드시 초기화해야 사용 가능
public void calculateSum() {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += i;
}
System.out.println("Sum: " + sum);
}
매개변수 (Parameter Variable)
- 메서드나 생성자에 인자로 전달되는 변수인
매개변수
도 지역변수로 분류되는데, 매개변수는 메서드나 생성자가 호출될 때 생성되고 종료되면 소멸됩니다.
- 선언 위치: 메서드 또는 생성자의 매개변수 선언부
- 유효 범위: 메서드나 생성자가 실행되는 동안 유효
- 메모리 할당 시점: 메서드나 생성자가 호출될 때 스택(Stack)에 메모리 할당
public void greet(String name) {
System.out.println("Hello, " + name);
}
2-3-2. 멤버 변수 (Member Variable)
멤버 변수
는 클래스의 속성으로, 객체가 생성될 때 힙(Heap) 메모리 영역에 할당됩니다. 멤버 변수는 다시 인스턴스 변수
와 클래스 변수
두 가지로 나뉩니다.
인스턴스 변수 (Instance Variable)
- 인스턴스 변수는 클래스 내에 선언되며, 각 객체(instance)가 개별적으로 가지는 변수입니다.
- 객체가 생성될 때마다 별도로 할당되며, 객체가 소멸되면 함께 소멸됩니다.
- 선언 위치: 클래스 내부, 메서드나 생성자 외부
- 유효 범위: 객체가 존재하는 동안 해당 객체에서 접근 가능
- 메모리 할당 시점: 객체가 생성될 때 힙(Heap)에 메모리 할당
- 기본값: 자동으로 초기화됨 (숫자 타입은 0, 객체 참조는 null 등)
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("My name is " + name + " and I am " + age + " years old.");
}
}
클래스 변수 (Class Variable)
- 클래스 변수는
static
키워드로 선언되며, 클래스 전체에서 공유됩니다.
- 클래스 변수는 클래스가 메모리에 로드될 때 단 한 번 할당되며, 모든 객체가 이 변수를 공유합니다.
- 선언 위치: 클래스 내부, static 키워드를 사용
- 유효 범위: 클래스가 메모리에 있는 동안 유효, 모든 객체에서 공유
- 메모리 할당 시점: 클래스가 메모리에 로드될 때 메서드 영역(Method Area)에 메모리 할당
- 기본값: 자동으로 초기화됨 (숫자 타입은 0, 객체 참조는 null 등)
public class Counter {
static int count = 0;
public Counter() {
count++;
}
public static void showCount() {
System.out.println("Count: " + count);
}
}
2-4. 참조형 변수의 메서드 및 클래스에서의 특징
2-4-1. 참조형 변수와 메서드
- 참조형 변수를 메서드의 인자로 전달할 때, 해당 변수는 객체의 주소를 전달합니다.
- 따라서 메서드 내에서 객체의 속성을 변경하면, 원본 객체에도 영향을 미칩니다.
public class ReferenceExample {
public static void modifyArray(int[] arr) {
arr[0] = 99;
}
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
modifyArray(numbers);
System.out.println(numbers[0]);
}
}
- 위 예시에서 modifyArray 메서드는 numbers 배열을 참조하는 주소를 전달받아 배열의 첫 번째 요소를 변경합니다.
- 이 변경 사항은 메서드가 끝난 후에도 main 메서드에서 확인할 수 있습니다.
2-4-2. 참조형 변수와 객체 비교
- 참조형 변수는 객체의 주소를 가리키기 때문에, 두 객체를 비교할 때는
==
연산자를 사용하는 것이 아닌 .equals()
메서드를 사용해야 합니다.
String name1 = new String("John");
String name2 = new String("John");
System.out.println(name1 == name2);
System.out.println(name1.equals(name2));
- 위 예시에서 name1과 name2는 같은 문자열 값을 가지지만, 각각 다른 주소를 참조합니다.
==
연산자는 주소를 비교하므로 false를 반환하지만, .equals()
메서드는 객체의 내용을 비교하므로 true를 반환합니다.
2-4-3. 참조형 변수의 null 값
- 참조형 변수는
null
값을 가질 수 있으며, 이는 해당 변수가 어떤 객체도 참조하지 않음을 의미합니다.
- 이를 잘못 다루면
NullPointerException
이 발생할 수 있습니다.
String name = null;
System.out.println(name.length());
- 위 코드에서 name 변수가
null
값을 가지므로, length() 메서드를 호출할 때 NullPointerException
이 발생합니다.
- 따라서 참조형 변수를 사용할 때는 null 여부를 반드시 확인해야 합니다.
2-4-4. 클래스와 참조형 변수의 관계
- 클래스는 참조형 변수를 정의할 수 있는 설계도이며, 이를 통해 다양한 데이터 타입의 객체를 생성할 수 있습니다.
- 참조형 변수를 통해 객체를 생성하고, 이 객체는 클래스에 정의된 속성과 메서드를 활용할 수 있습니다.
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("My name is " + name + " and I am " + age + " years old.");
}
public static void main(String[] args) {
Person person1 = new Person("Alice", 30);
person1.introduce();
Person person2 = person1;
person2.name = "Bob";
person1.introduce();
}
}
마무리
- Java에서 기본형 변수와 참조형 변수는 메모리에서의 처리 방식과 사용 방법에서 큰 차이를 보입니다.
- 기본형 변수는 값 자체를 저장하는 반면, 참조형 변수는 객체의 주소를 저장합니다.
- 참조형 변수는 메서드에서 객체의 상태를 변경할 수 있고, 객체의 비교나 null 처리와 같은 중요한 개념을 포함합니다.
- 이러한 차이를 이해하고 적절히 사용하는 것이 Java 프로그래밍의 중요한 부분이며, 객체지향 프로그래밍을 효과적으로 활용하기 위해 반드시 숙지해야 할 개념들입니다.
- 다음 포스팅에서는 패키지와 클래스의 활용법에 대해서 다루어보도록 하겠습니다.