<변수의 종류>
자바 원시 타입의 값을 저장하는 변수와 메모리 주소를 저장하는 변수가 있다.
1) 자바 원시 타입 변수(primitive variable)
정수, 부동소수점, 논리, 문자코드의 값을
2) 레퍼런스 변수(referece variable)
자바 원시 타입의 값을 제외한 모든 값
//자바 원시 데이터 타입 변수
//- 정수
byte b; // 1바이트 크기의 메모리
short s; // 2바이트 크기의 메모리
int i; // 4바이트 크기의 메모리
long l; // 8바이트 크기의 메모리
//- 부동소수
float f; // 4바이트 크기의 메모리
double d; // 8바이트 크기의 메모리
//- 문자코드
char c; // 2바이트 크기의 메모리
//- 논리
boolean bool; // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 다만 JVM 명세서에는 int 로 다룬다고 나와있다.
//레퍼런스 변수
String str; // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 메모리 주소를 저장할 만큼 큰 크기
Date date; // 자바 언어 명세서에는 메모리의 크기가 정의되어 있지 않다. 메모리 주소를 저장할 만큼 큰 크기
<메모리 크기에 따라 저장할 수 있는 값의 범위>
1) primitive data type (원시 데이터 타입)
- 정수
- byte : 1byte 메모리 (-128 ~ 127)
- short : 2byte 메모리 (-32768 ~ 32767)
- int : 4byte 메모리 (약 -21억 ~ 21억)
- long : 8byte 메모리 (약 -922경 ~ 922경)
- 부동소수점
- float : 4byte 메모리 (유효자릿수 7자리)
- double : 8byte 메모리 (유효자릿수 15자리)
- 문자
- char : 2byte 메모리 (0 ~ 65535). UCS-2 코드 값 저장.
- 논리값
- boolean : JVM에서 4 바이트 int 메모리를 사용한다. 배열일 경우 1 바이트 byte 메모리를 사용한다.
2) reference(레퍼런스)
데이터가 저장된 메모리의 주소를 저장하는 메모리.
- 문자열(주소)
- String : 문자열이 저장된 메모리의 주소를 저장한다.
프로그래밍 입문 단계에서는 그냥 문자열을 저장하는 메모리로 생각하라!
- 날짜(주소)
- Date : 날짜 값이 저장된 메모리의 주소를 저장한다.(날짜를 저장하는 메모리로 생각)
<정수 변수 - 변수의 메모리 크기>
// 1바이트 크기의 정수 값을 담을 메모리 준비
byte b;
// 값을 메모리에 저장하려면 1과 0, 2진수 형태로 바꿔야 한다.
// 정수를 2진수로 바꿀 때 '2의 보수' 방식을 사용한다.
// 1 byte(8 bit)에 저장할 수 있는 최대/최소값은 다음과 같다.
b = -128; // 10000000
b = 127; // 01111111
// 다음과 같이 메모리 크기를 벗어난 값을 저장하려 하면 컴파일 오류가 발생한다.
//b = -129; // 컴파일 오류!
//b = 128; // 컴파일 오류!
// 2바이트 크기의 정수 값을 담을 메모리 준비
short s;
// 2바이트 메모리에 담을 수 있는 최소/최대 정수값
s = -32768; // 10000000 00000000
s = 32767; // 01111111 11111111
// 2바이트 범위를 벗어나면 컴파일 오류!
//s = -32769; // 컴파일 오류!
//s = 32768; // 컴파일 오류!
// 4바이트 크기의 정수 값을 담을 메모리 준비
int i;
// 4바이트 메모리에 담을 수 있는 최소/최대 정수값
i = -2147483648; // 10000000 00000000 00000000 00000000
i = 2147483647; // 01111111 11111111 11111111 11111111
// 다음은 값을 저장할 메모리의 크기 때문에 발생한 오류가 아니다.
// 리터럴 크기의 문제다.
// 정수 값 뒤에 L 또는 l을 붙이지 않은 리터럴은 4바이트 크기를 의미하다.
// 그런데 4바이트를 넘어서는 값을 리터럴로 표현했기 때문에 오류가 발생한 것이다.
//i = -2147483649; // 컴파일 오류!
//i = 2147483648; // 컴파일 오류!
// 해결책?
// - 4 byte 크기를 벗어나는 정수를 표기할 때는 반드시 숫자 뒤에 L 또는 l을 붙여야 한다.
//i = -2147483649L; // 컴파일 오류가 발생하는 이유? 메모리의 크기가 4바이트라서 값을 저장할 수 없다.
//i = 2147483648L; // 컴파일 오류!
// 8바이트 크기의 정수 값을 담을 메모리 준비
long l;
// 8바이트 메모리에 담을 수 있는 최소/최대 정수값
l = -9223372036854775808L; // 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
l = 9223372036854775807L; // 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
<정수 변수 - 변수와 리터럴의 크기>
//4바이트 정수 리터럴 ==> byte, short 변수
//- 4바이트 리터럴인 경우 메모리 크기에 상관없이 저장할 수만 있다면
// byte(1바이트), short(2바이트) 메모리에 값을 저장해도 컴파일 오류가 발생하지 않는다.
//
byte b;
short s;
b = 127; // 4바이트 리터럴 ==> 1바이트 메모리
s = 32767; // 4바이트 리터럴 ==> 2바이트 메모리
//- 단, 리터럴을 메모리에 저장할 수 없다면 컴파일 오류가 발생한다.
// b = 128; // 1바이트 크기를 초과하는 값
// s = 32768; // 2바이트 크기를 초과하는 값
//8바이트 정수 리터럴
//- 8바이트 리터럴인 경우 값이 크고 작음에 상관없이
// byte(1바이트), short(2바이트), int(4바이트) 메모리에 값을 저장하려하면 컴파일 오류가 발생한다.
// b = 127L;
// s = 32757L;
// int i = 100L;
<정수 변수 - 크기가 다른 변수끼리 값 할당>
long l = 100;
int i = 100;
short s = 100;
byte b = 100;
char c = 100;
//변수의 값을 다른 변수에 저장할 때,
//- 값의 크기에 상관없이 같거나 큰 크기의 메모리이어야 한다.
long l2;
int i2;
short s2;
byte b2;
char c2;
// long ===> long 이상
l2 = l;
//i2 = l; // 컴파일 오류
//s2 = l; // 컴파일 오류
//b2 = l; // 컴파일 오류!
//c2 = l; // 컴파일 오류!
// int ===> int 이상
l2 = i;
i2 = i;
//s2 = i; // 컴파일 오류!
//b2 = i; // 컴파일 오류!
//c2 = i; // 컴파일 오류!
// short ===> short 이상
l2 = s;
i2 = s;
s2 = s;
//b2 = s; // 컴파일 오류!
//c2 = s; // 컴파일 오류! char(0 ~ 65535) | short(-32768 ~ 32767)
// byte ===> byte 이상
l2 = b;
i2 = b;
s2 = b;
b2 = b;
//c2 = b; // 컴파일 오류! char(0 ~ 65535) | byte(-128 ~ 127)
<부동소수점 변수 - 변수의 메모리 크기>
// 4바이트 부동소수점 변수
//- 유효자릿수 7자리 부동소수점 저장 가능
//- 10 진수로 부동소수점을 표현할 경우 소수점을 제외한 숫자가 7 개인 경우 정상적으로 메모리에 저장된다는 의미
//
float f;
f = 9.876545f; // 소수점을 떼면 숫자의 개수가 7개이다.
System.out.println(f);
f = 987654.5f; // 소수점을 떼면 숫자의 개수가 7개이다.
System.out.println(f);
// 소수점을 뗐을 때 앞에 0만 있을 경우 그 0은 자릿수에서 제외한다.
f = 0.000009876545f; // 소수점을 떼면 숫자가 13개 이지만, 앞의 0을 제외하면 실제 7개이다.
System.out.println(f); // OK
// 주의!
//- 유효자릿수가 7자리를 넘어가면 정상적으로 값을 저장되지 않을 수 있다.
f = 9.8765456f; // 맨 뒤의 값이 반올림 된다.
System.out.println(f);
f = 9876545.6f; // 맨 뒤의 값이 반올림 된다.
System.out.println(f);
// 8바이트 부동소수점 변수
//- 유효자릿수 15자리 부동소수점 저장 가능
//- 10 진수로 부동소수점을 표현할 경우 소수점을 제외한 숫자가 15 개인 경우 정상적으로 메모리에 저장된다는 의미
//
double d;
d = 9.99999999988888; // 소수점을 떼면 숫자의 개수가 15개이다.
System.out.println(d);
d = 9999999.88888888; // 소수점을 떼면 숫자의 개수가 15개이다.
System.out.println(d);
d = 99999999998888.8; // 소수점을 떼면 숫자의 개수가 15개이다.
System.out.println(d);
// 소수점을 뗐을 때 앞에 0만 있을 경우 그 0은 자릿수에서 제외한다.
d = 0.00000999999999988888; // 소수점을 떼면 숫자가 21개 이지만, 앞의 0을 제외하면 실제 7개이다.
System.out.println(d); // OK
// 주의!
//- 유효자릿수가 15자리를 넘어가면 정상적으로 값을 저장되지 않을 수 있다.
d = 9.999999999999997; // 맨 뒤의 값이 반올림 되거나 잘린다.
System.out.println(d);
d = 999999999999999.7; // 맨 뒤의 값이 반올림 되거나 잘린다.
System.out.println(d);
// 주의!
//'유효자릿수'는 부동소수점의 저장 가능 여부를 간단히 계산하기 위해 나온 개념이다.
//실제는 유효자릿수에 해당하는 부동소수점이라도 정규화 과정을 통해 2 진수로 변환되는 과정에서
//값이 짤리는 경우가 있음을 잊지 말라!
//
//
// 단정도(single precision)와 배정도(double precision)
//- double 변수는 float 변수에 두 배 정도 더 정밀한 값을 저장할 수 있다.
// 그래서 '배정도(double precision)'라 한다.
//- float은 double과 비교하여 한 배 정도 정밀한 값을 저장할 수 있다.
// 그래서 '단정도(single precision)'이라 한다.
<부동소수점 변수 - 변수와 리터럴의 크기>
float f;
double d;
// 변수도 크기에 따라 구분되지만, 리터럴도 크기에 따라 구분된다.
// - 부동소수점 리터럴 값 뒤에 f나 F를 붙이면, 4바이트 크기의 부동소수점 값을 의미한다.
// - 부동소수점 리터럴 값 뒤에 d나 D를 붙이거나 아무것도 붙이지 않으면, 8바이트 크기의 부동소수점 값을 의미한다.
f = 9999.888f; // 4바이트 변수 = 4바이트 리터럴
System.out.println(f);
d = 99999999.8888888; // 8바이트 변수 = 8바이트 리터럴
System.out.println(d);
// - float 메모리에 값을 저장할 때는 유효자릿수가 7자리 이하인 4바이트 부동소수점(f 또는 F가 붙은)을 저장하라!
// - double 메모리에 값을 저장할 때는 유효자릿수가 15자리 이하인 8바이트 부동소수점을 저장하라!
double d;
// 주의!
// - 잘못된 리터럴 값을 변수에 저장해봐야 소용없다!
d = 99999.8888877777f;
System.out.println(d);
// 4바이트 크기를 넘어가는 부동소수점 리터럴은 이미 짤린 값이기 때문에 제대로 저장될 수 없다.
d = 99999.8888877777f;
System.out.println(d);
// 주의!
// 정수의 경우 리터럴을 표현할 때
// 값이 그 크기를 넘어가면 컴파일 오류가 발생하지만,
// 부동소수점의 경우 리터럴이 메모리의 크기를 넘어갈 때
// 컴파일 오류 대신 단지 값이 짤린다.
// 변수의 크기에 맞춰 부동소수점의 리터럴을 지정하라.
float f = 99999.88f;
System.out.println(f);
d = 99999.8888877777;
System.out.println(d);
// 4바이트 부동소수점을 8바이트 메모리에 저장할 때
// 계산 방식에 의해 소수점 이하의 수가 근사 값으로 바뀐다.
// => 8바이트 메모리에 값을 저장할 때는 8바이트 리터럴을 사용하라.
d = 99999.88f;
System.out.println(d);
float f1 = 99988.88f;
float f2 = 11.11111f;
// 각 변수의 값이 개별적으로 옳은 부동소수점이라도,
System.out.println(f1);
System.out.println(f2);
// 주의!
// 연산 결과가 해당 타입의 크기를 벗어 난다면 그 결과 값이 짤린다.
float f3 = f1 + f2;
System.out.println(f3);
// 그래서 부동소수점을 다룰 때는 가능한 float 보다 두 배 더 정밀한 double을 사용하라!
// 문법에서도 double 리터럴을 기본 부동소수점으로 간주한다.
// 즉 부동소수점 뒤에 d나 D 표시를 생략할 수 있다.
double d1 = 99988.88;
double d2 = 11.11111;
double d3 = d1 + d2;
System.out.println(d3);
<부동소수점 변수 - 크기가 다른 변수끼리 값 할당>
float f;
double d;
d = 3.14;
// 값의 유효 여부에 상관없이 메모리 크기가 큰 변수의 값을 작은 크기에 변수에 저장할 수 없다.
//f = d; // 문법 오류!
<문자 변수 - 변수의 메모리 크기>
// 자바는 'UCS(Universal Character Set; ISO 10646)'라는 국제 표준 문자 인코딩 규격에 따라 문자를 다룬다.
// UCS-2 라고도 부르며, 각 글자를 0 ~ 65535 까지의 16비트 코드 값으로 저장한다.
// 자바는 UCS-2 코드 값을 저장하기 위해 2바이트 크기의 메모리를 사용한다.
// 다음은 2바이트 크기의 UCS-2 코드 값을 저장할 변수를 선언한다.
char c;
c = 0;
c = 65535;
// char(2byte) 크기의 메모리 범위를 초과하면 문법 오류이다.
//c = -1; // 컴파일 오류 발생!
//c = 65536; // 컴파일 발생!
<문자 변수 - UCS-2 문자 코드 값 저장>
char c1, c2, c3;
// 문자 'A'를 변수에 저장하는 방법?
//- 문자 'A'의 UCS-2 코드 값을 저장하면 된다.
//
c1 = 65; // 문자 'A'의 코드 값을 10진수로 표현한 것.
c2 = 0x41; // 문자 'A'의 코드 값을 16진수로 표현한 것.
c3 = 0b0100_0001; // 문자 'A'의 코드 값을 2진수로 표현한 것.
// println()을 통해 문자를 출력할 수 있다.
//- 변수의 종류가 char 이면 출력할 때 코드 값 대신 문자를 출력한다.
//- 해당 코드의 문자를 폰트 파일에서 찾아 출력한다.
//
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
<문자 변수 - 따옴표('', single quotation) 활용하기>
// 문자 코드 값을 모른다면 따옴표를 사용하라!
// - 문법
// '문자' : UCS-2에 정의된 코드 값을 리턴한다.
//
char c = 'A'; // c 변수에 저장되는 것은 문자 'A'의 UCS-2 코드 값이다.
System.out.println(c);
//문자의 UCS-2 코드 값을 확인하기
//- 정수 변수를 사용하면 문자의 코드 값을 받아서 그래도 출력할 수 있다.
// println()은 int 변수의 값은 10진수로 출력한다.
int i = 'A';
System.out.println(i);
<논리값 변수 - 변수의 메모리 크기>
// 논리 값을 담을 변수는 JVM 내부에서 4바이트 크기의 int 타입 메모리를 사용한다.
boolean b1, b2;
b1 = true; // 실제 메모리에는 1을 저장한다.
b2 = false; // 실제 메모리에는 0을 저장한다.
System.out.println(b1);
System.out.println(b2);
// 주의!
// - JVM 내부에서 true, false를 정수 값으로 다룬다고 해서 boolean 변수에 직접 1과 0을 저장할 수 없다.
//b1 = 1; // 컴파일 오류!
//b2 = 0; // 컴파일 오류!
<레퍼런스 변수>
java.util.Date d1 = new java.util.Date();
java.util.Date d2 = d1;
System.out.printf("%d, %d\n", d1.getDate(), d2.getDate());
d1.setDate(22);
System.out.printf("%d, %d\n", d1.getDate(), d2.getDate());
// d1에 저장된 일자 값을 변경한 후
// d2에 저장된 일자 값을 출력해 보면 d1과 똑같이 변경되어 있다.
// 이유는?
// d1과 d2에 저장되는 것은 값이 아니라 (날짜 정보가 저장되어 있는 메모리의) 주소이다.
// 이렇게 값을 저장하지 않고 값이 저장된 위치(주소)를 저장하는 변수를
// "레퍼런스 (변수)"라 부른다.
// 자바 기본 데이터 타입(byte, short, int, long, float, double, boolean, char)을
// 제외한 모든 타입의 변수는 레퍼런스이다.
'Java' 카테고리의 다른 글
배열, 배열레퍼런스, 배열인스턴스 (0) | 2021.10.28 |
---|---|
변수 (0) | 2021.09.29 |
예외처리 (0) | 2021.09.19 |
오버로딩 (0) | 2021.09.16 |
생성자는 언제 쓰나? (0) | 2021.09.14 |