자바 변수 완전 정복 — 타입, 스코프, final, var 한 번에 정리
목차
- [개념 요약]
- [예제 코드]
- [동작 원리]
- [요약]
개념 요약
- 변수(Variable): 값을 담는 이름 있는 저장소. 자바에서는 타입(Types) 으로 메모리 크기·표현 범위를 결정해.
- 원시 타입(Primitive) vs 참조 타입(Reference):
int,double,boolean등은 값 자체를 담고,String, 배열, 객체 등은 힙(Heap) 의 객체를 가리키는 참조(reference) 를 담아. - 스코프(Scope)와 수명(Lifetime): 블록
{}기준으로 접근 가능 범위가 정해지고, 지역 변수는 스택 에서 블록이 끝나면 사라져. 필드는 객체 수명과 같아. - 상수(constant)와
final:final은 재할당 금지. 원시 타입은 값 자체가 고정, 참조 타입은 참조 자체 가 고정(객체 내부 상태는 별개). - 타입 추론(Type inference)
var(Java 10+): 로컬 변수 에 한해 컴파일러가 타입을 유추. 읽기 쉬움 이 전제될 때만 사용 추천.
왜 중요한가?
변수는 모든 로직의 최소 단위야. 타입·스코프·불변성 규칙을 명확히 알면 NullPointerException, 부정확한 캐스팅, 예상치 못한 변경 같은 버그를 크게 줄일 수 있어.
자주 쓰는 원시 타입 요약
| 타입 | 비트 | 기본값(필드) | 예시 리터럴 |
|---|---|---|---|
| byte | 8 | 0 | (byte) 1 |
| short | 16 | 0 | (short) 7 |
| int | 32 | 0 | 42 |
| long | 64 | 0L | 42L |
| float | 32 | 0.0f | 3.14f |
| double | 64 | 0.0d | 3.14, 2.0d |
| char | 16 | \u0000 |
'A', '가' |
| boolean | 1(논리) | false |
true, false |
참고: 지역 변수의 기본값은 없다. 초기화하지 않으면 컴파일 오류.
예제 코드
1) 변수 선언·초기화·스코프·final·var 한 번에 보기
public class VariableBasics {
// 필드(멤버 변수): 객체 수명과 동일, 기본값 존재
private int count; // 기본값 0
private String name; // 기본값 null
private static final int MAX_SIZE = 100; // 클래스 상수(컴파일 시 상수 풀)
public void run() {
// 지역 변수: 반드시 초기화 필요, 블록 종료 시 소멸(스택 프레임)
int local = 10;
final double PI = 3.14159; // 재할당 불가
// var: Java 10+, 지역 변수에만 사용 가능(명확할 때만)
var title = "Hello"; // 컴파일러가 String으로 추론
var numbers = new int[] {1, 2, 3};
// 블록 스코프
{
int inner = local + 5;
System.out.println(inner); // 15
}
// System.out.println(inner); // 컴파일 오류: inner는 블록 밖에서 접근 불가
// 캐스팅과 리터럴
long big = 42L; // L 접미사
float ratio = 0.75f; // f 접미사
char ch = '가'; // 2바이트 유니코드
boolean ok = true;
// 참조 타입: 변수에 저장되는 건 '객체의 참조'
String s1 = "abc";
String s2 = s1; // 같은 객체를 가리킴(참조 복사)
s1 = s1.toUpperCase(); // 새 String 생성(불변)
System.out.println(s2); // "abc"
// final 참조: 참조 변경만 금지, 객체 상태 변경은 별개
final StringBuilder sb = new StringBuilder("hi");
sb.append("!"); // OK: 내부 상태 변경
// sb = new StringBuilder(); // 컴파일 오류: 참조 재할당 불가
}
public static void main(String[] args) {
new VariableBasics().run();
}
}2) "자바는 값에 의한 호출" 증명: 원시 vs 참조
class Counter { int value; }
public class PassByValue {
static void changePrimitives(int x) {
x = 999; // 호출자 변수에 영향 없음(값 복사)
}
static void changeReference(Counter c) {
c.value = 999; // 같은 객체를 가리키는 '참조의 복사'이므로 내부 상태는 바뀜
c = new Counter(); // 참조 자체를 새로운 객체로 바꿔도 호출자 참조엔 영향 없음
c.value = -1;
}
public static void main(String[] args) {
int a = 1;
changePrimitives(a);
System.out.println(a); // 1
Counter cnt = new Counter();
cnt.value = 1;
changeReference(cnt);
System.out.println(cnt.value); // 999
}
}동작 원리
- 메모리 모델: 지역 변수는 스택 프레임 에 저장되고 블록/메서드 종료 시 소멸. 객체는 힙 에 생성되고, 참조 변수는 힙 객체의 주소 비슷한 정보를 저장해.
- 값에 의한 호출(Call by Value): 메서드 인자는 항상 복사본 으로 전달돼. 원시 타입은 값이 복사되고, 참조 타입은 참조 값 이 복사돼서 같은 객체를 가리키게 된다.
final의 의미: 원시 타입은 값이 고정. 참조 타입은 참조 변경만 금지 이므로, 불변성을 원하면String,record, 불변 컬렉션 등을 사용하거나 방어적 복사를 적용해.var사용 기준: 타입이 우변에서 명확 할 때만(예:new ArrayList<String>()). 공개 API나 복잡한 제네릭에선 명시적 타입 이 가독성을 높인다.- 기본값 규칙: 필드/배열 요소엔 타입별 기본값이 자동으로 채워지지만, 지역 변수는 반드시 초기화 해야 한다. 미초기화 시 컴파일 오류로 막아 버그를 예방한다.
대안과 선택 기준
- 불변 데이터가 필요하면:
final+ 불변 타입(String,LocalDate,List.of(...)) 또는 Lombok의@Value, Java 16+의record활용. - 가독성이 우선이면:
var과용 금지. 팀 컨벤션에 맞춰 "명확성 > 타이핑 단축" 원칙. - 성능 고려: 박싱/언박싱 자동 변환(auto boxing/unboxing) 비용 유의(
int↔Integer). 컬렉션에 원시 타입을 직접 담을 수 없으니 필요한 최소 범위에서만 래퍼 사용.
요약
- 변수는 타입·스코프·수명 을 정확히 이해해야 안전해. 지역 변수는 초기화 필수, 필드/배열은 기본값이 자동으로 채워진다.
- 자바의 인자 전달은 항상 값 복사. 참조 타입은 참조의 값 을 복사하므로, 메서드에서 객체 내부 상태는 바뀔 수 있다.
final은 재할당만 금지. 진짜 불변을 원하면 불변 타입/패턴을 쓰자.var는 로컬·명확할 때만. 공개 API나 복잡한 타입은 명시적 선언 이 읽기 좋다.- 이어서 보면 좋은 주제: 오토 박싱/언박싱, String/컬렉션 불변성 패턴.
'Backend > Java' 카테고리의 다른 글
| [JAVA] 예외처리 (0) | 2025.09.22 |
|---|---|
| [JAVA] 클래스 (0) | 2025.09.15 |
| [JAVA] 반복문 (0) | 2025.09.08 |
| [Java] 기본형 vs 참조형 (1) | 2025.02.11 |
| 스파르타 코딩 클럽 SQL 1주차 (0) | 2022.06.28 |