
프로그래밍 하는 과정에서 필요에 따라 데이터를 저장할 때 사용하는 공간 입니다. 마치 양동이와 같이 데이터를 담을 수 있는 공간을 할당할 때 변수 선언을 하죠.
프로그래밍 하는 과정에서 필요에 따라 데이터를 저장할 때 사용하는 공간 입니다. 마치 양동이와 같이 데이터를 담을 수 있는 공간을 할당할 때 변수 선언을 하죠. 
변수라는 이름을 갖게 된 이유는 프로그램에 의해서 수시로 값이 변동될 수 있기 때문입니다. 변수에는 복수 개의 값을 저장할 수 없고, 하나의 값만 저장할 수 있습니다. 단, 배열 자료형의 경우에만 복수개의 값을 저장할 수 있습니다.
변수를 사용하기 위해서는 먼저 변수를 선언해야 합니다. 자바에서의 변수 선언은 어떤 타입의 데이터를 저장할것인지, 변수 이름이 무엇인지를 결정합니다.
(자료형 타입) (변수명) = (값);
int age = 20;
double pi = 3.14;
그리고 자바는 예약어가 있습니다. 이 예약어로 변수 이름을 지정하면 컴파일 에러가 발생하기 때문에 주의해야합니다.
지금 모두 외울 필요는 없고, 자바를 학습하다보면 알게 될 부분이라 지금은 눈으로만 확인해보시면 됩니다. 자바에 익숙해진 후에 다시 아래 예약어를 확인해본다면 더 잘 보일것입니다.
| 분류 | 예약어 |
|---|---|
| 기본 데이터 타입 | boolean, byte, char, short, int, long, float, double |
| 접근 지정자 | private, protected, public |
| 클래스와 관련된 것 | class, abstract, interface, extends, implements, enum |
| 객체와 관련된 것 | new, instanceof, this, super, null |
| 메소드와 관련된 것 | void, return |
| 제어문과 관련된 것 | if, else, switch, case, default, for, do, while, break, continue |
| 논리값 | true, false |
| 에외 처리와 관련된 것 | try, catch, finally, throw, throws |
| 기타 | transient, volatile, package, import, synchronized, native, final, static, strictfp, assert |
변수는 초기화 되어야 읽을 수 있고, 초기화 되지 않은 변수는 읽을 수 없습니다.

위 예시를 보면, 변수 value는 선언만 되고 초기화 되지 않은 값이기 때문에 산술 연산식 value+10 에서 사용할 수 없습니다. 컴파일 오류 메시지를 보면 Variable ‘value’ might not have been initialized 값을 초기화하지 않았음에도 불구하고, 다른 변수 할당에 읽어오려는 시도를 하여 발생한 오류임을 알 수 있죠?
변수는 중괄호 { } 블록 내에서 선언되고 사용됩니다. 중괄호 블록을 사용하는 곳은 클래스, 메소드인데 다음과 같은 사용 규칙이 있습니다.
💡 메소드 블록 안에있는 변수는 선언된 블록 내에서만 사용 가능

이렇듯 변수를 초기화 하는게 중요!
메소드 블록 내에서 선언된 변수를 특히 로컬 변수(local variable)라고 부르고, 이 로컬 변수는 메소드 실행이 끝나면 메모리에서 자동으로 없어집니다. 그렇기 때문에 메소드 실행이 끝난 후 부터는 변수를 사용할 수 없게 되죠.
아래의 코드는 변수와 선언의 테스트!

value2가 출력되지 않는 이유는 무엇일까요??
변수의 네이밍 규칙은 다음과 같습니다.
숫자로 시작해서는 안됩니다.
예약어를 사용해서는 안됩니다.
대소문자가 구분되며 길이에는 제한이 없습니다.
특수문자는 언더바(_)와 달러($)만 가능합니다.
위의 네이밍 규칙은 자바 컴파일러가 규정하는 규칙이지만, 다음으로 오는 네가지는 ‘컨벤션’, 혹은 권장사항 정도로 알고계시면 좋습니다. 실무에서는 이런 규칙을 잘 지켜서 개발해야겠죠.
클래스나 변수명은 영문이어야 합니다.
클래스명의 첫 글자는 항상 대문자여야 합니다.
여러 단어가 합쳐진 변수명 이라면 단어의 시작은 대문자로 합니다.
예시) saveMembers, lastIndexOf
상수의 이름은 대문자가 권장사항 입니다. 단어 사이의 구분자는 언더바(_) 입니다.
예시) MIN_NUMBER, LAST_NAME
(1) 자바에서의 변수 선언은 어떤 타입의 데이터를 저장할것인지,
변수 이름이 무엇인지를 결정한다.
(2) 변수는 선언 시 사용한 타입의 값만 저장할 수 있다.
(3) 변수는 변수가 선언된 중괄호{} 안에서만 사용 가능하다.
(4) 변수는 초기값이 저장되지 않은 상태에서 읽을 수 있다.
(1) className
(2) class
(3) 6hour
(4) $value
(5) _age
(6) at
Python, Javascript 언어와는 다르게 자바에서는 모든 변수에 타입이 있고, 타입에 따라 저장할 수 있는 값의 종류와 범위가 달라집니다. 변수를 선언할 때 주어진 타입은 변수를 사용하는 도중에 변경할 수 없고 따라서 변수를 선언할 때 어떤 타입을 사용할지 충분히 고려해야합니다.
그럼 자바에서 사용하는 변수의 타입 종류를 알아보겠습니다.

| 값의 종류 | 기본 타입 | 메모리 사용 크기 | 저장되는 값의 범위 |
|---|---|---|---|
| 정수 | byte | 1byte | -128 ~ 127 |
| 정수, 문자 | char | 2byte | 0 ~ 65535 |
| 정수 | short | 2byte | -32,768 ~ 32,767 |
| 정수 | int | 4byte | -2,147,483,648 ~ 2,147,483,647 |
| 정수 | long | 8byte | –9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
| 실수 | float | 4byte | 3.4E+/-38(7개의 자릿수) |
| 실수 | double | 8byte | 1.7E+/-308(15개의 자릿수) |
| 논리형 | boolean | 1byte | true, false |
5가지 정수타입은 각각 저장할 수 있는 값의 범위가 다릅니다. 각각의 정수 타입을 메모리 사용 크기(byte) 순서대로 나열하면 다음과 같습니다.
byte (1byte) < char (2byte) < short (2byte) < int (4byte) < long (8byte)
```java
public class ByteVariableExample {
public static void main(String[] args) {
byte var1 = -128;
byte var2 = -30;
byte var3 = 0;
byte var4 = 30;
byte var5 = 127;
System.out.println(var1);
System.out.println(var2);
System.out.println(var3);
System.out.println(var4);
System.out.println(var5);
}
}
```
```java
-128
-30
0
30
127
```
byte 변수는 최소값 -128 부터 시작해서 최대값 127을 표현할 수 있는 자료형입니다. byte변수는 최대값인 127을 넘어가는 값을 저장할 수 없는데, 만약 128을 변수에 대한 값으로 할당한다면 컴파일 오류가 발생합니다.
다음 예시를 보시죠. byte 타입의 변수 var1과 int 타입의 변수 var2를 125로 먼저 할당한 후 1씩 증가해보는 연산을 해볼게요.
```java
public class GarbageValueExample {
public static void main(String[] args) {
byte var1 = 125;
int var2 = 125;
for (int i = 0; i < 5; i++) {
var1++;
var2++;
System.out.println("var1: " + var1 + "\t" + "var2: " + var2);
}
}
}
```
byte 타입은 최대값이 127이고 그 이후 값으로 넘어가면 어떻게 값이 출력 되는지 결과를 확인해보면
```java
var1: 126 var2: 126
var1: 127 var2: 127
var1: -128 var2: 128
var1: -127 var2: 129
var1: -126 var2: 130
```
127에서 +1 증가하면, 신기하게도 다시 최소값(-128)으로 넘어가는 것을 확인할 수 있습니다.
이처럼 byte 외에 또 다른 정수형 타입인 short, int, long 역시 저장할 수 있는 범위를 초과해서 값이 저장될 경우 엉터리값이 변수에 저장되는데, 이러한 값을 쓰레기값 이라고 합니다. 개발자는 쓰레기값이 생기지 않도록 주의해야합니다.
보통 하나의 문자를 저장하는데 사용하는 타입 입니다. 문자열을 선언하는 String타입과는 달리 char 타입은 작은 따옴표(’)를 사용합니다.
char 타입을 사용하여 변수를 선언한 코드를 확인해보겠습니다.
public class CharVariableExample {
public static void main(String[] args) {
char c1 = 'A'; // 문자를 직접 저장
char c2 = 65; // 10진수로 저장
char c3 = '\u0041'; // 16진수로 저장
char c4 = '가'; // 문자를 직접 저장
char c5 = 44032; // 10진수로 저장
char c6 = '\uac00'; // 16진수로 저장
int unicode = c1; // 유니코드 얻기
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(unicode);
}
}
A
A
A
가
가
가
65
출력 결과를 보면 모두 문자 값을 출력하는 것을 볼 수 있습니다.
char 타입의 변수에 어떤 문자를 넣지 않고 초기화를 할 경우 다음과같이 빈(empty) 문자열을 대입하면 컴파일 에러가 발생합니다.
char c = ''; // 컴파일 에러 -> char c = ' '; 로 바꿔줘야 함
하지만 String 변수는 큰 따옴표 두개를 붙인 빈 문자를 대입하여 선언해도 괜찮습니다.
String str = "" // 가능
자바에서 정말 많이 사용하는 정수형 타입으로, 정수 연산을 하기 위한 기본 타입입니다. 4byte(32bit)로 표현되기 때문에 저장할 수 있는 범위는 -2,147,483,648 ~ 2,147,483,647 입니다. 주로 실무에서 정수값을 int 타입으로 가장 많이 사용하고, 21억이 넘어가는 큰 범위의 숫자는 long 타입을 사용합니다.
public class IntVariableExample {
public static void main(String[] args) {
int result = 10 + 20;
System.out.println(result); // 연산 결과 30 출력
}
}
자료구조나 알고리즘 문제를 풀 때 뿐만 아니라 실무에서도 많이 활용하게 될 기본 정수형 타입이므로 잘 알아두세요.
8byte(64bit)로 표현되는 정수값을 저장할 수 있는 타입으로, int 타입보다 저장할 수 있는 범위가 많습니다. -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 까지의 값을 저장할 수 있습니다. 어마어마한 숫자죠. 수치가 큰 데이터를 다루는 프로그램에서는 long 타입이 필수적으로 사용되는데, 주로 은행, 우주와 관련된 프로그램에서 사용합니다.
long 타입의 변수를 초기화할 때는 정수값 뒤에 소문자 엘(l)이나 대문자 엘(L)을 붙일 수 있습니다. 이것은 4byte 정수 데이터가 아닌 8byte 정수 데이터임을 컴파일러에게 알려주기 위한 목적입니다. 이렇게 붙이지 않으면 컴파일 에러가 납니다.
소수점이 있는 숫자를 ‘실수’ 라고 하는데, 이런 소수점이 있는 실수 데이터를 저장하기 위한 타입입니다. 메모리 사용 크기에 따라 float, double이 있습니다.
float (4byte) < double (8byte)
메모리 사용 크기는 앞서 본 int, long 각각의 크기와 같지만, 정수 타입과는 다른 저장 방식 때문에 훨씬 더 큰 범위의 값을 저장할 수 있습니다.
자바는 실수 연산을 하기 위한 기본 타입으로 double을 사용합니다. float을 사용하여 실수값을 저장하기 위해서는 값 뒤에 소문자 ‘f’나 대문자 ‘F’를 붙여야 합니다.
double var1 = 3.14;
float var2 = 3.14F;

만약 float 타입 값에 F를 붙이지 않는다면 이런 컴파일 오류를 만날 수 있습니다.
이렇게 말이죠!

또한 float과 double의 정밀도 차이는 매우 큽니다!
boolean값은 1byte(8bit)로 표현되는 논리값(true/false)을 저장할 수 있는 데이터 타입입니다. 두 가지 상태로 분류하며 상태값에 따라 조건문과 제어문의 실행 흐름을 변경하는데 주로 이용됩니다.
public static void main(String[] args) {
boolean stop = true;
if (stop) {
System.out.println("중지합니다!");
} else {
System.out.println("시작합니다!");
}
}
타입 변환은 데이터 타입을 다른 데이터 타입으로 변환하는 것을 말합니다. 예를 들어 int타입을 double타입으로 변환하거나 반대로 double타입을 int타입으로 변환하는 행위를 말합니다.
타입 변환에는 두가지 방법이 있는데 하나는 자동으로(묵시적) 타입변환을, 또 하나는 강제적으로(명시적) 타입을 변환해주는 방법입니다.
작은 크기의 타입은 큰 크기의 타입으로 자동 타입 변환이 가능합니다.
public static void main(String[] args) {
byte byteValue = 10;
int intValue = byteValue; // 타입 변환 (byte -> int)
System.out.println(intValue);
char charValue = '가';
intValue = charValue;
System.out.println("'가'의 유니코드= " + intValue);
intValue = 500;
long longValue = intValue; // 타입 변환 (int -> long)
System.out.println(longValue);
intValue = 200;
double doubleValue = intValue; // 타입 변환 (int -> double)
System.out.println(doubleValue);
}
10
'가'의 유니코드= 44032
500
200.0
``
반대로, 큰 크기의 타입은 작은 크기의 타입으로 자동 타입 변환을 할 수 없습니다. 마치 큰 그릇의 물을 작은 그릇 안에 모두 넣을 수 없는 것과 동일한 이치입니다. 하지만 큰 그릇을 쪼개어 하나의 조각만 작은 그릇에 넣는다면 가능하죠. 이렇게 쪼개는 행위를 타입 ‘캐스팅’ 해준다고 표현합니다. 강제 타입 변환 이라고도 하지요.
long타입을 int타입으로 변환해본다고 가정해보죠. long타입에 300이라는 숫자값이 저장되어 있을 경우 8byte 중 끝의 4byte로 300이라는 값을 충분히 표현할 수 있으므로 int타입으로 강제 타입 변환하면 앞의 4byte는 버려지고 끝의 4byte만 int 타입 변수에 저장되어 300이 그대로 유지됩니다.
long longValue = 300;
int intValue = (int) longValue; // intValue는 300이 그대로 저장
실수 타입(double, float)은 정수 타입(int, long)으로 자동 변환되지 않기 때문에 강제 타입 변환을 사용해야 합니다. 이 경우 소수점 이하 부분은 버려지고, 정수 부분만 저장이 되겠죠.
double doubleValue = 3.14;
int intValue = (int) doubleValue; // intValue는 정수 부분인 3만 저장
강제 타입 변환시 주의해야할 점은 사용자로부터 입력받은 값을 변환할 때 값의 손실이 발생하면 안된다는 것 입니다. 변환 전에 우선 안전하게 값이 보존될 수 있는지 검사하는 것이 좋습니다.
연산은 기본적으로 같은 타입끼리 수행되기 때문에 서로 다른 타입일 경우 두개의 피연산자(operand) 중 크기가 큰 타입으로 자동변환된 후 연산을 수행합니다. 예를 들어 int 타입 피연산자와 double 타입 피연산자를 덧셈 연산하면 먼저 int 타입 피연산자가 double 타입으로 자동 변환되고 연산을 수행합니다.
int intValue = 10;
double doubleValue = 5.5;
double result = intValue + doubleValue; // result에 15.5가 저장
만약 int 타입으로 꼭 연산을 해야한다면 double 타입을 int 타입으로 강제 변환하고 덧셈 연산을 수행하면 됩니다
int intValue = 10;
double doubleValue = 5.5;
int result = intValue + (int)doubleValue; // result에 15가 저장

이렇든 강제 변환이 가능하다.
byte byteValue = 10;
char charValue = 'A';
(1) int intValue = byteValue;
(2) int intValue = charValue;
(3) short shortValue = charValue;
(4) double doubleValue = byteValue;
크게 보면 자바의 데이터 타입(자료형)은 기본 자료형(Primitive Data Type)과 참조 자료형(Reference Data Type)으로 나뉩니다. 앞서 봤었던 기본 자료형은 여러분들이 추가로 만들 수 없고 자바에서 제공해주는 타입이 정해져 있지만, 참조 자료형은 여러분들 마음대로 바꿀 수 있습니다.

지금까지 배운 기본 자료형 타입 외에 참조 자료형에 대해서도 간단하게 알아보겠습니다.
기본 자료형으로 선언된 변수와 참조 자료형으로 선언된 변수의 차이점은 저장되는 값이 무엇이냐 입니다. 기본 자료형인 byte, char, short, int, long, float, double, boolean을 이용해서 선언된 변수는 실제 값 을 변수 안에 저장하지만, 참조 자료형인 Array(배열), Enum(열거형), Class를 이용해서 선언된 변수는 메모리의 번지(주소)를 값으로 갖습니다. 번지를 통해 객체를 참조한다는 뜻에서 참조 자료형(타입) 이라고 부릅니다.

기본 타입 변수의 초기화를 해보겠습니다.
int age = 10;
이것 또한 초기화 입니다. 참조 변수의 초기화죠
Calculator calculator = new Calculator();
int를 초기화할 때는 값을 바로 적어주었고, 참조변수인 Calculator를 초기화할 때에는 new라는 예약어를 사용합니다.
자바에서는 이렇게 new를 사용하여 초기화하는 것을 참조 자료형, new 없이 바로 초기화가 가능한 것을 기본 자료형이라고 합니다.
단, 참조 자료형에서 딱!!하나 초기화할 때 예외적인 것이 있습니다. 바로 문자열을 다루는 String 인데, 초기화할 때에는 다음과 같이 초기화합니다.
String name = "sung yeon";
그리고 다음과 같이 초기화를 해도 상관이 없죠.
String name = new String("sung yeon");
이 두개의 값은 출력해보면 알겠지만 결과가 동일합니다.
String은 참조 자료형이지만 new를 사용해서 객체를 생성하지 않아도 되는 유일한 타입임을 알고 계시면 됩니다.
먼저 우리가 알고있는 기본형(Primitive) 타입과 이것의 Wrapper 타입을 알아봅시다. 참고로 Wrapper 타입(클래스)란 기본 자료형을 참조 자료형처럼 사용하기 위한 클래스 입니다. 즉, 기본 자료형을 감싸 객체 형태로 만든 것이죠.
기본형 에서 Wrapper 타입으로 변환되는 것을 박싱(Boxing), 그리고 반대로 변환되는 것을 Unboxing 이라고 부릅니다. 참고로 Java 1.5 버전부터 도입된 기능입니다.

오토박싱은 기본 타입의 데이터를 Wrapper 클래스의 객체로 변환하는 것을 말합니다.
다음 코드에서 박싱(Boxing)과 오토박싱의 차이를 예시로 보겠습니다.
int index = 11;
Integer number = new Integer(index); // 박싱(Boxing)
int index = 11;
Integer number = index; // 오토박싱
오토박싱은 제네릭 컬렉션에 값을 추가하는 경우 유용합니다.
다음 예제를 보면 Integer 타입의 ArrayList를 선언하여 생성했지만 add() 메소드를 보면 Integer가 아닌 기본 타입값을 전달했죠. 오토박싱으로 기본 타입의 값은 Wrapper 클래스의 객체로 변환되어 Integer 타입의 ArrayList에 할당됩니다.
public class AutoBoxingExample {
public static void main(String args[]) {
ArrayList<Integer> arrayList = new ArrayList<>();
/* 오토 박싱 */
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
System.out.println("ArrayList: " + arrayList);
}
}
실행 결과
ArrayList: [10, 20, 30]
언박싱은 래퍼 클래스를 기본형 타입으로 변환하는 것을 말합니다. 예를 들어 Integer를 int로 변환하는 것도 언박싱이죠. 다음 코드로 오토박싱과 언박싱의 차이를 보겠습니다.
int index = 20;
Integer intObject = index; // 오토박싱
int index = intObject; // 언박싱 Integer -> int
편의성을 위해 오토박싱과 언박싱이 제공되지만, 내부적으로 추가 연산 작업을 거치게 됩니다. 아래 두가지 코드에서도 확실한 성능 차이가 보이실겁니다.
그렇기 때문에, 오토박싱과 언박싱이 일어나지 않도록 동일한 타입 연산이 이루어지도록 구현해야합니다.
public class AutoBoxingPerformanceExample {
public static void main(String[] args) {
long startTimeMs = System.currentTimeMillis();
Long sum = 0L;
for (int i = 0; i < 1000000; i++) {
sum = sum + 1;
}
System.out.println("실행 시간: " + (System.currentTimeMillis() - startTimeMs) + "ms");
}
}
// 실행 시간: 37ms
public static void main(String[] args) {
long startTimeMs = System.currentTimeMillis();
long sum = 0L;
for (int i = 0; i < 1000000; i++) {
sum = sum + 1;
}
System.out.println("실행 시간: " + (System.currentTimeMillis() - startTimeMs) + "ms");
}
// 실행 시간: 5ms
100만 건 기준으로 연산 수행에 걸린 시간을 측정해보면, 성능 차이가 7배 정도의 차이가 납니다. 따라서 오토박싱과 언박싱이 이루어지지 않도록 동일한 타입연산이 이루어지도록 구현해야합니다.
Integer.parseInt() : 문자열 파싱하여 int 객체 생성Integer.valueOf() : 문자열로 Integer 객체 생성String str = "12345";
int intValue = Integer.parseInt(str);
Integer integerValue = Integer.valueOf(str);
System.out.println(intValue);
System.out.println(integerValue);
위의 코드에서 만약 str값을 “문자열입력” 이라는 값으로 변경한다면 어떻게 될까요?
자바 컴파일러는 숫자로 입력된 문자열 값을 숫자 타입으로 파싱하는 것을 기대했지만, 숫자가 아닌 일반 문자열로 입력했기 때문에 파싱 과정에서 오류가 발생합니다.
NumberFormatException
