일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- sorting
- database
- dynamic programming
- string
- Math
- java
- SQL
- Stack
- geometry
- Data Structure
- 파이썬
- 코딩테스트
- simulation
- bit manipulation
- Counting
- implement
- two pointers
- Matrix
- Tree
- hash table
- 코테
- Method
- array
- Class
- Binary Search
- Number Theory
- Binary Tree
- greedy
- 구현
- 자바
- Today
- Total
코린이의 소소한 공부노트
형변환(type casting) 본문
형변환이란 값의 타입을 다른 타입으로 바꾸는 것을 말한다. 기본형 8가지 중 논리형(boolean)을 제외한 나머지 기본형은 서로 형변환이 가능하다. 왜냐면 논리형을 뺀 정수형, 실수형, 문자형은 모두 숫자 리터럴을 이용할 수 있기 때문이다. 여기서 문자형이 숫자 리터럴을 쓸 수 있는 건 이것 때문이다.
이것은 자바가 사용하는 유니코드의 일부분이다. char 타입은 문자를 그대로 저장하는 것이 아니고, 문자에 해당하는 숫자코드를 저장한다. 그래서 숫자형과 형변환이 가능하다.
형변환을 하는 방법은 간단하다. 변수나 리터럴 앞에 (바꾸고 싶은 타입)만 붙여주면 된다.
// int를 float으로 형변환하기
int i = 3;
float f = (float)i; // 3.0
기본적으로, 사용자가 형변환을 하지 않아도 컴파일러가 자동변환을 해주는 경우가 있다.
1. 같은 숫자형, 좌변의 범위 > 우변의 범위
// double > int
int i = 4;
double d = i; // double d = (double)i; 와 같음
System.out.println(d); // 4.0
// int > byte
byte b = 2;
i = b; // i = (int)b; 와 같음
System.out.println(i); // 2
그래서 사실 맨 위에 있는 int를 float으로 형변환하는 예시에서도 형변환 연산자는 필요 없다.
2. int에 char 변수 또는 문자 리터럴 대입
// 'A'의 코드는 65
char c = 'A';
int i1 = c;
System.out.println(i1); // 65
int i2 = 'A';
System.out.println(i2); // 65
char 타입의 변수 c에 'A'를 저장하면 실제로는 65가 저장된다. 그래서 i1에 c를 대입하면 똑같이 65가 저장된다.
i2에 직접 'A'를 대입해도 똑같이 65로 저장된다.
3. char에 정수 리터럴 대입
char c = 65;
System.out.println(c); // 'A'
'A'의 코드가 65이므로 65를 c에 저장하면 'A'가 저장된 것과 같은 효과를 낸다. 위의 2번과 다른 점은, int에는 char 변수든 문자 리터럴이든 대입이 가능했지만, 3번에서는 정수 리터럴만 char에 대입하는 것을 보여줬다. 그 말인즉슨...
한편, 컴파일러가 자동으로 변환해줄 수도 있을 것 같지만 수동으로 형변환을 하게끔 에러를 발생시키는 경우도 있다.
1. 같은 숫자형, 좌변의 범위 < 우변의 범위, 값은 표현 가능 범위 내
// int < double
double d = 3.14;
int i = (int)d;
System.out.println(i); // 3
// 0.14만큼 값손실 발생
// byte < int
int i = 10;
byte b = (byte)i;
System.out.println(b); // 10
두 번째의 경우, byte와 int 모두 정수 리터럴을 쓰기 때문에 b에도 10이 저장되긴 한다. 그렇지만 컴파일 단계에서는 int 타입의 변수가 byte 범위 내의 정수를 담고 있다는 확신이 없기 때문에 형변환을 하지 않으면 type mismatch 에러가 발생한다.
2. 같은 숫자형, 좌변의 범위 < 우변의 범위, 값이 표현 가능 범위를 초과
위에서 int를 byte로 형변환할 때, 10은 byte의 범위인 -128~127에 포함되기 때문에 값손실 없이 10이 b에 저장됐지만, 만약 i의 값이 byte의 범위를 벗어난다면 어떻게 될까?
// 1) 1 byte의 크기로 표현 가능한 숫자 200
int i = 200;
byte b = (byte)i;
System.out.println(b); // -56
// 2) 1 byte로 표현 불가능한 숫자 300
i = 300;
b = (byte)i;
System.out.println(b); // 44
어마어마한 값손실이 발생했다. 이렇게 된 이유는 다음과 같다.
int는 4 byte이고 byte는 1 byte이기 때문에 int -> byte 형변환을 하게 되면 int의 앞쪽 3 byte를 버리고 나머지 1 byte만 byte로 변환이 된다. 이때 200을 변환한 경우, 버려지는 값은 없으나 맨 앞 부호비트가 1이어서 음수가 되어버린 것이고, 300을 변환한 경우는 값이 있는 비트가 버려지는 일이 발생해서 값손실이 일어나게 된 것이다. 이러한 값손실을 막기 위해 컴파일러가 에러를 발생시켜 수동으로 형변환을 유도하는 것이다.
3. char에 int 변수 대입
// 자동변환 3. char에 정수 리터럴 대입 예시
char c = 65;
System.out.println(c); // 'A'
// char에 정수 변수를 대입한다면?
int i = 66;
char c = i;
System.out.println(c); // error: type mismatch
에러가 발생하는 이유는 표현 가능한 범위의 차이 때문이다. int는 부호 있는 4 byte 이진수로 대략 -20억~20억까지 표현이 가능하고, char는 부호 없는 2 byte 이진수로 대략 0~6만까지 표현이 가능하다. 컴파일을 할 당시에는 실제 저장된 값을 확인해보지 않기 때문에 변수 i에 저장되어있는 값이 c에 저장 가능한 값인지 확신할 수 없으므로 에러를 발생시켜 수동으로 형변환을 하게 만드는 것이다.
int i = 66;
char c = (char)i;
System.out.println(c); // 'B'
(char)를 붙여 수동으로 형변환을 하면 정상적으로 'B'가 저장되는 것을 볼 수 있다.
지금까지의 내용을 정리해보자면,
1. 형변환을 하는 이유는 서로 다른 두 타입을 맞추기 위해서이다.
2. 형변환 연산자를 생략하면 컴파일러가 값을 최대한 보존할 수 있는 방법으로 자동 변환을 한다.
3. 그 방법이라 함은 두 타입 중 표현 범위가 넓은 타입으로 변환하는 것이다.
4. 값손실이 발생할 것 같으면 에러를 발생시켜 사용자가 수동 변환을 하게끔 한다.
5. 형변환 연산자를 이용해 수동 변환을 할 때, 내 의도대로 형변환이 되는 건지 확인해 볼 필요가 있다.
[쿠키글] 색다르게 형변환을 할 수 있는 방법
1. 문자(char) ⇔ 숫자
문자를 숫자로 바꿀 때는 '0'(문자 0)을 빼주면 되고, 숫자를 문자로 바꿀 때는 앞에 (char)를 붙이고 '0'을 더해주면 된다.
// 1) 문자를 숫자로
System.out.println('7' - '0'); // 7
// 2) 숫자를 문자로
// 문자 0의 유니코드값은 48
System.out.println( (char) (7+'0') ); // 7 + 48 = 55. 유니코드 55번은 '7'
// 2)-1. (char)를 안붙이는 경우
System.out.println(7 + '0'); // 7 + 48 = 55
// 2)-2. '0'을 더하지 않는 경우
// 문자 7의 유니코드값은 55
System.out.println( (char) 7 ); // 유니코드값이 7인 문자가 출력됨
1)의 문자를 숫자로 바꾸는 원리는 아래 링크의 [쿠키글] 윗부분에 설명되어있다.
2021.12.31 - [Java] - 산술 연산자와 산술 변환
2. 문자, 숫자 ⇒ 문자열(String)
숫자든 문자든 ""(빈 문자열)만 더해주면 문자열로 바뀐다.
System.out.println(7 + ""); // "7"
System.out.println('7' + ""); // "7"
3. 문자열 ⇒ 숫자
숫자의 타입에 따라 다른 메서드를 써서 문자열을 숫자로 변환할 수 있다.
// 정수형 - int
System.out.println(Integer.parseInt("7")); // 7
// 실수형 - double
System.out.println(Double.parseDouble("7")); // 7.0
// 실수형 - float
System.out.println(Float.parseFloat("7")); // 7.0
4. 문자열 ⇒ 문자
문자열을 문자로 바꿀 때 charAt(0)을 이용한다.
System.out.println("7".charAt(0)); // '7'
'Java' 카테고리의 다른 글
비교 연산과 논리 연산 (0) | 2021.12.31 |
---|---|
산술 연산자와 산술 변환 (0) | 2021.12.31 |
연산자(operator)의 종류와 우선순위, 결합규칙 (0) | 2021.12.28 |
정수의 오버플로우(overflow) (0) | 2021.12.16 |
Scanner를 이용해 값을 직접 입력해서 화면에 출력하기 (0) | 2021.12.12 |