개발이 취미인 사람

[Java] 리터럴(Literal)이란? - 변수와 값의 차이 완벽 이해 본문

언어(Programming Language)/Java

[Java] 리터럴(Literal)이란? - 변수와 값의 차이 완벽 이해

RyanSin 2026. 1. 29. 09:00
반응형

개요

안녕하세요. 이번 시간에는 Java의 가장 기초적이지만 중요한 개념인 **리터럴(Literal)**에 대해 알아보겠습니다.

 

"리터럴이 뭔가요?"라고 물어보면 많은 개발자들이 명확하게 설명하지 못하는 경우가 많습니다. 하지만 리터럴은 Java 프로그래밍의 가장 기본이 되는 개념이에요!

 

특히 String Pool, 메모리 구조, 참조 타입 등을 이해하려면 리터럴 개념을 정확히 알아야 합니다. 오늘은 "코드에 직접 적는 값"인 리터럴에 대해 쉽고 명확하게 정리해보겠습니다.

개념

리터럴(Literal)이란?

"소스 코드에 직접 입력한 값 그 자체"

다시 말해, 우리가 코드를 작성할 때 **"직접 적는 데이터"**를 리터럴이라고 합니다.

쉬운 비유

레시피: "설탕 100g을 넣으세요"
        ^^^^
        이 100g이 "리터럴"

코드: int sugar = 100;
                  ^^^
                  이 100이 "리터럴"

1. 리터럴 vs 변수

기본 개념

int age = 25;
//  ^^^   ^^
//  │     └─── 리터럴 (값 그 자체)
//  └───────── 변수 (값을 담는 그릇)

변수: 값을 담는 그릇 (상자)
리터럴: 그릇에 담을 값 (물건)

예제로 이해하기

public class LiteralExample {
    public static void main(String[] args) {
        // 변수 선언과 리터럴 할당
        int number = 100;        // 100이 리터럴
        double pi = 3.14;        // 3.14가 리터럴
        char grade = 'A';        // 'A'가 리터럴
        String name = "홍길동";   // "홍길동"이 리터럴
        boolean isTrue = true;   // true가 리터럴
        
        // 연산에서의 리터럴
        int sum = 10 + 20;       // 10과 20이 리터럴
        
        // 메서드 호출에서의 리터럴
        System.out.println("Hello");  // "Hello"가 리터럴
    }
}

메모리 관점

int x = 10;

Stack 메모리:

Stack
└─ x = 10  ← 10(리터럴)이 변수 x에 저장됨

리터럴 10은 컴파일 시점에 처리되어 변수 x에 직접 저장됩니다.


2. 타입별 리터럴 표기법

2-1. 정수 리터럴

public class IntegerLiteral {
    public static void main(String[] args) {
        // 10진수 리터럴
        int decimal = 100;
        
        // 16진수 리터럴 (0x 또는 0X로 시작)
        int hex = 0x64;          // 100과 같음
        
        // 8진수 리터럴 (0으로 시작)
        int octal = 0144;        // 100과 같음
        
        // 2진수 리터럴 (0b 또는 0B로 시작)
        int binary = 0b1100100;  // 100과 같음
        
        // long 타입 리터럴 (L 또는 l 접미사)
        long bigNumber = 100L;
        
        // 가독성을 위한 언더스코어 (Java 7+)
        int million = 1_000_000;  // 백만
        
        System.out.println(decimal);   // 100
        System.out.println(hex);       // 100
        System.out.println(octal);     // 100
        System.out.println(binary);    // 100
    }
}

주의사항:

int x = 100;   // OK
int y = 100L;  // 컴파일 에러! long을 int에 넣을 수 없음
long z = 100;  // OK, 자동으로 long으로 변환됨

2-2. 실수 리터럴

public class FloatingLiteral {
    public static void main(String[] args) {
        // double 타입 리터럴 (기본)
        double d1 = 3.14;
        double d2 = 3.14d;      // d 접미사 (생략 가능)
        double d3 = 3.14D;
        
        // float 타입 리터럴 (f 또는 F 접미사 필수!)
        float f1 = 3.14f;
        float f2 = 3.14F;
        
        // 지수 표현
        double scientific1 = 1.23e2;   // 1.23 × 10² = 123.0
        double scientific2 = 1.23e-2;  // 1.23 × 10⁻² = 0.0123
        
        System.out.println(d1);          // 3.14
        System.out.println(scientific1); // 123.0
    }
}

주의사항:

float f = 3.14;   // 컴파일 에러! double을 float에 넣을 수 없음
float f = 3.14f;  // OK! f 접미사 필수

2-3. 문자 리터럴

public class CharLiteral {
    public static void main(String[] args) {
        // 일반 문자 리터럴 (작은따옴표 '')
        char c1 = 'A';
        char c2 = '가';
        char c3 = '1';
        
        // 유니코드 리터럴
        char unicode = '\u0041';  // 'A'와 같음
        
        // 이스케이프 시퀀스
        char newLine = '\n';      // 줄바꿈
        char tab = '\t';          // 탭
        char backslash = '\\';    // 역슬래시
        char singleQuote = '\'';  // 작은따옴표
        
        System.out.println(c1);       // A
        System.out.println(unicode);  // A
        System.out.println("Hello" + newLine + "World");
        // 출력:
        // Hello
        // World
    }
}

주의사항:

char c1 = 'A';    // OK, 문자 1개
char c2 = 'AB';   // 컴파일 에러! 문자는 1개만
char c3 = "A";    // 컴파일 에러! 큰따옴표는 String

2-4. 문자열 리터럴 (중요!)

public class StringLiteral {
    public static void main(String[] args) {
        // 문자열 리터럴 (큰따옴표 "")
        String str1 = "Hello";
        String str2 = "안녕하세요";
        String str3 = "123";      // 문자열!
        
        // 빈 문자열
        String empty = "";
        
        // 여러 줄 문자열 (Java 13+)
        String multiLine = """
            첫 번째 줄
            두 번째 줄
            세 번째 줄
            """;
        
        // 이스케이프 시퀀스
        String escaped = "Hello\nWorld";  // 줄바꿈
        String quoted = "그가 말했다: \"안녕\"";  // 큰따옴표
        
        System.out.println(str1);     // Hello
        System.out.println(escaped);
        // 출력:
        // Hello
        // World
    }
}

문자 vs 문자열:

char c = 'A';      // 문자 (작은따옴표)
String s = "A";    // 문자열 (큰따옴표)

// 타입이 완전히 다름!

2-5. 불린 리터럴

public class BooleanLiteral {
    public static void main(String[] args) {
        // boolean 리터럴은 true와 false 두 개뿐!
        boolean isTrue = true;
        boolean isFalse = false;
        
        // 조건문에서 자주 사용
        if (true) {
            System.out.println("항상 실행됨");
        }
        
        // 비교 연산 결과는 boolean
        boolean result = (10 > 5);  // true
        
        System.out.println(isTrue);   // true
        System.out.println(result);   // true
    }
}

주의사항:

boolean b1 = true;   // OK
boolean b2 = 1;      // 컴파일 에러! Java는 1을 true로 변환 안 함
boolean b3 = "true"; // 컴파일 에러! 문자열은 boolean 아님

2-6. null 리터럴

public class NullLiteral {
    public static void main(String[] args) {
        // null은 "참조가 없음"을 나타내는 특별한 리터럴
        String str = null;
        Integer num = null;
        Object obj = null;
        
        // 기본 타입에는 null 사용 불가!
        // int x = null;  // 컴파일 에러!
        
        // null 체크
        if (str == null) {
            System.out.println("str은 null입니다");
        }
    }
}

3. 리터럴의 타입

기본 타입 리터럴

// 정수 리터럴의 기본 타입은 int
int i = 100;        // OK
long l = 100;       // OK, int → long 자동 변환
byte b = 100;       // OK, int → byte 자동 변환 (범위 내일 때)

// 실수 리터럴의 기본 타입은 double
double d = 3.14;    // OK
float f = 3.14;     // 에러! double → float 불가
float f = 3.14f;    // OK, float 명시

타입 변환 예제

public class LiteralType {
    public static void main(String[] args) {
        // int 범위를 벗어나면 L 필수
        long big = 3000000000L;  // int 범위 초과, L 필수
        
        // byte 범위를 벗어나면 에러
        byte b1 = 127;   // OK
        // byte b2 = 128;   // 에러! byte 범위는 -128~127
        
        // float은 f 필수
        float f = 3.14f;
        
        // char는 작은따옴표
        char c = 'A';
    }
}

4. 리터럴과 메모리

기본 타입 리터럴 - Stack에 저장

int age = 25;
double height = 175.5;

메모리 상태:

Stack
├─ age = 25  ← 리터럴 25가 직접 저장
└─ height = 175.5  ← 리터럴 175.5가 직접 저장

문자열 리터럴 - String Pool(Heap)에 저장

String s1 = "Hello";
String s2 = "Hello";

메모리 상태:

Heap (String Pool)
└─ "Hello" 객체 (0x1234)  ← 리터럴 1개만!

Stack
├─ s1 = 0x1234  ← 주소 저장
└─ s2 = 0x1234  ← 같은 주소!

핵심 차이:

  • 기본 타입 리터럴: 값 자체가 Stack에 저장
  • 문자열 리터럴: Heap의 String Pool에 저장, Stack에는 주소만

이 부분은 다음 글 [참조 타입의 메모리 저장 방식]에서 자세히 다룹니다!


5. 실전 예제

예제 1: 리터럴 구분하기

public class LiteralQuiz {
    public static void main(String[] args) {
        int x = 10;              // 10: 정수 리터럴
        double y = 3.14;         // 3.14: 실수 리터럴
        char c = 'A';            // 'A': 문자 리터럴
        String s = "Hello";      // "Hello": 문자열 리터럴
        boolean b = true;        // true: 불린 리터럴
        
        int sum = x + 20;        // 20: 정수 리터럴
        String msg = s + "World";  // "World": 문자열 리터럴
        
        System.out.println("결과: " + sum);
        //                 ^^^^^^^
        //                 "결과: ": 문자열 리터럴
    }
}

예제 2: 리터럴 타입 주의

public class LiteralTypeError {
    public static void main(String[] args) {
        // 올바른 예
        int i = 100;
        long l = 100L;
        float f = 3.14f;
        double d = 3.14;
        char c = 'A';
        String s = "Hello";
        
        // 컴파일 에러 예
        // float f2 = 3.14;      // 에러! double을 float에
        // char c2 = "A";        // 에러! String을 char에
        // char c3 = 'AB';       // 에러! 문자는 1개만
        // int x = 3000000000;   // 에러! int 범위 초과
        // boolean b = 1;        // 에러! int를 boolean으로
    }
}

예제 3: 문자열 리터럴의 특별함

public class StringLiteralTest {
    public static void main(String[] args) {
        String s1 = "Hello";  // 리터럴
        String s2 = "Hello";  // 같은 리터럴
        String s3 = new String("Hello");  // new 객체
        
        System.out.println(s1 == s2);  // true (같은 리터럴)
        System.out.println(s1 == s3);  // false (다른 객체)
        
        System.out.println(s1.equals(s2));  // true
        System.out.println(s1.equals(s3));  // true
    }
}

실행 결과:

true
false
true
true

왜 이런 결과가 나올까요? → 다음 글 [String & String Pool]에서 자세히 알아봅니다!


6. 리터럴 vs 상수 vs 변수

개념 정리

용어 의미 예시

리터럴 코드에 직접 적은 값 100, "Hello", true
변수 값을 저장하는 공간 (변경 가능) int x = 10;
상수 값을 저장하는 공간 (변경 불가) final int MAX = 100;

예제로 이해

public class LiteralVsConstant {
    // 상수 (관례: 대문자 + 언더스코어)
    static final int MAX_VALUE = 100;  // 100이 리터럴
    static final String TITLE = "제목";  // "제목"이 리터럴
    
    public static void main(String[] args) {
        // 변수
        int x = 10;        // 10이 리터럴
        x = 20;            // 변경 가능! 20도 리터럴
        
        // 상수
        final int y = 30;  // 30이 리터럴
        // y = 40;         // 컴파일 에러! 상수는 변경 불가
        
        // 리터럴 직접 사용 (비추천)
        if (age > 19) {    // 19가 리터럴 (매직 넘버)
            // ...
        }
        
        // 상수 사용 (추천)
        if (age > MAX_AGE) {  // 의미가 명확함
            // ...
        }
    }
}

베스트 프랙티스:

// 나쁜 예: 리터럴 직접 사용 (매직 넘버)
if (status == 1) { ... }
if (score > 90) { ... }

// 좋은 예: 상수로 정의
static final int STATUS_ACTIVE = 1;
static final int PASS_SCORE = 90;

if (status == STATUS_ACTIVE) { ... }
if (score > PASS_SCORE) { ... }

7. 컴파일 타임 상수

개념

컴파일 시점에 값이 결정되는 상수

public class CompileTimeConstant {
    // 컴파일 타임 상수
    static final int MAX = 100;
    static final String NAME = "Java";
    
    public static void main(String[] args) {
        // 컴파일러가 직접 값으로 치환
        int x = MAX;  // int x = 100; 으로 컴파일됨
        
        // 상수 표현식도 컴파일 타임에 계산
        int result = MAX * 2;  // int result = 200; 으로 컴파일됨
    }
}

핵심 정리

1. 리터럴이란?

"소스 코드에 직접 입력한 값 그 자체"

int x = 10;        // 10이 리터럴
String s = "Hi";   // "Hi"가 리터럴

2. 타입별 리터럴 표기

타입 표기법 예시

정수 숫자 100, 0xFF, 0b1010
long 숫자 + L 100L
실수 소수점 3.14
float 소수점 + f 3.14f
문자 작은따옴표 'A'
문자열 큰따옴표 "Hello"
불린 true/false true
null null null

3. 메모리 저장

기본 타입 리터럴 → Stack에 값 직접 저장
문자열 리터럴 → Heap의 String Pool에 저장

4. 리터럴 vs 변수 vs 상수

리터럴: 코드에 적은 값 (100, "Hello")
변수: 값을 담는 그릇 (int x = 10;)
상수: 변경 불가 그릇 (final int MAX = 100;)

마무리

이번 시간에는 Java의 가장 기본이 되는 리터럴(Literal) 개념에 대해 알아봤습니다.

리터럴은 단순해 보이지만, 메모리 구조를 이해하고 String Pool, 참조 타입 등을 학습하는 데 꼭 필요한 기초 개념입니다.

특히 문자열 리터럴은 String Pool이라는 특별한 공간에 저장되는데, 이에 대해서는 다음 글에서 자세히 다루겠습니다!

기초를 탄탄히 하면 복잡한 개념도 쉽게 이해할 수 있습니다. 꼭 실습을 통해 학습하신 걸 추천드리겠습니다!!

참고 자료