1. 변수
- 데이터를 저장하는 공간
- 하나의 값만 저장할 수 있다.
1.1 변수의 선언과 초기화
- 변수에 저장할 데이터의 타입에 따라 변수 타입을 지정해야 한다.
- 변수에 이름을 붙여 데이터를 저장한 공간을 쉽게 다룰 수 있다.
- 공간을 구분하기 위해 변수 이름은 중복이 불가능하다.
- `int age`와 같이 변수 선언시, 메모리의 빈 공간에 변수 타입 `int`에 해당하는 크기의 공간이 확보되고, 앞으로 이 공간을 `age`를 이용하여 사용할 수 있다.
- 변수에는 다른 프로그램에 의해 저장된 알수없는 값이 남아있을 수 있기 때문에 사용하기 전에 초기화해야 한다.
- 알수없는 값을 쓰레기 값(garbage value)이라고도 한다.
- 초기화란 변수에 처음으로 값을 저장하는 것을 의미한다.
- 대입 연산자`=`를 사용하여 변수에 값을 저장할 수 있다.
- `int age = 23;`
int firstValue = 0;
int addValue = 10;
System.out.println(firstValue);
firstValue = firstValue + addValue;
System.out.println(firstValue);
// 1. firstValue, addValue를 각각 0과 10으로 초기화한다.
// 2. println() 메서드를 사용하여 firstValue의 값을 출력한다.
// 3. firstValue와 addValue에 저장된 값을 읽어온 다음, 더하기 연산을 수행하고, 결과 값을 firstValue에 저장한다.
// 4. firstValue의 값을 출력한다.
1-2. 변수의 명명규칙
- 변수의 이름처럼 프로그래밍에서 사용하는 모든 이름을 식별자라고 한다.
- 식별자를 만드는 규칙은 다음과 같다.
1. 대소문자가 구분되고, 길이에 제한이 없다.
2. 예약어(=키워드, 리져브드 워드)를 사용할 수 없다.
예약어란 프로그래밍 언어의 구문에 사용되는 단어를 의미한다.
abstract, default, for, if, ...숫자로 시작할 수 없다.
3. 특수문자는 `_`와 `$`만이 허용된다.
- 식별자를 만들 때 필수는 아니지만 권장되는 규칙은 다음과 같다.
1. 클래스 이름의 첫 글자는 대문자로 한다.
변수와 메서드 이름의 첫 글자는 소문자로 한다.
2. 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다. (camel case)
checkType
3. 상수의 이름은 모두 대문자로 하며, 여러 단어로 이루어진 경우 `_`로 구분한다.
MAX_NUMBER
2. 변수의 타입
- 데이터의 종류에 따라 변수의 크기와 저장형식을 정의한 것이 자료형(=변수의 타입)이다.
- 자료형은 기본형과 참조형으로 나눌 수 있다.
- 기본형 : 데이터 저장
- 참조형 : 데이터가 저장되어 있는 주소를 저장
- 참조변수의 초기 값은 `null`이며 JVM이 32bit라면 `4byte`의 저장 공간을 가진다.
2-1. 기본형 (primitive type)
- 기본형에는 모두 8개의 자료형이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 나눌 수 있다.
- boolean을 제외한 나머지 7개의 기본형은 서로 연산과 변환이 가능하다.
- 문자형 char는 문자를 내부적으로 정수(유니코드)로 저장하기 때문에 연산이 가능한 것이다.
- int타입의 변수는 대략 10자리 수(약 20억)의 값을 저장할 수 있다.
- 연산 중 저장범위를 넘어설 경우 원하지 않는 값이 저장될 수 있어 주의해야 한다.
- 7~9자리의 수를 계산할 때는 long타입(약 19자리)을 사용하도록 하자.
- 실수형과 정수형의 메모리 공간 크기는 같지만 저장 범위가 다른 것은 저장 방식이 다르기 때문이다.
- 실수형은 정수형보다 훨씬 큰 값을 저장할 수 있지만 오차가 발생할 수 있어 주의해야 한다.
- float의 정밀도는 7자리이고, double의 정밀도는 15자리이다.
2-2. 상수와 리터럴
- 변수와 상수의 차이점은, 상수는 한 번 값을 저장하면 다른 값으로 변경할 수 없다는 것이다.
- 상수를 선언할 때는 변수와 똑같이 선언한 후 타입 앞에 `final` 키워드를 붙이면 된다. `final int MAX_SPEED = 10;`
- JDK 1.6 이전까지는 선언과 동시에 초기화해야 했으나, 그 후부터는 사용하기 전에만 초기화하면 되도록 변경되었다.
- 리터럴은 단지 값을 의미한다.
2-3. 리터럴의 타입과 접미사
- 정수형과 실수형에는 여러 타입이 존재하므로, 리터럴에 접미사를 붙여서 구분한다.
- 정수형 리터럴
- long 타입에 `l` 또는 `L`을 붙인다. 접미사가 없으면 int 타입이다.
- byte와 short 타입의 리터럴은 없으며 int 타입의 리터럴을 사용한다.
- 2, 8, 16진수로 표현된 리터럴도 저장할 수 있다.
- 실수형 리터럴
- float 타입에 `f` 또는 `F`를 붙이고, double 타입의 리터럴에는 `d` 또는 `D`를 붙인다. 접미사가 없으면 double 타입이다.
- 소수점이나 10의 제곱을 나타내는 기호 `E` 또는 `e`, 그리고 접미사 `f`, `F`, `d`, `D`를 포함하고 있으면 실수형 리터럴로 간주된다.
2-4. 타입의 불일치
- 변수의 타입과 리터럴의 타입은 다를수도 있다.
- 큰 컵에 작은 컵에 담겨있던 🍺를 따르는 것이 가능한 것처럼, 저장범위가 넓은 타입의 변수에 좁은 타입의 리터럴을 저장할 수 있다.
// 가능
int i = 'A'; // int 타입 변수 <- char 타입 리터럴
long l = 123; // long 타입 변수 <- int 타입 리터럴
double d = 3.14f; // double 타입 변수 <- float 타입 리터럴
// 불가능, 에러
int i = 0x123456789; // int 타입의 범위를 넘는 값 저장
float f = 3.14; // float 타입 변수 <- double 타입 리터럴
- byte, short 타입의 변수에는 int 타입의 리터럴을 저장할 수 있으나, 각 타입이 저장할 수 있는 범위에 속하는 리터럴이어야 한다.
- 문자 리터럴
- 문자 하나를 작은 따옴표로 감싼 것이다.
- 빈 문자를 저장할 수 없다.
- 공백은 저장할 수 있다.
- 문자열 리터럴
- 문자를 큰 따옴표로 감싼 것이다.
- 빈 문자를 저장할 수 있다.
- 문자열은 모든 타입의 변수와 덧셈연산을 수행할 수 있다. 문자열이 아닌 타입을 문자열로 변환하고 두 문자열을 결합하는 것이다.
- 결합 순서에 따라 결과가 달라질 수 있음을 주의해야 한다.
- 기본형 타입을 문자열로 변환할 때는 빈 문자열을 더하면 된다.
2-5. 형식화된 출력 printf()
- 값을 변환하여 출력하고자 할 때 사용한다.
- 지시자를 이용하여 변수의 값을 여러가지 형식으로 변환하여 출력할 수 있다.
int num = 10;
System.out.printf("[%5d]%n", num); // [ 10]
System.out.printf("[%-5d]%n", num); // [10 ]
System.out.printf("[%05d]%n", num); // [00010]
double d = 1.23456789;
// %f는 소수점 아래 6자리까지만 출력하며, 7자리에서 반올림한다.
System.out.printf("[%f]%n", d); // [1.234568]
// 전체 14자리 중 소수점 아래 10자리
System.out.printf("[%14.10f]%n", d); // [ 1.2345678900]
3. 기본형(primitive type)
3-1. 논리형 - boolean
- true 또는 false를 저장하며, 기본값은 false이다.
- 주로 대답(yes/no), 스위치(on/off)와 같은 논리구현에 사용된다.
- 1bit로 충분하지만 자바에서 데이터를 다루는 최소 단위가 byte이기 때문에 메모리의 크기가 1byte인 것이다.
3-2. 문자형 - char
- 단 하나의 문자를 저장한다.
- 사실, 문자의 유니코드(정수)로 변환하여 저장된다.
- 문자 리터럴 대신 유니코드를 직접 저장할 수 있다. `char ch = 65;`
- 문자의 유니코드는 `int code = (int)ch`와 같이 정수형으로 변환하여 얻을 수 있다.
3-3. 정수형 - byte, short, int, long
n비트로 표현할 수 있는 정수의 개수 : 2^n개 (= 2^(n-1)개 + 2^(n-1)개)
n비트로 표현할 수 있는 부호있는 정수의 범위 : -2^(n-1) ~ 2^(n-1) - 1
- byte, short가 int보다 크기가 작아서 메모리를 절약할 수는 있지만, JVM의 피연산자 스택이 피연산자를 4byte로 저장하기 때문에 그보다 작은 타입의 값을 계산할 때는 4byte로 변환하여 연산을 수행한다. 따라서 int를 사용하는 것이 보다 효율적이다.
- 변수의 값이 표현범위를 넘어서면 오버플로우가 발생하여 원하는 값을 얻을 수 없으므로 주의해야 한다.
3-4. 실수형 - float, double
- 실수형도 오버플로우가 발생할 수 있으며, 이때 값은 무한대가 된다.
- 정수형에는 없는 언더플로우가 있으며, 양의 최소값보다 작은 값이 되는 경우를 의미한다. 이때 값은 0이 된다.
- 부호, 지수, 가수로 이루어져 있어, 정수형보다 큰 범위의 값을 저장하는 것이 가능하다.
- 오차가 발생하지 않도록 정밀도에 주의해야 한다.
4. 형변환 (casting)
- 변수, 상수, 리터럴의 타입을 다른 타입으로 변환하는 것
- 서로 다른 타입간의 연산을 수행할 때 같은 타입으로 맞추는 것이다.
- `(타입)피연산자`와 같이 변환하고자 하는 타입을 괄호와 함께 붙여주면 된다.
- 이때 사용되는 괄호를 형변환 연산자라고 한다.
- 형변환 후에도 피연산자에는 아무런 변화가 없다. 단순히 형변환된 결과를 반환할 뿐이다.
double d = 85.5;
int score = (int)d;
System.out.println(score); // 85
System.out.println(d); // 85.5, d에는 아무런 변화가 없다.
- 실수형을 int 타입으로 변환시 소수점 이하의 값은 반올림하지 않고 그냥 버린다.
4-1. 정수형 간의 형변환
- 큰 타입의 값을 작은 타입으로 변환할 때는 값 손실이 발생할 수 있다.
- 큰 컵에 들어있던 🍺를 작은 컵에 따를 경우, 작은 컵에 담을 수 있을 만큼 들어있었다면 넘치지 않지만 가득 들어있었다면 넘치는 것과 같다.
- 작은 타입의 값을 큰 타입으로 변환할 때는 값 손실이 발생하지 않으며, 다만 나머지 빈 공간이 0 또는 1로 채워진다.
- 변환하려는 값이 음수라면 1로 채워진다.
4-2. 실수형 간의 형변환
- double 타입에서 float 타입으로의 변환
- 지수는 double의 기저인 1023을 뺀 후 float의 기저인 127을 더한다.
- 가수는 double의 52자리 중 23자리만 저장하고 나머지는 버린다.
- 이때, 가수의 24번째 자리의 값이 1이면 반올림이 발생한다.
- float 타입의 범위를 넘는 값을 float로 형변환할 경우, `+/- 무한대` 또는 `+/- 0`을 결과로 얻는다.
- float 타입에서 double 타입으로의 변환
- 지수는 float의 기저인 127을 뺀 후 double의 기저인 1023을 더한다.
- 가수는 float의 가수 23자리를 채우고 남은 자리를 0으로 채운다.
4-3. 정수형과 실수형 간의 형변환
- 정수형과 실수형은 저장형식이 다르기 때문에 보다 복잡한 변환 과정을 거쳐야 한다.
- 정수형을 실수형으로 변환
- 정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장형식으로 저장된다.
- 실수형은 정수형보다 저장범위가 훨씬 크지만, 정밀도로 인한 오차가 발생할 수 있다.
- int는 최대 10자리의 정밀도가 필요하지만 float는 약 7자리의 정밀도를 제공하여 오차가 발생할 수 있다.
- 실수형을 정수형으로 변환
- 정수형의 표현형식으로 소수점 이하의 값은 표현할 수 없기 때문에, 변환시 실수형의 소수점이하 값은 버려진다.
- 만약 소수점이하 값을 버리고 남은 정수가 정수형의 저장범위를 넘는 경우에는 오버플로우가 발생한다.
4-4. 자동 형변환
- 표현범위가 좁은 타입에서 넓은 타입으로 형변환시 형변환을 생략할 수 있다.
- 컴파일러가 자동으로 추가해준다.
- 표현범위가 넓은 타입에서 좁은 타입으로 형변환시 형변환을 생략한다면 에러가 발생한다.
byte -> short -> int -> long -> float -> double
char -> ...
- short와 char의 저장 크기는 2byte로 같지만, 저장 범위가 달라서 형변환을 생략할 수 없다.
남궁성 강사님의 자바의 정석 챕터2를 참고하여 작성한 글입니다.
'Java' 카테고리의 다른 글
Java :: 객체지향 II (0) | 2024.07.07 |
---|---|
Java :: 객체지향 I (0) | 2024.07.06 |
Java :: 배열 (0) | 2024.06.24 |
Java :: 제어문 (0) | 2024.06.24 |
Java :: 연산자 (0) | 2024.06.23 |