[자바] 2. 변수

[자바] 2. 변수

목차

자바에서 변수는 값을 저장해 두는 공간이고, 상수는 한 번 저장하면 바꿀 수 없는 공간이다. 변수를 제대로 다루려면 변수의 선언과 초기화, 자료형의 종류와 크기, 명명 규칙, 형변환, 상수와 리터럴까지 한 번에 정리해 두는 것이 좋다. 이 글에서는 자바 변수의 기초 개념을 예제 코드와 표로 정리하고, 정수형 오버플로우와 형변환 방법까지 함께 다룬다.

이 글은 [자바] 기초 시리즈의 2편이다. 1편 자바란?에 이어 변수를 다루며, 이후 3편 연산자, 4편 조건문과 반복문으로 이어진다.

변수란 무엇인가

프로그래밍을 하다 보면 값을 저장해 둘 공간이 필요한데, 그 공간을 변수(variable)라고 한다. 정수를 담을 준비가 된 x라는 이름의 빈 상자를 떠올려 보자. 여기에 5를 넣으면 상자 속에 정수 5가 들어간 것이고, 다시 3을 넣으면 기존 값 5는 지워지고 3이 저장된다. 변수는 이렇게 값을 한 번 저장한 뒤에도 다른 값으로 자유롭게 바꿀 수 있다.

변수와 짝을 이루는 개념이 상수리터럴이다. 상수는 한 번 저장하면 값을 바꿀 수 없는 공간이고, 리터럴은 그 공간에 들어가는 값 자체다. 셋의 관계를 먼저 잡아 두면 이후 내용이 한결 명확해진다.

변수 선언과 초기화

변수를 사용하려면 먼저 선언해야 한다. 선언은 자료형 변수이름; 형식으로 한다. 예를 들어 int x;라고 선언하면 정수를 담을 x라는 저장 공간이 생긴다. 선언한 변수에 값을 넣는 것을 대입 또는 초기화라고 한다.

int x;   // 변수 선언
x = 5;   // 변수에 값 5 대입
x = 3;   // 새로운 값 대입, 기존 값 5는 지워짐

선언과 대입을 한 줄로 동시에 할 수도 있다. 같은 자료형의 변수 여러 개를 한 줄에 선언하는 것도 가능하다.

int x = 5;           // 선언과 초기화를 동시에
int a = 10, b = 20;  // int a = 10; 과 int b = 20; 을 한 줄로

여기서 주의할 점이 있다. 수학에서 =는 양쪽이 같음을 의미하지만, 자바에서 =는 오른쪽 값을 왼쪽 변수에 저장하라는 대입 연산자다. 같다는 비교가 아니라는 점을 혼동하지 않도록 한다.

두 변수의 값 바꾸기

두 변수의 값을 서로 맞바꾸려면 임시 변수를 하나 둬야 한다. 한쪽 값을 잠시 보관해 둘 공간이 없으면 대입 과정에서 원래 값이 덮어써지기 때문이다.

int x = 10, y = 20;
int tmp = x;  // tmp에 x의 값(10)을 보관
x = y;        // x에 y의 값 대입 → x = 20
y = tmp;      // 보관해 둔 원래 x값을 y에 대입 → y = 10

tmptemp는 “temporary(임시의)”의 준말로, 임시로 값을 담는 변수에 흔히 쓰는 이름이다.

기본 자료형 8가지

변수를 선언할 때는 저장할 값의 종류에 따라 자료형(타입)을 골라야 한다. 자바의 자료형은 크게 기본형(primitive type)참조형(reference type)으로 나뉜다. 기본형은 실제 값을 직접 저장하며, 모두 8가지다. 정수형 4종(byte·short·int·long), 실수형 2종(float·double), 문자형 1종(char), 논리형 1종(boolean)으로 구성된다.

각 자료형의 크기와 표현 범위는 자바를 다루는 내내 기준이 되므로 반드시 익혀 두어야 한다. 아래 표로 정리했다.

분류자료형크기표현 범위
논리형boolean1 bytetrue, false
문자형char2 byte0 ~ 65,535 (유니코드 문자)
정수형byte1 byte-128 ~ 127
short2 byte-32,768 ~ 32,767
int4 byte약 -21억 ~ 21억 (-2³¹ ~ 2³¹-1)
long8 byte약 -922경 ~ 922경 (-2⁶³ ~ 2⁶³-1)
실수형float4 byte약 ±3.4 × 10³⁸ (유효자리 6~7)
double8 byte약 ±1.8 × 10³⁰⁸ (유효자리 15)

정수에는 기본적으로 int를, 실수에는 double을 쓰는 것이 일반적이다. int 범위를 넘는 큰 정수에는 long, 정밀도보다 메모리가 중요한 특수한 경우에만 float를 쓴다. 아래 이미지는 같은 내용을 정리한 표다.

자바 기본 자료형의 종류와 값의 범위 표

문자형과 문자열

문자형 char는 문자 하나만 저장한다. 작은따옴표로 문자 하나를 감싼 'A' 같은 값을 문자 리터럴이라고 한다. 문자 두 개 이상을 다루려면 char가 아니라 String(문자열) 타입을 써야 하며, 이때는 큰따옴표로 감싼다.

char ch = 'J';        // OK. char ch = "JAVA"; 는 불가능 (char는 문자 하나)
String name = "JAVA"; // 변수 name에 문자열 리터럴 "JAVA" 저장

String은 빈 값("")을 가질 수 있지만, char는 빈 문자('')를 가질 수 없다. 단, 공백(' ')은 가능하다. 공백은 아무것도 없는 게 아니라 엄연한 하나의 문자이기 때문이다. 참고로 String은 기본형이 아니라 참조형이다.

String str = "";  // 빈 문자열 가능
char c1 = '';      // 빈 문자 불가능, 에러
char c2 = ' ';     // 공백은 가능

참조형 자료형

기본형 변수가 실제 값을 저장하는 반면, 참조형(reference type) 변수는 값이 저장된 메모리 주소를 저장한다. 8개의 기본형을 제외한 나머지 자료형이 모두 참조형이다.

  • 기본형(primitive type): 논리형(boolean), 문자형(char), 정수형(byte·short·int·long), 실수형(float·double). 실제 값을 직접 저장하며, 모두 8개다.
  • 참조형(reference type): String, 배열, 클래스, 인터페이스 등. 객체가 저장된 주소를 저장한다. 기본형 8개를 제외한 모든 타입이 여기에 속한다.

참조형은 클래스와 객체를 본격적으로 배우면서 다시 자세히 다루게 된다. 지금은 “기본형은 값 자체, 참조형은 주소를 담는다”는 차이만 기억해 두면 충분하다.

변수 명명 규칙

변수 이름은 마음대로 지을 수 있지만 몇 가지 규칙을 지켜야 한다. 자바는 대소문자를 구분하므로 numNum은 서로 다른 변수다.

  • 영문자·숫자·_·$를 사용할 수 있고, 숫자로 시작할 수 없다.
  • int, class, final 같은 예약어(키워드)는 이름으로 쓸 수 없다.
  • 이름 사이에 공백을 넣을 수 없다.
  • 관례상 변수는 소문자로 시작하고, 여러 단어가 붙으면 두 번째 단어부터 첫 글자를 대문자로 쓴다(카멜 표기법, 예: userName).
  • 상수는 모두 대문자로 쓰고, 여러 단어는 _로 구분한다(예: MAX_COUNT).

형변환(캐스팅)

한 자료형의 값을 다른 자료형으로 바꾸는 것을 형변환(type casting)이라고 한다. 형변환에는 두 가지가 있다. 표현 범위가 작은 타입에서 큰 타입으로 변환할 때는 값 손실이 없어 자동으로 이루어지고(자동 형변환), 반대로 큰 타입에서 작은 타입으로 변환할 때는 값이 잘릴 수 있어 (타입) 형식으로 직접 명시해야 한다(강제 형변환).

자료형 사이의 값 변환 외에, 문자·숫자·문자열 사이의 변환도 자주 쓰인다. 자주 쓰는 변환 방법을 정리하면 다음과 같다.

  1. 문자를 숫자로: 문자에서 '0'을 뺀다. '3' - '0'은 정수 3이다.
  2. 숫자를 문자열로: 숫자에 빈 문자열을 더한다. 3 + ""은 문자열 “3”이다.
  3. 문자열을 숫자로: Integer.parseInt() 또는 Double.parseDouble()을 쓴다. Integer.parseInt("3")은 3이다.
  4. 문자열을 문자로: charAt(0)을 쓴다. "3".charAt(0)은 문자 '3'이다.
  5. 문자를 문자열로: 빈 문자열을 더한다. '3' + ""은 문자열 “3”이다.

문자열과 숫자가 +로 만나면 결과는 항상 문자열이 된다는 점도 기억해 두자. + 연산자는 양옆이 모두 숫자일 때만 덧셈을 하고, 한쪽이 String이면 나머지를 문자열로 바꾼 뒤 결합한다. 따라서 계산 순서에 따라 결과가 달라진다.

System.out.println(7 + 7 + "");  // 14 — 7+7을 먼저 계산한 뒤 문자열로 변환
System.out.println("" + 7 + 7);  // 77 — 앞의 7을 먼저 문자열로 바꿔 결합

정수형의 오버플로우

형변환과 함께 알아 둬야 할 것이 오버플로우다. 오버플로우는 연산 결과가 해당 타입이 표현할 수 있는 범위를 넘어서는 현상이다. 0000~9999만 표시할 수 있는 계기판을 떠올려 보자. 최댓값 9999에서 1을 더하면 10000이 아니라 0000으로 돌아가고, 0000에서 1을 빼면 9999가 된다. 즉 최댓값 + 1 = 최솟값, 최솟값 – 1 = 최댓값이 성립한다.

예를 들어 short는 -32,768~32,767을 표현한다. 따라서 32,767에 1을 더하면 -32,768이 되고, -32,768에서 1을 빼면 32,767이 된다. 아래 코드로 직접 확인할 수 있다.

public class Hello {
    public static void main(String[] args) {
        short sMin = -32768, sMax = 32767;
        System.out.println("sMin = " + sMin);
        // 문자열과 사칙연산이 함께 있으면 괄호로 연산을 먼저 묶는다
        System.out.println("sMin-1 = " + (sMin - 1));          // -32769
        // 1이 int 타입이라 산술 변환이 일어난다 (자세한 내용은 3편 연산자에서)
        System.out.println("sMin-1 = " + (short)(sMin - 1));   // 32767 (강제 형변환)
        System.out.println("sMax = " + sMax);
        System.out.println("sMax+1 = " + (short)(sMax + 1));   // -32768
    }
}

상수와 리터럴

상수(final)

상수(constant)도 변수처럼 값을 저장하는 공간이지만, 한 번 저장하면 다른 값으로 바꿀 수 없다. 선언 방법은 변수와 같고, 자료형 앞에 키워드 final을 붙이면 된다. 상수 이름은 관례상 모두 대문자로 쓴다.

final int CONST;
CONST = 5;
CONST = 3; // 에러 — 상수에 저장된 값은 변경할 수 없음

리터럴과 접미사

리터럴(literal)은 변수나 상수에 들어가는 자체를 가리킨다. 변수에 타입이 있듯이 리터럴에도 타입이 있다. 정수 리터럴은 기본이 int, 실수 리터럴은 기본이 double이며, 다른 타입임을 나타낼 때 접미사를 붙인다. 진법을 바꾸는 접두사, 자릿수를 구분하는 _도 함께 알아 두자.

int octNum = 010;   // 8진수 10 → 10진수 8.  접두사 "0"
int hexNum = 0x10;  // 16진수 10 → 10진수 16. 접두사 "0x"
long big = 100_000_000_000L; // long 리터럴은 접미사 L. '_'로 자릿수 구분 가능
float pi = 3.14f;   // float 리터럴은 접미사 f(또는 F), 생략 불가
double rate = 1.68d; // double 리터럴은 접미사 d(또는 D), 생략 가능

실수 리터럴은 기본이 double이므로 float 변수에 대입할 때는 접미사 f를 반드시 붙여야 한다. 반면 double은 기본 타입이라 접미사 d를 생략해도 된다. 리터럴 타입을 한눈에 정리한 표는 다음과 같다.

자바 변수 리터럴 타입과 접미사 정리 표

실습: 출력과 입력

변수 값을 화면에 출력하고, 키보드로 값을 입력받는 기본 방법도 함께 익혀 두면 실습이 한결 수월하다.

출력 — print · println · printf

화면 출력에는 System.out.print() 계열을 쓴다. print()는 줄바꿈을 하지 않고, println()은 출력 후 줄을 바꾼다. 형식을 지정해 출력하려면 printf()를 쓰고, 지시자(%d·%f 등)로 값의 형식을 지정한다. 줄바꿈은 %n으로 넣는다.

System.out.print("Hello, world"); // 줄바꿈 없이 출력
System.out.println(3 + 5);        // 8 출력 후 줄바꿈

int age = 14;
System.out.printf("age=%d%n", age); // age=14
자바 printf 형식 지시자 표

입력 — Scanner

키보드 입력은 Scanner 클래스로 받는다. 입력받은 내용은 문자열이므로, 숫자로 쓰려면 Integer.parseInt()로 형변환해야 한다. 앞서 본 “문자열을 숫자로” 변환이 그대로 쓰이는 예다.

import java.util.Scanner; // Scanner 클래스 사용을 위해 추가

public class Hello {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("정수를 입력하세요"); // 예: 22 입력
        String input = scanner.nextLine();       // 입력 내용을 input에 저장
        int num = Integer.parseInt(input);       // 문자열을 int로 변환
        System.out.println("입력 내용:" + input); // 입력 내용:22 (문자열 "22")
        System.out.printf("num=%d%n", num);      // num=22 (정수 22)
    }
}

정리

변수는 값을 담는 공간, 상수는 한 번 정하면 바꿀 수 없는 공간, 리터럴은 그 안에 들어가는 값이다. 변수의 선언과 초기화, 기본 자료형 8가지의 크기와 범위, 명명 규칙, 형변환과 오버플로우의 원리까지 이해하면 이후 연산자 학습이 한결 수월해진다. 특히 자료형의 크기·범위 표는 자주 들여다보며 익혀 두자.

다음 글은 [자바] 3. 연산자에서 산술·비교·논리 연산자와 형변환, 연산자의 우선순위를 다룬다.

💬 댓글 1

💬 댓글을 남기려면?
여겸 김
김여겸 멘토 2024.07.15
첫번째 글에서도 알고 있었지만 매뉴얼이나 글을 작성하는데 소질이 있어보입니다. 앞으로 작성되는 글이 정말 기대되는군요.

이 콘텐츠가 도움이 됐나요?

누스쿨 커뮤니티에서 더 많은 커리어 전략을 나눠요