Updated:

변수 선언

 프로그램은 데이터를 메모리(RAM)에 저장하고 읽는 작업을 빈번히 수행한다. 이때 데이터를 어떤 방식으로 저장할지 정해져 있지 않다면 메모리 관리가 무척 어려워진다. 프로그래밍 언어는 이 문제를 해결하기 위해 변수를 사용한다.

  • 변수(variable): 하나의 값을 저장할 수 있는 메모리 번지에 붙여진 이름
    • 자바의 변수는 다양한 타입의 값을 저장할 수 없다. 즉, 정수형 변수에는 정수값만 저장할 수 있고, 실수형 변수에는 실수값만 저장할 수 있다.
  • 변수 선언: 어떤 타입의 데이터를 저장할 것인지 그리고 변수 이름이 무엇인지를 결정하는 것
    • 자바 10부터 local variable을 위한 타입 추론(type inference) 기능이 추가되어 변수 선언 시 구체적인 타입 대신 예약된 타입(reserved type)인 var를 사용할 수 있다.
    • 변수 이름은 첫 번째 글자가 문자여야 하고, 중간부터는 문자, 숫자, $, _를 포함할 수 있다. 첫 문자를 소문자로 시작하되 Camel Style로 작성하는 것이 관례이다.

 변수 선언은 저장되는 값의 타입과 이름만 결정한 것이지, 아직 메모리에 할당된 것은 아니다. 변수에 최초로 값이 대입될 때 메모리에 할당되고, 해당 메모리에 값이 저장된다.

  • 변수 초기화: 변수에 최초로 값을 대입하는 행위
  • 초기값: 변수 초기화를 할 때의 값값

 초기화되지 않은 변수는 아직 메모리에 할당되지 않았기 때문에 변수를 통해 메모리 값을 읽을 수 없다.

  • The local variable value may not have been initialized: 초기화되지 않은 변수를 연산식에 사용할 경우 컴파일 에러러

변수 타입

 자바는 정수, 실수, 논리값을 저장할 수 있는 기본(primitive) 타입 8개를 다음과 같이 제공한다.

  • 정수 타입
    • byte
      • 저장되는 값의 허용 범위: $-2^7 \sim 2^7-1$
      • 8 bit
    • char
      • 저장되는 값의 허용 범위: $-2^{15} \sim 2^{15}-1$
      • 16 bit
      • 문자 리터럴: 하나의 문자를 작은따옴표로 감싼 것, 문자 리터럴은 유니코드로 변환되어 저장되는데 유니코드는 각국의 문자를 0 ~ 65535 숫자로 매핑한 국제 표준 규약이다.
      • 유니코드가 정수이므로 char 타입도 정수 타입에 속한다. 그렇기 때문에 유니코드 숫자를 직접 대입할 수도 있다.
      • char 타입의 변수 초기화는 공백을 작은때옴표로 감싸서 한다.
    • short
      • 저장되는 값의 허용 범위: $0 \sim 2^{16}-1$
      • 16 bit
    • int
      • 저장되는 값의 허용 범위: $-2^{31} \sim 2^{31}-1$
      • 32 bit
    • long
      • 저장되는 값의 허용 범위: $-2^{63} \sim 2^{63}-1$
      • 64 bit
      • 수치가 큰 데이터를 다루는 프로그램에서 사용
      • 기본적으로 컴파일러는 정수 리터럴을 int 타입으로 간주하기 때문에 int 타입의 허용 범위를 초과하는 리터럴은 뒤에 소문자 l이나 대문자 L을 붙여 long 타입 값임을 컴파일러에게 알려줘야 한다.
    • 정수 리터럴
      • 리터럴(literal): 코드에서 프로그래머가 직접 입력한 값
      • 2진수: 0b 또는 0B로 시작하고 0과 1로 작성
      • 8진수: 0으로 시작하고 0 ~ 7 숫자로 작성
      • 10진수: 소수접이 없는 0 ~ 9 숫자로 작성
      • 16진수: 0x 또는 0X로 시작하고 0 ~ 9 숫자나 A, B, C, D, E, F 또는 a, b, c, d, e, f로 작성
  • 실수
    • float
      • 저장되는 값의 허용 범위(양수 기준): $1.4 \times 10^{-45} \sim 3.4 \times 10^{38}$
      • 32 bit
    • double
      • 저장되는 값의 허용 범위(양수 기준): $4.9 \times 10^{-324} \sim 1.8 \times 10^{308}$
      • 64 bit
    • float와 double 타입의 값은 부동 소수점(floating point) 방식으로 메모리에 저장한다.
    • 컴파일러는 실수 리터럴을 기본적으로 double 타입으로 해석하기 때문에 double 타입 변수에 대입해야 한다. float 타입에 대입하고 싶으면 리터럴 뒤에 소문자 f나 대문자 F를 붙여 컴파일러가 float 타입임을 알 수 있도록 해야 한다.
  • 논리
    • boolean
      • 논리 리터럴은 true와 false이다.

문자열

 작은따옴표로 감싼 한 개의 문자는 char 타입이지만, 큰따옴표로 감싼 여러 개의 문자들은 유니코드로 변환되지 않는다. 큰따옴표로 감싼 문자들은 문자열이라고 부르는데, 문자열을 변수에 저장하고 싶다면 String 타입을 사용해야 한다.
 문자열 내부에 역슬래쉬( \ )가 붙은 문자를 사용할 수 있는데, 이것을 이스케이프(escape)문자라고 한다.

  • " : “문자 포함
  • ' : ‘문자 포함
  • \ : \문자 포함
  • \u16진수: 16진수 유니코드에 해당하는 문자 포함
  • \t : 출력 시 탭만큼 띄움
  • \n : 출력 시 줄바꿈
  • \r : 출력 시 캐리지 리턴

 Java 13부터는 다음과 같은 텍스트 블록 문법을 제공한다.

String str = """
...
""";

 텍스트 블록에서 줄바꿈은 \n에 해당한다. 만약 줄바꿈을 하지 않고 다음 줄에 이어서 작성하고 싶다면 다음과 같이 맨 끝에 \를 붙여 주면 된다. 이 기능은 Java 14부터 제공한다.

String str = """
  나는 자바를 \
  학습합니다.
"""

타입 변환

자동 타입 변환

자동 타입 변환(promotion)은 말 그대로 자동으로 타입 변환이 일어나는 것을 말한다. 자동 타입 변환은 값의 허용 번위가 작은 타입이 허용 범위가 큰 타입으로 대입될 때 발생한다(큰 허용 번위 타입 = 작은 허용 범위 타입). 기본 타입을 허용 범위 순으로 나열하면 다음과 같다.

  • byte < short, char < int < long < float < double

강제 타입 변환

강제 타입 변환(casting)은 큰 허용 범위 타입을 작은 허용 범위 타입으로 쪼개어서 저장하는 것을 말한다. 강제 타입 변환은 캐스팅 연산자로 괄호()를 사용하는데, 괄호 안에 들어가는 타입은 쪼개는 단위이다.(작은 허용 범위 타입 = (작은 허용 범위 타입) 큰 허용 범위 타입) 강제 타입 변환의 목적은 원래 값이 유지되면서 타입만 바꾸는 것이다. 그렇기 때문에 작은 허용 번위 타입에 저장될 수 있는 값을 가지고 강제 타입 변환을 해야 한다.

  • int $\rightarrow$ byte
    • int 타입은 4byte의 크기를 가지므로 byte 타입으로 강제 타입 변환하면 앞 3byte는 삭제되고 끝 1byte값만 byte 타입 변수에 저장된다.
  • long $\rightarrow$ int
    • long 타입은 8byte의 크기를 가지므로 끝 4byte만 변수에 저장된다.
  • int $\rightarrow$ char
    • 원래 값을 유지하기 위해서는 char 타입의 허용 범위인 0 ~ 65535 사이의 값만 원래 값을 유지한다.
  • 실수 $\rightarrow$ 정수
    • 실수 타입은 정수 타입 보다 항상 큰 허용 범위를 가진다. 따라서 대상 정수 타입으로 캐스팅해서 강제 변환시켜야 한다. 이 경우 소수점 이하 부분은 버려지고, 정수 부분만 저장된다.
public class CastingExample {

    public static void main(String[] args) {
        int var1 = 10;
        byte var2 = (byte) var1;
        System.out.println(var2);   // 10이 그대로 유지

        long var3 = 300;
        int var4 = (int) var3;
        System.out.println(var4);   // 300이 그대로 유지

        int var5 = 65;
        char var6 = (char) var5;
        System.out.println(var6);   // 'A'가 출력

        double var7 = 3.14;
        int var8 = (int) var7;
        System.out.println(var8);   // 3이 출력
    }
}

연산식에서 자동 타입 변환

 자바는 실행 성능을 향상시키기 위해 컴파일 단계에서 연산을 수행한다. 따라서 실행 시 덧셈 연산이 없으므로 실행 성능이 좋아진다. 하지만 정수 리터럴이 아니라 변수가 피연산자로 사용되면 실행 시 연산을 수행한다. 정수 타입 변수가 산술 연산식에서 피연산자로 사용되면 int타입보다 작은 byte, short 타입의 변수는 int 타입으로 자동 타입 변환되어 연산을 수행한다.

  • byte 변수 x, y가 피연산자로 사용되면 int 타입으로 변환되어 연산되고 결과도 int 타입으로 생성된다.
  • 따라서 결과값을 byte 변수에 저장할 수 없고, int 변수에 저장해야 한다.

 정수 연산식에서 모든 변수가 int 타입으로 변환되는 것은 아니다. int 타입보다 허용 번위가 더 큰 long 타입이 피연산자로 사용되면 다른 피연산자는 long 타입으로 변환되어 연산을 수행한다. 따라서 연산 결과는 long 타입 변수에 저장해야 한다.
 실수 연산에서 피연산자가 동일한 실수 타입이라면 해당 타입으로 연산된다. float result = 1.2f + 3.4f;는 피연산자에 모두 f가 붙어 있기 때문에 float 타입으로 연산을 수행한다. 따라서 결과도 당연히 float 타입이 된다. 하지만 피연산자 중 하나가 double 타입이면 다른 피연산자도 double 타입으로 변환되어 연산되고, 연산 결과 또한 double 타입이 된다.
 int 타입과 double 타입을 연산하는 경우에도 int 타입 피연산자가 double 타입으로 자동 변환되고 연산을 수행한다. 만약 int 타입으로 연산을 해야 한다면 double 타입을 int 타입으로 강제 변환하고 덧셈 연산을 수행하면 된다.

int intValue = 10;
double doubleValue = 5.5;
int result = intValue + (int) doubleValue;

 1을 2로 나누는 예를 보자.

int x = 1;
int y = 2;
double result = x / y;
System.out.println(result);
  • 위 코드를 실행하면 0.0이 출력된다. 자바에서 정수 연산의 결과는 항상 정수가 되기 때문이다.
  • 따라서 x / y의 연산 결과는 0.5가 아니라 0이 되고, 0을 double 타입 변수 result에 저장하므로 0.0이 된다.
  • 위 코드의 결과가 0.5가 되기 위해서는 x / y 부분을 정수 연산이 아니라 실수 연산으로 변경해야 한다. 즉, x와 y 둘 중 하나 또는 둘 모두를 double 타입으로 변환하는 것이다.

문자열을 기본 타입으로 변환

 프로그램에서 문자열을 숫자 타입으로 변환하는 경우(‘12’와 ‘3.5’를 정수 및 실수 타입으로 변환해서 숫자 연산을 하는 경우)가 매우 많다. 자바에서 문자열을 기본 타입으로 변환하는 방법은 다음과 같다.

  • String $\rightarrow$ byte
    • String str = “10”;
    • byte value = Byte.parseByte(str);
  • String $\rightarrow$ short
    • String str = “200”;
    • short value = Short.parseShort(str);
  • String $\rightarrow$ int
    • String str = “300000”;
    • int value = Integer.parseInteger(str);
  • String $\rightarrow$ long
    • String str = “40000000000”;
    • long value = Long.parseLong(str);
  • String $\rightarrow$ float
    • String str = “12.345”;
    • float value = Float.parseFloat(str);
  • String $\rightarrow$ double
    • String str = “12.345”;
    • double value = Double.parseDouble(str);
  • String $\rightarrow$ boolean
    • String str = “true”;
    • boolean value = Boolean.parseBoolean(str);

 반대로 기본 타입의 값을 문자열로 변경하는 경우도 있는데, 이 경우는 간단히 String.valueOf() 메소드를 이용하면 된다.

  • String str = String.valueOf(기본타입값);

콘솔로 변수값 출력

  • System.out.println(리터럴 또는 변수);
    • System. : 시스템으로
    • out. : 출력하는데
    • println(리터럴 또는 변수): 괄호 안의 내용을 출력하고 행을 바꿔라
  • 출력 방법
    • println(내용);
      • 괄호 안의 내용을 출력하고 행을 바꿔라
    • print(내용);
      • 괄호 안의 내용을 출력하고 행을 바꾸지 말아라.
    • printf(“형식문자열”, 값1, 값2, …);
      • 형식 문자열에 맞추어 뒤의 값을 출력하라
      • %d(정수), %f(실수), %s(문자열)
      • flags라는 빈 공간을 채우는 방법이 있다(예를 들어 %06d, %10.2f).
      • 형식 문자열에 포함될 값이 두 개 이상일 경우에는 값의 순번(argument_index$)을 포함시켜야 한다.
        printf("이름: %1$s, 나이: %2s$d", "김자바", 25);
        

키보드 입력 데이터를 변수에 저장

 키보드로부터 입력된 데이터를 읽고 변수에 저장하는 가장 쉬운 방법은 Scanner를 사용하는 것이다.

Scanner scanner = new Scanner(System.in); // scanner 변수 선언
String inputData = scanner.nextLine();  // Enter 키를 누르면 입력된 문자열을 String 변수에 저장

댓글남기기