Java Standard - 변수(Variable)
변수에 대해 알아보자
변수와 상수
변수란?
단 하나의 값을 저장할 수 있는 메모리 공간
변수의 선언과 초기화
- 선언
- 변수 선언시, 변수 타입에 맞는 크기의 저장공간이 확보되고, 확보된 저장공간을 변수이름을 통해 사용할 수 있게 된다.
1
2
String name; // name 이라는 이름의 변수를 선언
변수타입 변수이름
- 변수 타입: 저장될 값이 어떤 ‘타입’인지를 지정하는 것
- 변수 이름: 변수에 붙인 이름
- 초기화
- 변수를 사용하기 전에 처음으로 값을 저장하는 것, 메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 알 수 없는 값이 남아 있을 수 있기 때문
변수의 명명규칙
- 대소문자가 구분되며 길이에 제한이 없다.
- 예약어를 사용해서는 안된다.
- 숫자로 시작해선느 안 된다.
- 특수문자는
_
와$
만 허용한다. - 클래스의 이름의 첫글자는 대문자
- 여러 단어로 이루어진 단어의 첫글자를 대문자
- 상수의 이름은 모두 대문자, 여러단어로 이루어진 경우
_
로 구분
변수의 타입
- 기본형
- 실제 값을 저장
- boolean, char, byte, short, int, long, float, double
- 참조형
- 객체의 주소를 저장
기본형
- boolean(1byte): 논리형,
true
,false
저장 - char(2byte): 문자형, 내부적으로는 유니코드를 저장
- byte(1byte): 정수형
- short(2byte): 정수형
- int(4byte): 정수형, 기본 자료형, CPU가 가장 효율적으로 처리할 수 있는 타입
- long(8byte): 정수형
- float(4byte): 실수형, 낮은 정밀도
- double(8byte): 실수형, 기본 자료형, 높은 정밀도
상수와 리터럴
- 상수
- 값을 저장할 수 있는 공간, 한번 값을 저장하면 변경 할 수 없음
final
keyword 사용 - 리터럴
- 그 자체로 값을 의미 하는 것
- 타입구분 : 접미사를 붙여서 구분함
- long 타입:
L
,l
- int 타입: 미표기
- byte, short : int 타입의 리터럴 사용
- float 타입:
F
,f
- double 타입:
D
,d
(기본 자료형이라 생략 가능)
- long 타입:
- 진법구분 : 접두사를 붙여서 구분함
- 8진수:
0
- 16진수:
0x
,0X
- 2진수:
0b
- 8진수:
- 문자 리터럴과 문자열 리터럴
- 문자 리터럴: 문자 하나만
'
으로 감싼 것, 빈 문자 비허용 - 문자열 리터럴: 여러 문자를
"
으로 감싼 것, 빈 문자열 허용
- 문자 리터럴: 문자 하나만
진법
10진법과 2진법
컴퓨터는 2진 체계로 설계되었기 때문에, 우리가 변수에 값을 저장한다고 할때 10진수를 저장한다고 해도 2진수로 바뀌어 저장되게 된다.
비트(bit)와 바이트(byte)
- 비트(bit): 한자리의 2진수, 컴퓨터가 값을 저장할 수 있는 최소단위
- 바이트(byte): bit를 8개를 묶은 단위 (1byte = 8bit)
- 워드(word): CPU가 한번에 처리할 수 있는 데이터 크기, CPU 성능에 따라 다름, (대부분 64비트)
n
bit로 표현할 수 있는 10진수 값의 개수 : 2ⁿ개 값의 범위 : 0 ~ 2ⁿ-1
8진법과 16진법
2진법으로 값을 표현하면 자리수가 상당히 길어진다는 단점이 있는데, 이를 보완하기 위해 8진법이나 16진법을 사용한다. 8진수는 2진수의 3자리를, 16진수는 2진수의 4자리를 각각 한자리로 표현할 수 있어 자리수가 짧아져 알아보기 쉽고, 서로 간의 변환 방법도 매우 간단하다.
1
2
8진수로 변환: 2진수를 뒤에서 3자리씩 끊어서 변환
16진수로 변환: 2진수를 뒤에서 4자리씩 끊어서 변환
2진수를 8진수, 16진수로 변환
정수의 진법 변환
- 10진수 → n진수
- 10진수를 해당 진수로 더이상 나눌 수 없을때까지 나누고, 이때 마지막 몫과 나머지를 순서대로 적는다
1
2
3
4
5
6
46을 변환한다면, 101110
46 / 2 = 23 (나머지 **0**)
23 / 2 = 11 (나머지 **1**)
11 / 2 = 5 (나머지 **1**)
5 / 2 = 2 (나머지 **1**)
2 / 2 = **1** (나머지 **0**)
10진수 → 2진수
- n진수 → 10진수
- 각 자리수의 해당하는 단위의 값을 곱해서 모두 더한다.
1
2
123을 변환한다면, 9
1 X 2² + 2 X 2¹ + 2 X 1(2의0제곱) = 9
2진수 → 10진수
실수의 진법 변환
- 10진수 → n진수
- 10진수의 소수부에만 해당 진수로 소수부가 사라질때까지 곱하고, 이때의 곱한 결과의 정수부만 순서대로 적고 앞에
0.
을 붙여 해당 진법의 소수부를 따로 표시한다.
1
2
3
4
0.625을 변환한다면, 0.101
0.625 X 2 = **1**.25
0.25 X 2 = **0**.5
0.5 X 2 = **1**.0 (결과에서 소수부가 사라짐)
10진수 → 2진수
- n진수 → 10진수
- 각 자리수의 해당하는 단위의 값을 곱해서 모두 더한다. (소수는 -1제곱부터 시작한다)
1
2
3
4
5
0.101을 변환한다면, 0.625
1 X 2-¹ + 0 X 2-² + 1 X 2-³
= 1 X 0.5 + 0 X 0.25 + 1 X 0.125
= 0.5 + 0.125
= 0.625
2진수 → 10진수
음수의 2진 표현 - 2의 보수법
보수법
- 보수법
- 어떤 수의 n의 보수는 더했을때 n이 되는 수를 의미한다. ex) 7의 10의 보수는 3이다, 2의 10의 보수는 8이다.
- 사용이유
- 음수를 0과 1로만 표현한다면? -0 과 +0이 존재하게 됨 -5와 +5를 더했을때 2진수로 0이 되지 않음
- 보수법에 의해 음수를 배치한다면 해결 가능, 현재 대부분 시스템이 2의 보수법으로 정수표현
10진법의 음수를 2진수로 표현하기
- 음의 정수의 절대값을 구한다.
- 절대값을 2진수로 변환한다.
- 변환된 2진수의 2의 보수를 구한다.
2의 보수 구하는 방법
2의 보수 = 1의 보수 + 1
2진수 0101의 2의 보수를 구한다고 생각해보자 이때 크기는 4비트이기 때문에 10000을 만들면 되는데(맨 왼쪽의 1은 버려짐), 10000을 만들기 위해서는 1111이 된 뒤 여기에 +1 을 해주면 된다.
1111이 되는 수는 1의 보수이고, 이것에 +1을 해주면 2의 보수가 된다.
0101의 1의 보수는 1010이고, 1010 + 1 = 1011 이다. 따라서 0101의 2의 보수는 1011이다.
2의 보수법으로 표현한 10진수
10진법으로 -5를 표현하기 위해서는,
- 10진법의 5를 2진법으로 변환 = 0101
- 0101의 2의 보수를 구함 = 1011
이렇게 구하고, 이때 구해진 1011에서 맨 왼쪽에 첫번째 비트(MSB) 1은 음수를 뜻하기도한다. 다만 처음에 말했던 것처럼 맨 왼쪽의 첫번째 비트만을 바꿔서 표현할 수 는 없다.
기본형
논리형 - boolean
- 저장 되는 값: true, false
- 기본 값: false
- 크기 : 1byte(1 bit만으로도 충분하지만, 자바에서는 데이터를 다루는 최소 단위가 byte이기 때문)
문자형 - char
- 저장 되는 값: 단 하나의 문자만 저장, 실제로는 문자가 아닌 문자의 유니코드가(정수)가 저장, 음수를 나타낼 필요가 없어서 표현할 수 있는 값의 범위가 다르다.
- 기본값 : \u0000
- 크기 : 2byte
- 문자 인코딩
- 문자를 코드로 변환하는 것 문자 디코딩
- 코드를 문자로 변환하는 것
문자를 저장할 때는 인코딩해서, 읽어옭때는 디코딩 해서 이때 사용하는 표를 유니코드표 라고 하고, 인코딩과 디코딩시 사용하는 표가 바뀌면 글자가 제대로 표현되지 않는다.
- 유니코드
- 예전에는 아스키코드(정보교환을 위한 미국 표준 코드)를 사용했는데, 미국 표준 코드이기때문에 한글은 포함되지 않았고, 여러가지 중에서 한글이 포함된 코드표가 있는데 cp949가 윈도우에서 사용하는 코드표다. 여러개의 코드표를 전세계의 모든 문자를 하나의 통일된 문자 집합으로 표현한 것이 유니코드이다. 유니코드는 아스키코드의 내용을 포함하고 있다. 유니코드의 인코딩에는 UTF-8, UTF-16, UTF-32등 여러가지 방식이 있는데, 자바에서는 UTF-16를 사용한다.
- UTF-8 : 하나의 문자를 1~4byte의 가변크기로 표현, 다루기 어렵, 웹에서 주로 사용
- UTF-16 : 모든 문자를 2byte의 고정크기로 표현, 문서의 크기가 커짐
정수형 - byte, short, int, long
- 기본 자료형 : int
- n비트로 표현할 수 있는 표현할 수 있는 값의 범위: (-2ⁿ⁻¹) ~ (2ⁿ⁻¹-1)
- 왼쪽의 첫번째 비트는
부호비트
, 나머지는 값을 표현, 양수에서 -1 하는 이유는0
이 포함되기 때문에 - 왼쪽의 첫번째 비트는
- 정수형 선택의 기준
- 정수형 변수를 선언시에는 int를 사용하고, int의 범위를 벗어날 때는 long을 사용
- JVM의 피연산자 스택이 피연산자를 4byte 단위로 저장하기 때문에 이보다 작은 자료형의 값을 계산할 때는 4byte로 변환한 뒤 연산을 하기 때문에 int를 사용하는 것이 더 효율적이다.
JVM의 피연산자 스택? 변수가 피연산자(계산에 사용될 경우)가 될 경우 JVM은 피연산자 스택이라는 곳에 저장하는데, 지금 쉽게 이해하자면 JVM이 실제 연산을 할 때 사용하는 메모리 공간 정도가 되겠다. 따라서 위에서 한 말을 덧붙여 설명하자면, byte나 short 자료형의 변수를 선언 하더라도 이 변수를 이용해 계산을 할 때면 JVM이 실제 연산을 하면서 저장하는 공간에서는 4byte공간에 저장을 하고, 이때 이렇게 저장하기 위해 형변환이 일어나니 int를 사용하는것이 더 효율적이다.
- 부호가 없는 정수의 오버플로우: 0~15가 무한히 반복된다.
- 부호가 있는 정수의 오버플로우: 부호비트가 0에서 1이 될 때 오버플로우가 발생한다.-8~7이 무한히 반복된다.
최대값 +1 → 최소값 최소값 -1 → 최대값
실수형 - float, double
기본 자료형: double
- 실수형 선택의 기준
- 얼마나 큰 값을 표현할 수 있는 가와 얼마나 0에 가깝게 표현 할 수 있는 가
- 연산속도의 향상이나 메모리 절약을 위해서라면 float를 선택하고, 더 큰 값의 범위라던가 더 높은 정밀도를 원한다면 double을 선택
- 언더플로우(underflow)
- 정수형에는 없는 언더플로우는 실수형으로 표현할 수 없는 아주 작은 값, 양의 최소값보다 작은 값이 되는 경우를 의미한다.
- 오버플로우(overflow)
- 실수형에서 오버플로우가 발생하면 변수의 값은 무한대가 된다.
- 실수형의 저장형식
- 부동소수점의 형태로 저장
- 부호(S): 0이면 양수, 1이면 음수, 2의 보수법을 사용하지 않음
- 지수(E): 부호있는 정수, 범위 -127 ~ 128, 기저법 사용 -127, 128: 숫자 아님(NaN, Not a Number), 양의 무한대, 음의 무한대 표현을 위해 예약된 값
- 가수(M): 실제값을 저장하는 부분(소수점 부분) 부동소수점의 오차: 무한소수나 10진수에서는 유한소수라도 2진수로 변환시 무한소수가 되는 경우때문에 오차가 발생할 수 있다. 또, 유한소수라도 자수를 저장할 수 있는 자리가 한정되어있어 이부분에 저장되지 못하면 오차가 발생한다.
- 부호(S): 0이면 양수, 1이면 음수, 2의 보수법을 사용하지 않음
부동소수점? 실수를
±M X 2ᴱ
와 같은 형태로 표현하는 것을 말한다. 부호(S), 지수(E), 가수(M) 이렇게 3부분으로 이루어져 있다.
기저법? 정수형에서 2의 보수법 처럼 부호있는 정수를 저장하는 방법으로, 저장할 때 특정 값(기저)을 더했다가 읽어올 때는 다시 뺀다.
저장 예시 (9.1234567을 float에 저장)
- 9.1234567의 2진법으로 변환 ( 10진수에서는 유한이지만 2진수로는 무한 )
- 9 → 1001
- 0.1234567 → 0.000111111001101011011011…
- 1001.000111111001101011011011… 정규화
- 1.001000111111001101011011011… X 2³
- 1.001000111111001101011011011…에서
1.
을 제외한 부분이 가수로 저장 - 2³에서 지수인 3에 기저 127을 더한 130을 2진법으로 변환한 10000010을 지수에 저장
- 1.001000111111001101011011011…에서
- 저장 결과
- 부호: 0
- 지수: 10000010
- 가수: 00100011111100110101101, (1011…는 잘림)
정규화? 실수를 저장할 때에는 1.xxx X 2ⁿ 형태로 변환해서 저장하는데, 이를 정규화라고 함
형변환
형변환(캐스팅, casting)이란?
변수 또는 상수의 타입을 다른 타입으로 변환하는 것을 형변환 이라고한다. 정수형 int와 실수형 float의 값을 더하는 경우 int를 float으로 변환해 두개를 같은 타입으로 맞춘뒤 연산해야한다.
- 형변환 방법
- ()
캐스트 연산자, 형변환 연산자
사용 → (변경할 타입)피연산자 피연산자의 값은 형변환 후에도 아무런 변화가 없다.- 기본형과 참조형간의 형변환은 불가능하고, 기본형에서는
boolean
을 제외한 나머지 타입들은 서로 형변환이 가능하다. - 기본형과 참조형간의 형변환은 불가능하고, 기본형에서는
정수형 간의 형변환
- 큰 타입 → 작은 타입
- 값 손실 발생할 수 있음, 크기의 차이만큼 잘려나가기 때문에 가능성이 있다.
- 작은 타입 → 큰 타입
- 값 손실 발생할 수 없음, 빈 공간을 음수면 1로 양수면 0으로 채운다.
실수형 간의 형변환
- 작은타입 → 큰 타입
- 지수: float의 기저 127을 빼고, double의 기저인 1023을 더한다.
- 가수: float의 가수를 모두 채운 후 남은 자리를 0으로 채운다.
- 큰 타입 → 작은타입
- 지수: double의 기저인 1023을 빼고, float의 기저 127을 더한다.
- 가수: double의 가수 52자리 중 23자리만 저장되고 나머지는 버려진다. 이때 24번째 자리 값이 1이면 반올림이 발생해 23번째 자리값이 1 증가한다.
- float의 범위를 넘는 값을 변환하면 ±무한대 혹은 ±0을 결과로 얻는다.
- 같은 값을 저장해도 정밀도로 인해 다른 값이 저장될 수 있으며, 저장시 다르게 저장되었기 때문에 형변환을 해도 값이 같아지지 않는다.
- 가수: double의 가수 52자리 중 23자리만 저장되고 나머지는 버려진다. 이때 24번째 자리 값이 1이면 반올림이 발생해 23번째 자리값이 1 증가한다.
정수형과 실수형 간의 형변환
- 정수형 → 실수형
- 정수를 2진수로 변환 -> 2진수를 정규화 -> 정규화된 2진수를 실수의 저장형식으로 저장 실수형의 정밀도 제한으로 오차 발생가능성이 있기때문에 정수를 실수형으로 변환할 때에는 float보다 double형으로 변환해야한다. 그러면 오차가 발생하지 않는다.
- 실수형 → 정수형
- 실수형의 소수점이하 값은 버려진다. (반올림X)
자동 형변환
상황
- 형변환의 생략:
float a = 1234;
→float a = (float)1234;
- 범위를 넘으면 오류가 발생하는데 이때 명시적으로 형변환을 해줬을 경우 오류가 발생하지 않는다.
- 연산과정에서(산술 변환):
int i =3; double d = 1.0 + i;
→(double)i;
으로 한 뒤 연산
- 자동 형변환 규칙
- 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.
- 기본형과 참조형은 서로 형변환할 수 없다.
- boolean을 제외한 나머지는 서로 형변환이 가능하다.
- 서로 다른 타입의 연산은 형변환을 하는 것이 원칙이지만, 값의 범위가 작은 타입에서 큰 타입으로의 형변환은 생략할 수 있다.
- 기본형과 참조형은 서로 형변환할 수 없다.
- 묵시적 형변환: 형변환을 써주지 않아도 자동 형변환이 된다.
- 명시적 형변환: 형변환 연산자를 반드시 써줘야한다.
- char와 short는 둘 다 2byte의 크기지만 범위가 달라 값 손실이 발생할 수 있어 자동 형변환이 되지 않는다.