개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

기초개념 › Java

변수와 타입

변수는 무엇이고, 타입은 무엇을 정하는가

변수는 값을 담아 두는 이름입니다. int age = 20;이라는 한 줄은 세 부분으로 되어 있습니다. int는 타입으로, 이 변수에는 정수만 담는다는 뜻입니다. age는 이름이고, 20은 처음에 담을 값입니다. 이 줄을 선언이라고 하며, 선언을 읽은 컴파일러는 "age는 int 변수다"라고 기억해 두고 그 뒤의 줄들이 이 기억에 맞는지 실행하기 전에 확인합니다. 이 실습은 타입 int를 지우고, 담는 값을 바꾸고, 값을 아예 담지 않기도 하며 같은 코드를 컴파일하고 실행해, 컴파일러가 무엇을 알려 주고 무엇이 출력되는지를 봅니다.

실행으로 대조 · JDK 21에서 여섯 가지 조합을 javax.tools로 컴파일하고 실행해 대조

이 실습에 나오는 개념

변수
변수는 값을 담아 두는 저장 공간에 붙인 이름이다. 모든 변수에는 컴파일할 때 이미 정해진 타입이 있고, 그 타입이 어떤 종류의 값을 담을 수 있는지를 정한다. 예를 들어 int age;로 선언한 변수는 정수만 담을 수 있고, int는 -2147483648부터 2147483647까지의 32비트 정수이다. 변수에 값을 담는 것은 = 로 하며, age = age + 1;은 "오른쪽을 계산한 값을 왼쪽 변수에 담는다"는 뜻이다. 담긴 값은 바뀔 수 있지만 변수의 이름과 타입은 바뀌지 않는다. 타입에 맞지 않는 값을 담으려 하면 컴파일 오류이다.
선언과 초기화
메서드 안에서 변수를 만드는 줄을 지역 변수 선언이라고 하며 타입, 이름, 그리고 선택적으로 = 뒤에 처음 담을 값(초기화)을 적는다. int age;는 선언만 한 것이고 int age = 20;은 선언하면서 초기화한 것이다. 선언하지 않은 이름을 쓰면 컴파일러가 그 이름을 찾지 못해 오류를 낸다. 지역 변수는 필드와 달리 0 같은 기본값이 저절로 들어가지 않으므로, 값을 읽기 전에 반드시 값이 담겨 있어야 하고 아니면 컴파일 오류이다. 값을 담는 줄 = 의 왼쪽에 쓴 이름은 읽는 것으로 치지 않는다.
타입
타입은 변수에 담을 수 있는 값의 종류를 정하는 이름이다. 자바의 타입은 기본형과 참조형으로 나뉘고, 참조형에는 클래스 타입, 인터페이스 타입, 타입 변수, 배열 타입이 있다. class Card나 interface Payable 선언을 쓰면 Card, Payable이라는 타입을 쓸 수 있게 된다. 컴파일러는 값을 변수에 담는 줄마다, 그 값의 타입이 변수의 타입과 같거나 그 하위 타입인지 확인한다. 클래스가 implements로 밝힌 인터페이스는 그 클래스의 상위 타입이다. 선언하지 않은 이름을 타입으로 쓰면 컴파일러가 그 타입을 찾지 못해 오류를 낸다.
기본형과 참조형
자바의 타입은 기본형과 참조형 두 가지로 나뉜다. 기본형은 byte, short, int, long, float, double, char, boolean의 여덟 가지이며, 변수가 값 자체를 담는다. 참조형은 클래스, 인터페이스, 배열처럼 그 밖의 모든 타입이며, 변수가 객체 자체가 아니라 객체를 가리키는 참조를 담는다. 그래서 기본형 변수를 대입하면 값이 복사되어 두 변수가 서로 영향을 주지 않지만, 참조형 변수를 대입하면 참조가 복사되어 두 변수가 같은 객체를 가리키게 된다. 참조형 변수는 아무 객체도 가리키지 않는다는 뜻의 null을 담을 수 있고, 기본형 변수는 null을 담을 수 없다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 컴파일러가 main 안을 위에서부터 읽습니다. 먼저 int age = 20; 줄을 읽습니다. 이 줄은 세 부분입니다. int는 타입으로, 정수만 담는다는 뜻입니다. age는 이름입니다. 20은 담을 값입니다. 컴파일러는 "age라는 이름은 int 타입의 변수다"라고 기억합니다.
  2. 컴파일러가 담으려는 값을 확인합니다. 20은 정수이므로 정수만 담는 int 변수 age에 담을 수 있습니다.
  3. 컴파일러가 age = age + 1; 줄을 확인합니다. 오른쪽의 age + 1은 age에 담긴 값을 읽는 일입니다. age는 int로 선언돼 있고 앞 줄에서 값이 담겼으므로 읽을 수 있습니다. int에 1을 더한 결과도 정수이므로 다시 age에 담아도 됩니다.
  4. 컴파일러가 System.out.println(age); 줄을 확인합니다. age는 int 변수이고 값도 담겨 있으므로 읽어서 출력할 수 있습니다.
  5. 컴파일이 성공해 실행할 Main 클래스 파일이 만들어집니다. age가 int인지, 담는 값이 맞는지, 읽을 수 있는지는 실행할 때가 아니라 지금 컴파일러가 컴파일하면서 확인했습니다.
  6. java Main으로 실행합니다. main이 시작되고 int age = 20; 줄이 실행됩니다. age라는 이름표가 붙은 int 칸이 만들어지고, 그 칸에 20이 담깁니다.
  7. age = age + 1; 줄이 실행됩니다. 먼저 오른쪽의 age + 1을 계산합니다. age 칸에 든 20에 1을 더하면 21입니다. 이 값을 같은 age 칸에 담습니다. 칸은 그대로이고 안의 값만 20에서 21로 바뀝니다. 여기서 = 는 "같다"가 아니라 "오른쪽 계산 결과를 왼쪽 칸에 담는다"는 뜻입니다.
  8. System.out.println(age);가 실행됩니다. age 칸에 든 값을 읽어 화면에 21을 출력합니다.

실행 결과

코드

public class Main {
    public static void main(String[] args) {
        // 선언: int 타입의 변수 age를 만들고 20을 담는다
        int age = 20;
        age = age + 1;
        System.out.println(age);
    }
}

이 모형의 전제

컴파일러와 실행 환경은 JDK 21.0.12.1(javac 21)입니다. 여섯 가지 조합을 모두, 화면의 코드와 같은 소스(줄 단위로 같은 글)를 javax.tools로 컴파일하고, 컴파일에 성공한 것은 클래스 파일을 새 클래스 로더로 읽어 Main.main을 실행해 표준 출력을 잡은 결과와 대조했습니다. 대조한 것은 컴파일 성공 여부, 첫 번째 오류의 진단 코드(compiler.err.cant.resolve.location, prob.found.req, var.might.not.have.been.initialized를 화면의 세 가지 오류 설명으로 옮겼습니다), 오류의 개수와 오류가 난 줄, Main 클래스 파일이 만들어졌는지, 실행했을 때의 출력입니다. 문서는 Java Language Specification(Java SE 21)을 직접 열어 확인했습니다. 모든 변수와 식에 컴파일할 때 알려진 타입이 있다는 것은 4장 서두, 변수가 값을 담는 저장 공간이고 컴파일 시점의 타입을 가진다는 것은 4.12절, 기본형 변수는 그 타입의 값만 담는다는 것은 4.12.1절, int가 32비트 부호 있는 정수라는 것은 4.2절과 4.2.1절, 지역 변수 선언이 타입(또는 var)과 이름과 선택적인 초기화로 이루어진다는 것은 14.4절, 초기화 없이 선언한 변수는 읽기 전에 값을 담아야 하고 아니면 컴파일 오류라는 것은 14.4.2절과 4.12.5절과 16장 서두를 따랐습니다. 지역 변수에는 필드와 달리 기본값이 저절로 들어가지 않는다는 것도 4.12.5절입니다. 값을 읽는 것만 접근으로 치고 = 왼쪽의 이름은 접근이 아니라는 것은 16장 서두입니다. 오류의 종류, 개수, 어느 줄에서 나는지는 명세가 정한 것이 아니라 이 javac에서 관찰한 것입니다. 오류가 여럿이면 javac는 모두 알리는데, 표에는 첫 번째 것만 적었습니다. 컴파일에 실패한 모든 조합에서 Main 클래스 파일은 만들어지지 않았고, 그래서 실행할 수 없다고 적었습니다. 타입 int도 값도 없는 조합은 선언 줄을 아예 두지 않았습니다. 타입 없이 age;만 쓴 줄은 문법에 맞는 문장이 아니기 때문이며(14.8절: 문장으로 쓸 수 있는 식은 대입, 증감, 메서드 호출, 객체 생성뿐), 이 모양을 한 번 따로 컴파일해 보니 javac가 not a statement라는 문법 오류를 냈습니다(조합 대조에는 넣지 않았습니다). 이 실습은 지역 변수와 int 하나만 다뤘습니다. 다른 기본형, 참조형 변수, var, 변수의 이름 짓기와 범위, 상수(final)는 다루지 않았습니다. 기본형과 참조형 변수에 값이 어떻게 복사되는지는 "세부 동작 실습: 변수와 타입"에서 다룹니다.

다음 실습: 메서드

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요