단 하나의 값을 저장할 수 있는 메모리 공간.
int age; //age라는 이름의 변수를 선언
변수타입: 변수에 저장될 값이 어떤 타입인지를 지정하는 것.
변수이름: 변수에 붙인 이름. 같은 이름의 변수가 여러 개 존재해서는 안됨.
변수의 초기화
변수를 선언한 이후부터는 변수를 사용할 수 있으나, 그 전에 반드시 변수를 초기화 해야 함.
메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 알 수 없는 값이 남아있을 수 있기 때문
int age = 25; // 변수 age를 선언하고 25로 초기화한다.
class VarEx1 {
public static void main(String[] args) {
int year = 0;
int age = 14;
System.out.println(year);
System.out.println(age);
year = age + 2000; // 변수 age의 값에 2000을 더해서 변수 year에 저장
age = age + 1; // 변수 age에 저장된 값을 1증가시킨다.
System.out.println(year);
System.out.println(age);
}
}
두 변수의 값 교환하기
class VarEx2 {
public static void main(String[] args) {
int x = 10;
int y = 20;
int tmp = 0;
System.out.println("x:"+ x + " y:" + y);
tmp = x; // x값을 저장하기 위한 임시 저장소 tmp
x = y;
y = tmp;
System.out.println("x:"+ x + " y:" + y);
}
}
식별자: 변수의 이름처럼 프로그래밍에서 사용하는 모든 이름. 같은 영역 내에서 서로 구분 가능 해야 함.
식별자 만들 때 규칙
1. 대소문자가 구분되며 길이에 제한이 없음.
2. 예약어를 사용해서는 안된다.
예약어: 프로그래밍 언어의 구문에 사용되는 단어.
3. 숫자로 시작해서는 안된다.
4. 특수문자는 ‘_’와 ‘$’만 사용 가능.
권장되는 규칙
1. 클래스 이름의 첫글자는 항상 대문자
변수와 메서드의 이름의 첫 글자는 항상 소문자
2. 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자
lastIndexOf, StringBuffer
3. 상수의 이름은 모두 대문자. 여러 단어로 이루어진 경우 ‘_’로 구분.
PI, MAX_NUMBER
기본형과 참조형
기본형의 종류와 크기
| 1 byte | 2 byte | 3 byte | 8 byte | |
|---|---|---|---|---|
| 논리형 | boolean | |||
| 문자형 | char | |||
| 정수형 | byte | short | int | long |
| 실수형 | float | double |
상수(constant): 값을 저장할 수 있는 공간. 변수와 달리 한 번 값을 저장하면 다른 값으로 변경 불가.
final int MAX_SPEED =10;
상수는 선언과 동시에 초기화해야함.
리터럴
값 자체를 의미
상수가 필요한 이유
리터럴에 의미있는 이름을 붙여 코드의 이해와 수정을 쉽게 만듦.
리터럴의 타입과 접미사
| 종류 | 리터럴 | 접미사 |
|---|---|---|
| 눈리형 | false, true | 없음 |
| 정수형 | 123, 0b0101, 077, 0xFF, 100L | L |
| 실수형 | 3.14, 3.0e8, 1.4f | f, d |
| 문자형 | “A”, “1”, “\n” | 없음 |
| 문자열 | “ABC”, “123”, “abc”, “true” | 없음 |
타입의 불일치
int i = "A" // OK. "A"의 유니코드인 65가 저장 됨
long l = 123 // OK int보다 long의 범위가 더 큼
double d = 3.14f // OK float보다 double의 범위가 더 큼
int i = Ox1234568; // Error. int타입의 범위를 넘는 값 저장
float f = 3.14; // Error. float 타입보다 double 타입의 범위가 넓음
문자 리터럴과 문자열 리터럴
char ch = 'J';
String name = "JAVA";
String str = "";
char ch = ""; //Error ''안에 반드시 하나의 문자가 필요함
char ch = " ";
String name = new String("Java");
String name = "ja" + "va";
String str = name + 8.0;
class StringEx {
public static void main(String[] args) {
String name = "Ja" + "va";
String str = name + 8.0;
System.out.println(name);
System.out.println(str);
System.out.println(7 + " ");
System.out.println(" " + 7);
System.out.println(7 + "");
System.out.println("" + 7);
System.out.println("" + "");
System.out.println(7 + 7 + "");
System.out.println("" + 7 + 7);
}
}
printf(): 지시자를 통해 변수의 값을 여러 가지 형식으로 변환하여 출력.
지시자: 값을 어떻게 출력할 것인지를 지정해주는 역할.
System.out.printf("age:%d", age);
System.out.printf("age:%d", 14);
System.out.printf("age:14");
만약 출력하려는 값이 2개 이상이라면 지시자도 2개 이상 사용
System.out.printf("age: %d, year: %d", age, year);
줄바꿈은 %n을 사용한다
자주 사용하는 printf()의 지시자
| 지시자 | 설명 |
|---|---|
| %b | boolean |
| %d | decimal |
| %o | octal |
| %x, %X | hexa-decimal |
| %f | floating-point |
| %e, %E | exponent |
| %c | character |
| %s | string |
간격 맞게 프린트하는법
System.out.printf("finger = [%5d]", finger); // finger = [ 10]
System.out.printf("finger = [%-5d]", finger); // finger = [10 ]
System.out.printf("finger = [%05d]", finger); // finger = [00010]
import java.util.*; // Scanner를 사용하기 위해 추가
class ScannerEx {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("두자리 정수를 하나 입력해주세요.>");
String input = scanner.nextLine();
int num = Integer.parseInt(input); // 입력받은 문자열을 숫자로 변환
System.out.println("입력내용 :"+input);
System.out.printf("num=%d%n", num);
}
}
컴퓨터는 2진 체계로 설계.
2진법을 알지 못하면 컴퓨터의 동작원리나 데이터 처리방식을 온전히 이해할 수 없음.
비트: 한 자리의 2진수. 컴퓨터가 값을 저장할 수 있는 최소단위
바이트: 1비트 8개를 묶음. 데이터의 기본 단위.
워드: CPU가 한 번에 처리할 수 있는 데이터의 크기. CPU의 성능에 따라 크기는 달라짐.
n비트로 표현할 수 있는 10진수
8진수는 2진수 3자리를, 16진수는 2진수 4자리를 각각 한자리로 표현할 수 있기 때문에 자리수가 짧아져서 알아보기 쉽고 서로 간의 변환방법 또한 매우 간단.
2진수를 8진수, 16진수로 변환
2진수를 뒤에서부터 3, 4자리씩 끊어서 그에 해당하는 8진수 혹은 16진수로 바꾸면 된다.
10진수를 n진수로 변환
해당 진수로 나누고 나머지 값을 옆에 적는 과정을 몫이 해당 진수보다 작아질때까지 반복한다.
마지막 나머지부터 첫번째 나머지까지 순서대로 적는다.
n진수를 10진수로 변환
각 자리의 수에 해당 단위의 값을 곱해서 모두 더하면 됨.
10진 소수를 2진 소수점수로 변환하는 법
1. 10진 소수에 2를 곱한다.
0.625 X 2 = 1.25
2. 위의 결과에서 소수부만 가져다가 다시 2를 곱한다.
0.25 X 2 = 0.5
3. 1과 2의 과정을 소수부가 0이 될 때까지 반복한다.
0.5 X 2 = 1.0
4. 결과에 정수부만을 위에서 아래로 순서대로 적고 ‘0.’을 붙인다.
0.101
2진 소수점수를 10진 소수점수로 변환하는 방법
0.101 = 1 X 0.5 + 0 X 0.25 + 1 X 0.125 = 0.625
| # | 2진수 | 부호있는 10진수 |
|---|---|---|
| 1 | 0000 | 0 |
| 2 | 0001 | 1 |
| 3 | 0010 | 2 |
| 4 | 0011 | 3 |
| 5 | 0100 | 4 |
| 6 | 0101 | 5 |
| 7 | 0110 | 6 |
| 8 | 0111 | 7 |
| 9 | 1000 | -8 |
| 10 | 1001 | -7 |
| 11 | 1010 | -6 |
| 12 | 1011 | -5 |
| 13 | 1100 | -4 |
| 14 | 1101 | -3 |
| 15 | 1110 | -2 |
| 16 | 1111 | -1 |
2의 보수법
n의 보수: 더했을 때 n이 되는 수
음수를 2진수로 표현하기
10진 음의 정수를 2진수로 변환하려면 10진 음의 정수의 절대값을 2진수로 변환한다.
그 다음에 2진수의 2의 보수를 구하면 됨.
음수의 2진 표현을 구하는 방법
1. 음수의 절대값을 2진수로 변환한다.
-5의 절대값인 5를 2진수로 변환한다. (0101)
2. 1에서 구한 2진수의 1을 0으로 0을 1로 바꾼다.
0101 → 1010
3. 2의 결과에 1을 더한다.
1010에 1을 더하면 1011이 되고 이것이 -5의 2진 표현이다.
default: false
크기: 1바이트
TRUE와 true는 다름. true와 false만 가능.
변수에 ‘문자’가 저장되는 것 같지만, 사실은 문자가 아닌 ‘문자의 유니코드’가 저장됨.
특수 문자 다루기
char tab = '\t';
| 특수 문자 | 문자 리터럴 |
|---|---|
| tab | \f |
| backspace | \b |
| form feed | \f |
| new line | \n |
| carriage return | \r |
| 역슬래쉬 | \ |
| 작은 따옴표 | \’ |
| 큰 따옴표 | \” |
| 유니코드 문자 | \u유니코드 |
char타입의 표현방식
char ch = “A”;
short s = 65;
두 개의 2진수는 같음. 하지만 출력해보면 결과가 다름.
변수의 타입이 정수형이면 변수에 저장된 값을 10진수로 해석하여 출력하고, 문자형이면 저장된 숫자에 해당하는 유니코드 문자를 출력하기 때문.
인코딩과 디코딩
문자 인코딩: 문자를 코드로 변환하는 것.
문자 디코딩: 코드를 문자로 변환하는 것.
byte(1) → short(2) → int(4) → long(8)
정수형의 오버플로우
오버플로우: 연산과정에서 해당 타입이 표현할 수 있는 값의 범위를 넘어서는 것.
에러가 발생하는 것은 아님.
부호있는 정수의 오버플로우
부호있는 정수는 부호비트가 0에서 1이 될 때 오버플로우 발생.
실수형의 범위와 정밀도
float, double 두 가지가 있으며 각 타입의 변수에 저장할 수 있는 값의 범위는 아래와 같다.
| 타입 | 저장 가능한 값의 범위 | 정밀도 | 크기(bit) | 크기(byte) |
|---|---|---|---|---|
| float | 1.4 10^-45 ~ 3.4 10^38 | 7자리 | 32 | 4 |
| double | 4.9 10^-324 ~ 1.8 10^308 | 15자리 | 64 | 8 |
연산속도의 향상이나 메모리를 절약하려면 float, 더 큰 값의 범위라던가 더 높은 정밀도를 필요로 한다면 double.
실수형의 저장방식
실수형은 값을 부동소수점수의 형태로 저장.
float: 1(S) + 8(E) + 23(M) = 32 (4 byte)
double = 1 + 11 + 52 = 64 (8 byte)
| 기호 | 의미 | 설명 |
|---|---|---|
| S | 부호(Sign bit) | 0이면 양수, 1이면 음수 |
| E | 지수(Exponent) | 부호있는 정수 지수의 범위는 -127 ~ 128(float), -1023 ~ 1024(double) |
| M | 가수(Mantissa) | 실제값을 저장하는 부분. 10진수로 7자리(float), 15자리(double)의 정밀도로 저장 가능 |
부동소수점의 오차
실수 중에는 무한 소수가 존재하므로, 정수와 달리 실수를 저장할 때 오차 발생 가능.
// float 타입의 값이 실제로 어떻게 저장되는지 확인
class FloatToBinEx {
public static void main(String args[]) {
float f = -9.1234567f;
int i = Float.floatToIntBits(f);
System.out.printf("%f%n", f);
System.out.printf("%X%n", i); // 16진수로 출력
} // main의 끝
}
형변환: 변수 또는 상수의 타입을 다른 타입으로 변환하는 것.
(타입)피연산자
double d = 85.4;
int score = (int) d; // int score = 85;
형변환 연산자는 그저 피연산자의 값을 읽어서 지정된 타입으로 형변환하고 그 결과를 반환 → 피연산자인 변수 d의 값은 형변환 후에도 아무런 변화가 없음.
기본형에서 boolean을 제외한 나머지 타입들은 서로 형변환이 가능.
| 변환 | 수식 | 결과 |
|---|---|---|
| int → char | (char)65 | “A” |
| char → int | (int)”A” | 65 |
| float → int | (int)1.6f | 1 |
| int → float | (float)10 | 10.0f |
큰 타입에서 작은 타입으로의 변환에서, 경우에 따라 ‘값 손실’이 일어날 수 있다.
class CastingEx2 {
public static void main(String[] args) {
int i = 10;
byte b = (byte)i;
System.out.printf("[int -> byte] i=%d -> b=%d%n", i, b);
i = 300;
b = (byte)i;
System.out.printf("[int -> byte] i=%d -> b=%d%n", i, b);
b = 10;
i = (int)b;
System.out.printf("[byte -> int] b=%d -> i=%d%n", b, i);
b = -2;
i = (int)b;
System.out.printf("[byte -> int] b=%d -> i=%d%n", b, i);
System.out.println("i="+Integer.toBinaryString(i));
}
}
/* [int -> byte] i=10 -> b=10
[int -> byte] i=300 -> b=44
[byte -> int] b=10 -> i=10
[byte -> int] b=-2 -> i=-2
i=11111111111111111111111111111110 */
작은 타입에서 큰 타입으로 변환하는 경우, 빈 공간을 0으로 채운다.
float 타입의 범위를 넘는 값을 float으로 형변환하는 경우 +- 무한대 또는 +-0을 결과로 얻는다.
class CastingEx3 {
public static void main(String[] args) {
float f = 9.1234567f;
double d = 9.1234567;
double d2 = (double)f;
System.out.printf("f =%20.18f\n", f);
System.out.printf("d =%20.18f\n", d);
System.out.printf("d2=%20.18f\n", d2);
}
}
/* f =9.123456954956055000
d =9.123456700000000000
d2=9.123456954956055000 */
정수형을 실수형으로 변환
정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장형식으로 저장.
실수형의 정밀도 제한으로 인한 오차가 발생 가능.
10진수로 8자리 이상의 값을 실수형으로 변환할 때는 float가 아닌 double로 형변환해야 오차가 발생하지 않음.
실수형을 정수형으로 변환
실수형의 소수점 이하 값은 버려짐.
실수의 소수점을 버리고 남은 정수가 정수형의 저장범위를 넘는 경우에는 정수의 오버플로우가 발생한 결과를 얻음.
class CastingEx4 {
public static void main(String[] args) {
int i = 91234567; // 8자리의 10진수
float f = (float)i; // int를 float로 형변환
int i2 = (int)f; // float를 다시 int로 형변환
double d = (double)i; // int를 double로 형변환
int i3 = (int)d; // double을 다시 int로 형변환
float f2 = 1.666f;
int i4 = (int)f2;
System.out.printf("i=%d\n", i);
System.out.printf("f=%f i2=%d\n", f, i2);
System.out.printf("d=%f i3=%d\n", d, i3);
System.out.printf("(int)%f=%d\n", f2, i4);
}
}
/* i=91234567
f=91234568.000000 i2=91234568
d=91234567.000000 i3=91234567
(int)1.666000=1 */
서로 다른 타입간의 대입이나 연산을 할 때, 형변환으로 타입을 일치시키는 것이 원칙.
경우에 따라 편의상의 이유로 형변환 생략 가능.
컴파일러가 생략된 형변환을 자동적으로 추가.
서로 다른 두 타입간의 덧셈에서는 두 타입 중 표현 범위가 더 넓은 타입으로 형변환하여 타입을 일치시킨 다음 연산 수행.
산술변환: 연산과정에서 자동적으로 발생하는 형변환.
자동 형변환의 규칙
기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환.
기본형의 자동 형변환이 가능한 방향