반응형

형변환 연산자

  • 형변환이란?

변수또는 상수의 타입을 다른 타입으로 변환하는 것

바꾸는 방법은 쉽다. 

(타입)피연산자

이러한 형태로 피연산자 앞에다가 괄호안에 바꿀 타입을 적어주기만 하면 된다.

double d= 85.4;
int score = (int)d;

double타입은 8byte이고, int는 4byte이다.
타입이 달라서 저장할 수 없다. 이럴 때 사용하는게 형변환 이다. 

저장하려면 double을 integer로 바꾸어 집어넣어야 한다. 
그래서 (int)d; 이부분이 하는 일이 피연산자 d의 타입을 integer로 바꾸는 처리를 하는 것이다. 

그래서 그 과정을 조금 더 자세히 보면 아래와 같다.

double d = 85.4;
int score = (int)d;
int score = (int)85.4;
int score = 85;

이때 중요한 건, 변수 d에 있는 85.4는 바뀌지 않았다는 것이다.
즉, 변수에 있는 값을 읽어와서, 그 읽어온 값을 형변환 하는 것이지 변수의 값을 형변환 하는 것이 아니다.

intege타입 65를  char타입으로 형변환을 하면 문자 'A'가 된다.
65가 왜 'A'가 되냐면 아래의 유니코드 표를 보면 알 수 있다.

이 표에의해서 변경이 된다.
앞의 예시와 반대로 문자 'A'를 정수인 integer로 바꾸어도 65가 된다.

아래 그림을 보자.

이렇게 변수 ch에 문자 'A'를 저장하면, 'A'가 그대로 저장되는 것이 아니라, 유니코드표에서 문자 'A'의  코드인 65가 저장되는 방식으로 저장된다.

컴퓨터는 숫자밖에 모른다. 즉, 문자를 숫자로 바꾸어 저장해야 하는데, 그때 사용하는 표가 유니코드 표 이다.
'A'가 65로 기준이다. 소문자'a'는 97이다.
그리고 문자'0'은 코드 48~문자 '9'는 코드 57로 연속적으로 되어있다.

어쨋든, 우리가 저장하는 모든 데이터는 숫자(코드)로 바뀌어 저장된다는 점을 알아두자.

 

다시 아래의 표를 보자.

실수를 정수로 바꾸는 예를 보자.
float 1.6f를 integer로 변환하면 int1이 된다. 정수형은 소수점을 저장할 수 없고, 반올림을 하지 않고 버림을 한다.

이번에는 정수를 실수로 형변환 하면?
int 10을 float으로 형변환을 하면, 10.0f 가 된다. 그냥 .0을 붙히고 f접미사를 붙히면 된다.

 


 

자동 형변환

 

float f = 1234;		// intㅌ입의 값을 float타입의 변수에 저장

이러한 문장이 있을 때, 
왼쪽은 float타입이고, 오른쪽은 integer타입이다.
기본적으로 대입 연산자의 양쪽 타입이 일치해야하는데 위의 경우 불일치 한다.

int값을 float값에 넣을 수 있을까?

넣을 수 있다. 괜찮다.
왜냐하면, integer값의 범위는 +_20억이고, float타입은 10^38정도 된다.
float가 훨씬 크기때문에 문제가 없다. 

즉, 작은 값을 큰 타입의 변수에 넣으니까 문제가 없는 것이다.

그치만, 원래는 아래와같이 대입연산자의 양쪽 타입이 일치해야 한다.

float f = (float)1234;

이 문장처럼 형변환을 통해서라도 일치해야 한다. 

그치만 첫번째 문장에서는 형변환이 생략된 것이다.
형변환을 안썻다고해서 형변환이 되지 않는 것은 아니다.
컴파일러가 두번째 문장처럼 자동으로 넣어준다.

이렇게 첫번째 문장처럼 (float)을 생략해도, 두번째 문장처럼 자동으로 형변환을 넣어주는 것, 
즉, 컴파일러가 자동으로 형변환 해주는 것을  "자동 형변환" 이라고 한다.

 

int i = 3.14f		// 에러

그치만, 위의문장처럼 int타입의 변수에 float 3.14f를 저장하려고 하면 에러가 발생한다.

어? 앞에서는 분명히 자동 형변환을 해준다고 했는데 왜 에러가 발생하는거지? 라고 생각 할 수 있다.

float타입의 범위가 int타입의 범위보다 넓다. 그러면, 값이 짤릴 수 있지 않겠는가? 

예를 들어보자.
3.14f를 integer타입으로 형변환 하면 3이 된다. 소수점 뒤에가 짤린다.  원래값하고 달라진다.
이러한 것을 "값손실 발생" 이라고 한다. 

이처럼 범위가 큰  값을 범위가 작은 쪽에 넣으면 "값손실 발생"을 할 수 있다. 
그래서 이러한 경우에는 컴파일러가 자동 형변환 해주지 못한다.

그래서 이럴 때는 아래와 같이 수동형변환을 해주어야 한다.

int i = (int)3.14f;		// OK

이렇게하면 에러가 발생하지 않는다. 

이렇게 하는 이유는, 컴파일러가 알아서 해주는 경우도 잇지만, 여기서는 "값손실 발생"을 할 수 있기 때문에 자동으로 못하고 우리에게 직접 형변환을 하라고 하기 떄문이다. 즉 "값손실"이 우려되는 경우에는 자동으로 형변환을 해주지 않는다.

 

이번에는 그림과 함께 조금 더 자세히 살펴보자. 

byte 타입의 값을 int에 넣는 경우를 보자.

byte는 크기가 1byte다. integer는 4byte다.  작은 값을 큰 그릇에 담으려는 것이기 때문에
이럴 떄에는 형변환을 생략할 수 있다.(자동형변환)
그림을 보면, 값손실이 없다.

두번째 int를 byte에 담는 경우를 보자.

int 는 4byte이고, byte는 1byte인데, int를 byte에 담으려고 하면 값손실이 발생한다. (발생하지 않을수도 있지만)
작은 그릇에 큰 값을 담으려고 할 때는 컴파일러가 자동형변환을 해주지 않는다. 수동으로 형변환을 해주어야 한다. 
즉, 이러한 경우에는 형변환을 생략할 수 없다.

 

정리해보면,

위 그림은 왼쪽에서 오른쪽 순으로 값의 범위가 넓다.

작은 타입에서 큰타입으로 가는 것은 다 자동 형변환이 된다. 

byte가 short으로 자동 형변환 된다.

근데 같은 2byte인 short과 char끼리는 자동 형변환이 안된다. 

왜 안되냐면,
short는 부호 있는 정수라서 범위가 -3만~+3만이고,
char는 범위가 0~6만 이다.

표현할 수 있는 값의 개수는 둘다 6만 이지만, 
범위가 달라서 자동 형변환이 안되고, 반드시 수동으로 형변환을 해줘야 한다.

byte short  int → long 까지는 모두 정수형 이다. 
long은  크기는 8byte인데, 값의 범위가 10^19이고, float는 4byte 이긴한데 실제 표현할 수 있는 값의 범위는 10^38쯤 된다. float가 훨씬 크다.

단순히 byte로만 따지면 long이 크지만, 표현할 수 있는 값의 범위는 실수형이 크기 때문에 long에서 float는 자동 형변환가능하다. 


 

지금까지 자동 형변환에 대해 알아보았는데, 몇가지만 더 알아보자.

byte b = 100;		// OK. byte타입의 범위(-128~127)의 값의 대입

 

이런 문장이 있을 때, 100은 integer의 정수이다.  변수는 byte타입이다.
byte 타입은 1byte다. integer타입은 4byte다. 
큰 값을 작은 곳에 넣는데 아무런 문제가 없다? 왜그럴까?

그 이유는, 아래와 같이 컴파일러가 자동형변환을 해서 그렇다.

byte b = (byte)100;		// OK. byte타입으로 형변환하여 대입

작은 타입을 큰 타입에 넣을 떄는  자동형변환 하는게 맞다고 알고 있는데,
큰 타입을 작은 타입에 넣는데도 자동 형변환이 되는건가? 라는 생각이 들 수 있다. 

된다. 그치만 이건 예외적이다.

100의 타입이 integer긴하지만, 100은 byte 타입의 범위 -128~127 에 포함되어 있다. 

즉, integer지만 100은 byte로 자동 형변환해도 "값손실 없다" 라는 것을 컴파일이 알고 있다. 
그래서 컴파일러가 자동으로 byte타입으로 자동형변환을 하는 것이다.  (원래는 적어줘야 한다.)

 

int i = 100;
byte b = i;			// 에러. int타입을 byte의 타입에 대입
byte b = (byte)i;		// OK. byte타입으로 형변환하여 대입

그런데 이 예시의 두번쨰 문장에서는 왜 에러가 날까? 

위의 예시처럼  integer 타입 100을 byte타입에 저장하려고 하는데, 형변환을 생략했더니 100은 byte타입의 범위인 -127~128 에 있음에도 불구하고 자동형변환되지 않고 에러가 발생한다. 그이유가 뭘까?

이전의 예시와 현재 예시의 다른점은 100이 리터럴(상수) 이냐 아니냐 라는 것 이다.

이전이 예시에서는 100은 리터럴 값(상수) 즉 명백히 정해진 값이었다.

그러나, 현재 예시에서는 100은 변수 i에 저장된 값이고, 
자동형변환을 기대한 대상은 변수i이다. 즉 변수에 대하여 자동형변환은 되지 않는다.
왜냐하면 변수안에 어떤 값이 들어있는지 컴파일러가 확신할 수 없기 때문이다.

그래서 이런 경우에는 수동 형변환을 해야한다. 이 차이점에 대해서 잘 알아두자.

 

반응형

'JAVA' 카테고리의 다른 글

반올림 Math.round(), 나머지 연산자  (0) 2022.03.16
사칙 연산자, 산술변환  (0) 2022.03.16
증감 연산자, 부호 연산자  (0) 2022.03.15
연산자의 우선순위와 결합규칙  (0) 2022.03.14
연산자와 피연산자  (0) 2022.03.14