#1 교육정리
오늘은 변수에 대해서 심층적으로 교육받았으며, 아래와 같이 정리해보겠습니다.
1) 변수란
#2 변수란?
변수는 값을 저장하는 메모리 입니다.또한 말 그대로 변하는 수입니다.
변수 선언)
- 값을 저장하는 메모리를 준비하는 명령입니다.
- 값을 저장할 메모리의 종류와 크기를 결정하고 그 메모리에 이름을 부여해야 합니다.(자료형)
- 변수를 선언하고 그 이름을 사용하여 메모리에 접근하고 값을 넣고 꺼냅니다.
- 문법 : 메모리의 종류 메모리의이름; -> ex) int a;
변수 선언 문법)
public class Exam0110 {
public static void main(String[] args) {
// 변수 선언 문법
// - 데이터타입 변수
//
int i;
// 문법
// - int : 값을 저장할 메모리의 종류. '데이터 타입(data type; 자료형)'이라 부른다.
// - i : 메모리를 가리키는 이름. '변수(variables)'라 부른다.
//
// 의미
// - 정수 값을 담을 메모리를 준비하고 그 메모리의 이름을 i 라고 하자!
}
}
변수의 이름)
- 보통 소문사로 시작합니다.
- 대소문자를 구분합니다.
- 여러 단어로 구성된 경우 두번째 단어의 시작 알파벳은 대문자로 합니다. ex) firstName, createDate, userId
- 상수인 경우 보통 모두 대문자로 이름을 짓습니다. 단어와 단어 사이는 _를 사용합니다. ex) USER_TYPE, USER_MANAGER
#3 변수선언 문법과 선언 오류
변수 선언 문법2)
한 문장에서 여러 개의 변수를 선언할 수 있습니다.
한 문장으로같은 유형의 변수를 여러개 선언할 수 있습니다.
문법 : 데이터타입 변수1, 변수2, 변수3;
public class Exam0120 {
public static void main(String[] args) {
// 한 번에 한 개씩 변수를 선언할 수 있고,
int i1;
int i2;
int i3;
// 콤마(,)를 사용하여 여러 개의 변수를 한 번에 선언할 수 있다.
int j1, j2, j3;
}
}
변수 선언 문법3 - 변수에 값 할당)
변수가 가리키는 메모리에 값을 저장하는 것
문법 : 변수명 = 변수 또는 리터럴;
용어 :
= : 할당 연산자(assignment operator)
L-value : 왼쪽에 있는 변수를 가리키며, L-value는 리터럴이 될 수 없습니다.
R-value : 오른쪽에 있는 변수나 리터럴을 가리킵니다.
의미 : 오른쪽에 지정된 값을 왼쪽 변수가 가리키는 메모리에 저
변수 선언 문법4 - 동시에 변수선언과 값 할당하기)
변수와 동시에 값을 즉시 저장할 수 있습니다.
문법 : 데이터타입 변수명 = 값;
public class Exam0140 {
public static void main(String[] args) {
//변수 선언 + 값 저장
//- 이렇게 변수 선언과 값 저장을 한 번에 하는 것을 '변수 초기화 문장'이라 부른다.
int age = 20;
}
}
여러개의 변수를 한번에 선언하고 초기화도 함께 수행하기도 가능합니다.
public class Exam0150 {
public static void main(String[] args) {
//여러 개의 변수를 선언할 때도 한 개를 선언할 때와 마찬가지로 값을 저장할 수 있다.
int a1 = 100, a2 = 200;
}
}
public class Exam0160 {
public static void main(String[] args) {
//모든 변수를 다 초기화시킬 필요는 없다.
int a1, a2 = 200, a3, a4 = 400, a5;
}
}
할당 연산자를 이용하면 언제든 해당 메모리에 다른 값으 저장할 수 있습니다.
//# 변수의 값 변경
//
public class Exam0170 {
public static void main(String[] args) {
int age;
age = 20;
age = 30;
}
}
변수 선언 문법5 - 블록 안에서 변수 선언 위치)
public class Exam0210 {
public static void main(String[] args) {
//사용할 변수를 블록({}) 시작 부분에 미리 선언해 놓아도 된다.
int age;
int weight;
int height;
age = 20;
weight = 100;
height = 200;
//변수가 필요할 때 블록({}) 중간 부분에 언제든 선언할 수 있다.
int score;
score = 100;
System.out.println(age);
System.out.println(weight);
System.out.println(height);
System.out.println(score);
}
}
20
100
200
100
변수 선언 오류1)
public class Exam0220 {
public static void main(String[] args) {
//변수 선언 보다 변수 사용이 먼저 올 수 없다.
count = 50; // -> 문법 오류!
int count;
//항상 변수가 선언된 다음에 사용해야 한다.
count = 50; // -> 옳다!
System.out.println(count);
}
}
변수 선언 오류2)
public class Exam0230 {
public static void main(String[] args) {
int age;
//같은 블록 안에서 같은 이름의 변수를 중복해서 선언할 수 없다.
int age; // -> 문법 오류!
System.out.println(age);
}
}
#4 변수사용과 사용 오류
변수 사용1)
다른 도구(메서드 함수라고도 부른다)에 값을 전달 할 수 있습니다.
public class Exam0310 {
public static void main(String[] args) {
int age = 20;
//println() 메서드(도구)
//- 콘솔(console)로 값을 출력할 때 사용하는 도구이다.
//- 즉 JVM의 표준 출력 장치로 값을 출력한다.
//- 사용법
// System.out.println(리터럴 또는 변수, 결과가 생성되는 명령문)
//
System.out.println(age);
// println()을 실행할 때 age 변수를 넘기는 것이 아니라
// age 변수에 들어있는 값을 넘기는 것이다!!!!
}
}
20
변수 사용2)
다른 변수에 값을 저장할 때 사용할 수 있습니다.
public class Exam0320 {
public static void main(String[] args) {
int age1 = 20;
//r-value 자리에 변수를 놓을 수 있다.
int age2 = age1;
//의미
//- age1에 저장된 값을 age2에 복사하라!
//age1과 age2는 같은 메모리가 아니다.
//증명
//- age1의 값을 변경한다.
age1 = 30;
System.out.println(age1);
System.out.println(age2);
}
}
30
20
변수 사용 오류1)
변수에 값을 저장하지 않은 상태에서 변수를 사용할 수 없다.
public class Exam0330 {
public static void main(String[] args) {
int age;
//값이 저장되지 않은 변수를 사용하면 문법 오류이다.
System.out.println(age);
}
}
변수 사용 오류2)
public class Exam0340 {
public static void main(String[] args) {
int age1;
//값이 저장되지 않은 변수를 사용하면 문법 오류이다!
int age2 = age1;
}
}
#5 변수의 종류
자바 원시(기본) 타입의 값을 저장하는 변수와 메모리 주소를 저장하는 변수가 있습니다.
자바 원시 타입 변수(primitive variable)
-> 정수, 부동소수점, 논리, 문자코드의 값
레퍼런스 변수(reference variable)
-> 자바 원시 타입의 값을 제외한 모든 값
public class Exam0400 {
public static void main(String[] args) {
//자바 원시 데이터 타입 변수
//- 정수
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 : 날짜 값이 저장된 메모리의 주소를 저장한다.
프로그래밍 입문 단계에서는 그냥 날짜를 저장하는 메모리로 생각하라!
#6 정수 변수
변수의 메모리 크기)
public class Exam0411 {
public static void main(String[] args) {
// 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
}
}
변수와 리터럴의 크기)
public class Exam0412 {
public static void main(String[] args) {
//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 = 32767L;
// int i = 100L;
}
}
크기가 다른 변수끼리 값 할당)
public class Exam0413 {
public static void main(String[] args) {
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)
}
}
#7 부동소수점 변수
변수의 메모리 크기)
4바이트 부동소수점 변수
public class Exam0421 {
public static void main(String[] args) {
// 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);
}
}
9.876545
987654.5
9.876545E-6
9.876546
9876546.0
8바이트 부동소수점 변수
public class Exam0422 {
public static void main(String[] args) {
// 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자리를 넘어가면 정상적으로 값을 저장되지 않을 수 있다.
//- 리터럴 값이 이미 유효자릿수를 넘어간다.
//- 변수에 저장하기 전에 리터럴 값이 이미 반올림 되거나 잘린다.
//- IEEE754 표준을 따르며 근사치로 표현됩니다.
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)'이라 한다.
//
}
}
9.99999999988888
9999999.88888888
9.99999999988888E13
9.99999999988888E-6
9.999999999999996
9.999999999999998E14
변수와 리터럴의 크기1)
public class Exam0423 {
public static void main(String[] args) {
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바이트 부동소수점을 저장하라!
}
}
9999.888
9.99999998888888E7
변수와 리터럴의 크기2)
public class Exam0424 {
public static void main(String[] args) {
double d;
// 주의!
// - 잘못된 리터럴 값을 변수에 저장해봐야 소용없다!
d = 99999.8888877777f;
System.out.println(d);
// 4바이트 크기를 넘어가는 부동소수점 리터럴은 이미 짤린 값이기 때문에 제대로 저장될 수 없다.
d = 99999.8888877777; // 리터럴 값도 정상. 변수에 저장하는 것도 정상
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);
}
}
99999.890625
99999.8888877777
99999.88
99999.8888877777
99999.8828125
변수와 리터럴의 크기3)
public class Exam0425 {
public static void main(String[] args) {
float f1 = 99988.88f;
float f2 = 11.11111f;
// 각 변수의 값이 개별적으로 옳은 부동소수점이라도,
System.out.println(f1);
System.out.println(f2);
// 주의!
// 연산 결과가 해당 타입의 크기를 벗어 난다면 그 결과 값이 짤린다.
// 99988.88
// + 11.11111
// -----------------
// 99999.99111 <== 계산 결과가 4바이트 유효자릿수를 넘어간다.
// 계산 결과는 유효자릿수 범위 내에서 반올림되거나 잘린다.
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);
}
}
// 부동소수점 사용법
// - 유효자릿수 7자리 이하의 값을 단순이 저장하고 꺼내는 경우 float 타입을 사용하라!
// 예) float height;
// float weight;
// - 부동소수점에 대해 연산을 수행하는 경우 double 타입을 사용하라!
// 예) double average;
// double area;
99988.88
11.11111
99999.99
99999.99111
크기가 다른 변수끼리 값 할당)
public class Exam0426 {
public static void main(String[] args) {
float f;
double d;
d = 3.14;
// 값의 유효 여부에 상관없이 메모리 크기가 큰 변수의 값을 작은 크기에 변수에 저장할 수 없다.
//f = d; // 문법 오류!
}
}
#8 문자 변수
변수의 메모리 크기)
public class Exam0431 {
public static void main(String[] args) {
// 자바는 '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 문자 코드 값 저장)
public class Exam0432 {
public static void main(String[] args) {
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);
}
}
A
A
A
따옴표(' ', single quotation) 활용하기)
public class Exam0433 {
public static void main(String[] args) {
// 문자 코드 값을 모른다면 따옴표를 사용하라!
// - 문법
// '문자' : 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);
}
}
A
65
UCS-2 코드 확인하기)
public class Exam0434 {
public static void main(String[] args) {
// 자바는 문자를 저장할 때 UCS-2에 정의된 정수 값을 저장한다.
// 확인해 보자!
// 영어 대문자의 문자 코드 저장
int v = 0x41; // 65(10진수)
// 코드 값을 1씩 증가하면서 문자를 출력해 보자!
for (int i = 0; i < 26; i++) {
// 정수를 그냥 출력하면 10진수를 출력한다.
// 정수가 문자 코드임을 알려줘야만 println()은 해당 코드의 문자를 출력한다.
// 문법
// (char) 정수
//System.out.print(v + i);
System.out.print((char)(v + i));
System.out.print(' ');
}
}
}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#8 논리값 변수
논리 값을 저장하는데 사용되는 변수이며, 주로 조건문의 겨롸르 저장하거나 제어 흐름을 결정하는데 사용됩니다.
논리형에는 'boolean' 한 가지밖에 없으며, true와 false 중 하나를 저장할 수 있다. 기본값(default)은 false 입니다.
boolean형 변수는 대답(yes/no), 스위치(on/off) 등의 논리 구현에 주로 사용됩니다.
boolean형은 true와 false, 두 가지의 값만 표현하면 되므로 1bit로 충분하지만 자바에서는 데이터를 다루는 최소 단위가 byte이기 때문에 boolean의 크기는 1byte입니다.
논리 연산자(AND, OR, NOT 등)와 함께 사용하여 복잡한 조건식을 만들 수도 있습니다.
변수의 메모리 크기)
public class Exam0441 {
public static void main(String[] args) {
// 논리 값을 담을 변수는 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; // 컴파일 오류!
}
}
true
false
#9 레퍼런스 변수(references Type)
객체를 가리키는 변수이며, 객체는 클래스의 인스턴스입니다.
기본형 변수는 값을 직접 저장하나, 레퍼런스 변수는 객체의 위치를 가리킵니다.
레퍼런스변수는 객체의 타입과 일치하는 클래스 또는 인터페이스로 선언됩니다.
객체에 대한 참조를 저장하므로, 객체를 여러 개의 레퍼런스 변수에 할당 할 수도 있습니다. 이는 동일한 객체에 대한 여러 가지 작업을 수행하거나 객체를 전달하고 공유하는 데 유용합니다.
public class Exam0451 {
public static void main(String[] args) {
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)을
// 제외한 모든 타입의 변수는 레퍼런스이다.
}
}
27, 27
22, 22
아래에서 변수의 종류에 대해서 좀 더 자세하게 알아보겠습니다.
public class Exam0710 {
int a; // 인스턴스 변수
static int b; // 클래스 변수 == 스태틱 변수
public static void main(String[] args/*로컬변수=파라미터*/) {
int c; // 로컬 변수
}
}
// 인스턴스 변수(instance variable)
// - new 명령을 사용하여 인스턴스를 생성할 때 준비되는 변수
//
// 클래스 변수(class variable = static variable)
// - 클래스가 로딩될 때 준비되는 변수
//
// 로컬 변수(local variable)
// - 블록을 실행할 때 준비되는 변수
//
// 파라미터(parameter)
// - 메서드의 아규먼트를 받는 로컬 변수이다.
// 예) 위의 코드에서 main()의 args 로컬 변수
//
아래는 종류에 따른 변수의 사용 범위 입니다.
class MyClass {
int a = 11; // 인스턴스 변수
static int b = 22; // 클래스 변수
static void m1(int v1/*로컬변수=파라미터*/) {
int v2; // 로컬 변수
v2 = 200;
System.out.println(v1);
System.out.println(v2);
}
}
public class Exam0720 {
public static void main(String[] args) {
//1) 인스턴스 변수를 사용하는 방법
MyClass obj1 = new MyClass(); // new 명령이 실행될 때 변수가 준비된다.
System.out.println(obj1.a); // 인스턴스를 가리키는 레퍼런스를 통해 변수를 사용할 수 있다.
//2) 클래스 변수를 사용하는 방법
System.out.println(MyClass.b); // 클래스를 사용(로딩)하는 시점에 준비된다.
//3) 로컬 변수를 사용하는 방법
MyClass.m1(100); // 메서드를 실행할 때 변수가 준비된다. 메서드를 실행하는 동안만
// 메서드 호출이 끝나면, 그 메서드의 로컬 변수를 사용할 방법이 없다.
// v1 = 300; // 오류!
// 메서드를 실행하는 동안, 그 메서드 안에서만 사용할 수 있다.
}
}
11 = 'System.out.println(obj1.a);'
22 = 'System.out.println(MyClass.b);'
100 = 'System.out.println(v1);'
200 = 'System.out.println(v2);'
- 인스턴스 변수:
- int a = 11;은 MyClass 클래스의 인스턴스 변수로 선언됩니다.
- MyClass obj1 = new MyClass();를 통해 MyClass의 인스턴스를 생성하고, obj1이라는 레퍼런스 변수에 할당합니다.
- obj1.a를 통해 인스턴스 변수 a에 접근하여 값을 출력할 수 있습니다.
- 클래스 변수:
- static int b = 22;는 MyClass 클래스의 클래스 변수로 선언됩니다.
- MyClass.b를 통해 MyClass의 클래스 변수 b에 접근하여 값을 출력할 수 있습니다.
- 클래스를 사용(로딩)하는 시점에 클래스 변수가 준비되어 사용할 수 있습니다.
- 로컬 변수:
- static void m1(int v1) { ... }은 MyClass 클래스의 정적 메서드인 m1입니다.
- m1 메서드의 인자로 전달된 v1은 메서드 내에서 로컬 변수로 사용됩니다.
- int v2;는 m1 메서드 내에서 선언된 로컬 변수입니다.
- v1과 v2를 System.out.println()을 통해 출력할 수 있습니다.
- 로컬 변수는 메서드를 실행할 때 변수가 준비되고, 메서드의 실행이 끝나면 해당 변수를 사용할 수 없습니다.
따라서 위의 코드에서는 인스턴스 변수, 클래스 변수, 그리고 로컬 변수를 각각 다른 방식으로 사용하는 것을 확인할 수 있습니다.
이번에는 같은 블록에서는 중복 선언이 불가한 것을 보여드리겠습니다.
public class Exam0810 {
int a; // 인스턴스 변수
static int b; // 클래스 변수
// 클래스 블록 안에 선언된 변수는 종류에 상관없이 중복 선언 불가!
// int a; // 컴파일 오류!
// static int a; // 컴파일 오류!
// int b; // 컴파일 오류!
// static int b; // 컴파일 오류!
public static void main(String[] args/*로컬변수=파라미터*/) {
// 그러나 메서스 블록에서는 클래스에 선언된 변수의 이름과
// 같은 변수를 선언할 수 있다.
// 왜? 영역이 다르니까!
int a;
int b;
// 마찬가지로 이 블록 안에서는 같은 이름의 변수를 만들 수 없다.
// String a; // 컴파일 오류! 데이터 타입에 상관없이 이름 중복 불가!
}
public static void m2() {
// 여기에 선언된 변수는 main() 블록에 선언된 변수와 다른 변수이다.
int a;
int b;
}
}
로컬 변수와 블록1)
public class Exam0820 {
public static void main(String[] args) {
int a = 100;
{
// int a = 200; // 컴파일 오류!
// 메서드 안에서는 변수 이름 중복 불가!
// 안쪽 블록에서는 바깥 블록의 변수를 사용할 수 있다.
a = 200;
int b = 300;
// 이 블록의 실행을 끝내는 순간
// 이 블록에서 선언된 모든 변수는 제거된다.
// 그래서 b 변수는 제거된다.
}
System.out.println(a);
// 바깥 블록에서는 안쪽 블록의 변수를 사용할 수 없다.
// 왜?
// 안쪽 블록의 실행이 끝나면, 안쪽 블록에서 선언된 모든 변수들이
// 자동으로 제거된다.
// System.out.println(b); // 컴파일 오류!
{
// 이전 블록에서 선언된 변수는 그 블록이 종료되는 순간
// 제거되기 때문에,
// 다음과 같이 같은 이름의 변수를 선언할 수 있다.
int b = 400;
}
}
}
200
로컬 변수와 블록2)
public class Exam0821 {
public static void main(String[] args) {
int a = 100;
for (int i = 0; i < 10; i++) {
// 바깥 블록에 선언된 변수와 같은 이름으로 변수를 만들 수 없다.
// int a; // 컴파일 오류!
int b; // OK!
System.out.println(i); // for문 실행
}
System.out.println(a); // 출력 값 : 100
// 블록 안에 선언된 변수는 블록 실행을 마치면 제거된다.
// 따라서 사용할 수 없다.
// System.out.println(i); // 컴파일 오류!
// System.out.println(b); // 컴파일 오류!
}
}
0
1
2
3
4
5
6
7
8
9
100
로컬 변수와 블록3)
public class Exam0822 {
public static void main(String[] args) {
int a = 100;
switch (a) {
case 1:
//switch 바깥 블록에 같은 이름의 변수가 있다.
// int a; //컴파일 오류!
// case 문에서 선언한 변수는 switch 문에 소속된다.
int b;
{
// 다음과 명확하게 블록 안에 선언하면
// 이 블록의 변수가 된다.
int c;
}
break;
case 2:
// case는 다른 블록으로 취급되지 않는다.
// 위쪽 case에서 선언한 변수는 switch 문에 소속된다.
// 따라서 다음과 같이 아래쪽 case에서
// 같은 이름의 변수를 선언할 수 없다.
// int b; // 컴파일 오류!
int c; // OK!
break;
case 3:
for (int i = 0; i < 100; i++) {
// for의 바깥 블럭인 switch 문에 이미 b 변수가 있다.
// int b; // 컴파일 오류!
}
break;
default:
}
}
}
#10 값 저장과 메모리 크기
작은 크기의 메모리 값을 큰 크기의 메모리에 저장할 수 있습니다.
public class Exam0910 {
public static void main(String[] args) {
byte b = 100; // 1byte
short v1 = b; // 1byte ==> 2byte
short s = 100; // 2byte(-32768 ~ 32767)
int v2 = s; // 2byte ==> 4byte
int i = 98765678; // 4byte
long v3 = i; // 4byte ==> 8byte
long l = 98765678; // 4byte 리터럴 ==> 8byte
char c = 100; // 2byte(0 ~ 65535)
// short x1 = c; // char(0 ~ 65535) ==> short(-32768 ~ 32767), 값의 범위가 맞지 않아 컴파일 오류!
}
}
정수는 부동소수점 메모리에 저장할 수 있습니다.
주의할 점은 부동소수점 메모리의 유효자릿수를 넘어가는 정수를 정할 경우 값이 짤리게 됩니다. 그럼에도 커마일 오류가 발생하지 않습니다.
public class Exam0911 {
public static void main(String[] args) {
byte b = 100; // 1byte
short s = 32767; // 2byte(-32768 ~ 32767)
int i = 98765678; // 4byte(약 -21억 ~ +21억)
long l = 18_2345_3456_4567_5678L; // 8byte(약 -922경 ~ 922경)
float f; // 4byte
double d; // 8byte
// 주의!
// - float의 자릿수가 넘어가는 정수를 저장하는 경우 값이 짤릴 수 있다.
// - 그럼에도 불구하고 컴파일 오류가 발생하지 않는다.
// - 그래서 정수 값을 부동소수점 메모리에 저장할 때 특히 주의해야 한다.
f = b; // byte(1) ==> float(4). 값을 그대로 저장.
System.out.println(f);
f = s; // short(2) ==> float(4). 값을 그대로 저장.
System.out.println(f);
f = i; // int(4) ==> float(4).
// 유효자릿수를 넘는 정수는 짤린다.
System.out.println(f);
f = l; // long(8) ==> float(4)
// 유효자릿수를 넘는 정수는 짤린다.
System.out.println(f);
d = i; // int(4) ==> double(8)
// 유효자릿수 범위의 정수 값이므로 int(32비트) 값을 그대로 저장할 수 있다.
System.out.println(d);
d = l;
// 유효 범위를 넘어가는 정수인 경우 짤린다.
// 주의! 컴파일 오류가 발생하지 않는다.
System.out.println(d);
}
}
// 정리!
// - 정수 메모리의 값(byte, short, char, int, long)을
// 부동소수점 메모리(float, double)에 저장할 때
// 주의해서 사용하라!
// - 유효자릿수를 넘어가는 정수 값인 경우 부동소수점 메모리에 저장될 때 짤릴 수 있다.
// 그럼에도 컴파일 오류가 발생하지 않기 때문에
// 개발자들이 놓치는 경우가 많다!
#11 형변환
정수 변수 => 부동소수점 변수)
정수 변수의 값을 부동소수점 변수에 저장할 때 값이 짤릴 수 있습니다.
public class Exam0920 {
public static void main(String[] args) {
byte b = 100; // 1byte
short s = 100; // 2byte
int i = 98765678; // 4byte
long l = 98765678; // 8byte
char c = 100; // 2byte
float f; // 4byte
double d; // 8byte
//
f = b; // byte(1) ==> float(4). 값을 그대로 저장.
System.out.println(f);
f = s; // short(2) ==> float(4). 값을 그대로 저장.
System.out.println(f);
f = c; // char(2) ==> float(4). 값을 그대로 저장.
System.out.println(f);
f = i; // int(4) ==> float(4).
// 유효자릿수를 넘는 정수는 짤린다.
// 주의! 컴파일 오류가 발생하지 않는다.
System.out.println(f);
f = l; // long(8) ==> float(4)
// 유효자릿수를 넘는 정수는 짤린다.
// 주의! 컴파일 오류가 발생하지 않는다.
System.out.println(f);
d = i; // int(4) ==> double(8)
// 유효자릿수 범위의 정수 값이므로 int(32비트) 값을 그대로 저장할 수 있다.
System.out.println(d);
l = 18_2345_3456_4567_5678L;
d = l;
// 유효 범위를 넘어가는 정수인 경우 짤린다.
// 주의! 컴파일 오류가 발생하지 않는다.
System.out.println(d);
}
}
100.0
100.0
100.0
9.876568E7
9.876568E7
9.8765678E7
1.8234534564567568E17
부동소수점 변수 => 정수 변수)
public class Exam0921 {
public static void main(String[] args) {
float f = 3.14f;
double d = 9876.56789;
// 부동소수점 메모리의 값을 정수 메모리에 저장할 수 없다.
// 왜?
// - 정수 메모리는 소수점 이하의 값을 저장할 수 없기 때문에
// 자바에서는 부동소수점 값을 정수 메모리에 저장하는 것을
// 문법에서 막는다!
// int i = f; // 컴파일 오류!
// long l = d; // 컴파일 오류!
}
}
명시적 형변환)
컴파일러에세 강제로 값을 넣도록 명령하는 것
큰메모리의 값을 작은 메모리로 변환 할 때
부동소수점을 정수로 변환 할 때
문법 : 변수 = (바꾸고자하는타입) 변수 또는 값;
public class Exam0930 {
public static void main(String[] args) {
// 부동소수점 메모리의 값은 정수 메모리에 저장할 수 없다.
// 그럼에도 저장하려 한다면, 명시적 형변환 문법을 사용해야 한다.
//
// 명시적 형변환을 통해 부동소수점의 값을 정수 메모리에 저장할 때
// 소수점 이하의 값이 짤린다.
//
// float ==> int
float f = 3.14f;
int i = (int)f; // 소수점 이하가 제거된다.
System.out.println(i);
// double ==> long
double d = 9876.56789;
long l = (long)d; // 소수점 이하가 제거된다.
System.out.println(l);
}
}
3
9876
명시적 형변환2)
큰 정수 변수의 값을 작은 정수 변수에 저
큰 값을 작은 메모리에 넣는 것은 아무런 의미가 없습니다. 해서도 안됩니다.
다만, 큰 메모리의 값을 바이트 단위로 쪼개고 싶을 때 유용합니다.
public class Exam0940 {
public static void main(String[] args) {
byte b = 100; // 1byte
short s = 100; // 2byte
int i = 100; // 4byte
long l = 100; // 8byte
// 큰 메모리의 정수 값을 작은 메모리에 저장하는 경우
// => 컴파일 오류가 발생한다.
// => 해결책? 명시적 형변환을 해야 한다.
// 1) 큰 메모리의 값이 작은 메모리에 충분히 들어가는 경우
// short ==> byte
byte b2 = (byte)s; // 명시적 형변환
System.out.println(b2);
// int ==> byte
b2 = (byte)i; // 명시적 형변환
System.out.println(b2);
// long ==> byte
b2 = (byte)l; // 명시적 형변환
System.out.println(b2);
// 2) 큰 메모리의 값이 작은 메모리에 들어 갈 수 없는 경우
// => 앞 쪽 바이트의 값이 짤려서 들어간다.
int i2 = 0b0000_0000_0000_0000_0000_0001_0010_1100; // = 300(10진수)
b2 = (byte) i2; //
System.out.println(b2); // 0b0010_1100
l = 400_0000_0000L; // 0x00_00_00_09_50_2f_90_00
i = (int)l; // 큰 메모리의 값이 작은 메모리에 들어가지 못하는 경우
System.out.println(l); // 앞 쪽 바이트가 짤린다.
System.out.println(i);
System.out.println(0x502f9000);
}
}
100
100
100
44
40000000000
1345294336
1345294336
명시적 형변환이 불가능한 경우)
public class Exam0950 {
public static void main(String[] args) {
// 1) 정수 메모리끼리 형변환이 가능하다.
// 2) 부동소수점을 정수로 형변환이 가능한다.
// 3) 형변환 없이 정수는 부동소수점 메모리에 저장할 수 있다.
// 4) 숫자를 문자 코드로 형변환 가능한다.
// 그 외에는 형변환 불가!
// 예) 정수, 부동소수점 ==/==> boolean
boolean bool;
// bool = (boolean) 1; // 컴파일 오류!
// 예) 문자열 ==/==> 정수, 부동소수점, 문자, boolean
// boolean v1 = (boolean) "true"; // 컴파일 오류!
// char v2 = (char) "가"; // 컴파일 오류!
// int v3 = (int) "123"; // 컴파일 오류!
// float v4 = (int) "3.14f"; // 컴파일 오류!
}
}
명시적 형변환이 불가능한 경우, 특별한 메서드를 사용하면 가능합니다.
그 경우는 아래와 같습니다.
public class Exam0951 {
public static void main(String[] args) {
byte b = Byte.valueOf("100");
short s = Short.valueOf("32767");
int i1 = Integer.valueOf("2122223333"); // 문자열 ==> int
int i2 = Integer.parseInt("2122223333"); // 문자열 ==> int
long l = Long.valueOf("9221111222233334444");
float f1 = Float.valueOf("3.14f");
float f2 = Float.parseFloat("3.14f");
double d = Double.valueOf("9876.54321");
boolean bool1 = Boolean.valueOf("TRUE"); // 문자열 ==> boolean
boolean bool2 = Boolean.parseBoolean("TRUE"); // 문자열 ==> boolean
char c = "가나다".charAt(1); // => 나
System.out.println(b);
System.out.println(s);
System.out.println(i1);
System.out.println(i2);
System.out.println(l);
System.out.println(f1);
System.out.println(f2);
System.out.println(d);
System.out.println(bool1);
System.out.println(bool2);
System.out.println(c);
}
}
'[Naver Cloud Camp 7] 교육 정리' 카테고리의 다른 글
네이버 클라우드 캠프 26일차 230531 (0) | 2023.05.31 |
---|---|
네이버 클라우드 캠프 25일차 230530 (0) | 2023.05.30 |
네이버 클라우드 캠프 23일차 230525 (0) | 2023.05.25 |
네이버 클라우드 캠프 22일차 230524 (4) | 2023.05.24 |
네이버 클라우드 캠프 21일차 230523 (0) | 2023.05.23 |