Java Category/Java

[JAVA] 타입 변환(형 변환)

ReBugs 2022. 12. 23.

혼자 공부하는 자바 (저자 : 신용권)의 내용을 개인적으로 정리하는 글임을 알립니다.


타입 변환

타입 변환은 자동 타입 변환과 강제 타입 변환으로 나뉜다.

  • 자동 타입 변환
  • 강제 타입 변환

 

자동 타입 변환

자동 타입 변환은 값의 범위가 작은 타입이 값의 범위가 큰 타입으로 저장될 때 발생한다

예를 들어, int는 4바이트 숫자를 저장하는 타입인데 int자료형의 값을 8바이트인 long 자료형에 넣을 때 자동으로 int타입을 long타입으로 자동으로 변환해 준다.

또한 타입의 메모리 크기(byte)가 크더라도 값의 범위가 더 작다면 메모리 크기가 더 작은 타입으로 자동 타입변환 될 수 있다.

기본 타입 값의 범위 크기순 나열
byte < short < int < long < float < double
-char보다 값의 범위가 작은 byte타입은 char타입으로 자동 타입 변환될 수 없다. 왜냐하면 byte타입은 값의 범위가 음수를 포함하지만 char타입은 음수를 포함하지 않기 때문

-정수 타입이 실수 타입으로 대입될 경우에는 무조건 자동 타입 변환이 된다. 실수 타입은 정수 타입보다 허용 범위가 더 크기 때문이다.
float floatValue = longValue; //5.0E9f로 저장됨
double doubleValue = longValue; //5.0E9로 저장됨

 

강제 타입 변환

값의 범위가 큰 자료형은 값의 범위가 작은 자료형으로 자동 타입 변환이 될 수 없다.

이는 큰 접시에 있는 물을 작은 접시에 모두 담으려 하는 것과 똑같다.

하지만 큰 접시에 있는 물을 작은 접시의 크기로 나눠서 한 부분만 담는 것은 가능하다.

이와 같은 방법을 강제 타입 변환이라고 한다.

 

강제 타입 변환은 캐스팅 연산자를 이용한다. 캐스팅 연산자는 괄호() 이다.

int a = 65;
char b = (char) a;
System.out.println(b); //A 출력

주의해야 할 점은 실수 타입은 정수타입으로 자동 변환되지 않기 때문에 강제 타입 변환을 사용해야 한다.

이 경우 소수점 이하 부분은 버려지고, 정수 부분만 저장된다.

double a = 3.14;
int b = (int) a;
System.out.println(a); // 3 출력

 

강제 타입 변환을 하게 되면 값이 손상될 수도 있고 안 될 수도 있다.

위 그림처럼 int 타입을 byte 타입으로 강제 타입 변환을 하려 할 때, byte의 허용 범위를 넘는 값이라면 값이 손상될 수 있다.

 

정수 연산에서의 자동 타입 변환

정수 타입 변수가 산술 연산식에서 피연산자로 사용되면 int보다 작은 자료형의 변수는 int로 자동 타입 변환되어 연산을 수행한다.

int보다 작은 자료형의 변수끼리의 연산
byte x = 10;
byte y = 20;
byte result = x + y; //컴파일 에러
int result = x + y; // x와 y는 int로 자동 타입 변환
위 코드에서 3번째 줄은 컴파일 에러가 나는데, 이는 연산을 컴파일 단계에서 하느냐 JVM이 하느냐 문제이다.
숫자 자체가 아니라 변수끼리의 연산은 JVM에서 연산을 하기 때문에 int 타입으로 변환되어 컴파일 에러(오버플로)가 난다.
컴파일 단계에서 연산
자바는 실행 성능을 향상시키기 위해 컴파일 단계에서 연산을 수행할 수 있다.
byte a = 10 + 20;
위와 같은 연산은 정수 리터럴끼리 연산이어서 컴파일 단계에서 미리 연산해서 30을 만들고, result 변수에 30을 저장하도록 바이트 코드를 생성한다. 이 경우에는 피연산자가 변수가 아니므로 int 타입으로 변환을 하지 않는다.

특별한 이유가 없는 경우 정수 연산에서는 int형을 사용하는 것이 효율적이다. 왜냐하면 이유 없이 int형을 사용하지 않으면 형변환 단계가 쓸데없이 있기 때문.

 

 

정수 연산에서 모든 변수가 int타입으로 변환되는 것은 아니다. 두 피연산자 중 값의 범위가 큰 타입으로 변환되어 연산을 한다.

int 타입보다 값의 범위가 더 큰 long 타입이 피연산자로 사용되면 다른 피연산자는 무조건 long 타입으로 변환하고 연산을 수행한다.

	public static void main(String[] args) {
		byte a = 10;
		int b = 100;
		long c = 1000L;
		long result = a + b + c; // a,b,c long으로 형 변환
		System.out.println(result); // 1110 출력
	}

 

실수 연산에서의 자동 타입 변환

int타입과 double 타입을 연산해도 동일한 과정을 수행한다. int형 피연산자가 double형으로 자동 변환되고 연산을 수행

int a = 10;
double b = 5.5;
double result = a + b; // a는 double로 형변환 되어 10.0 + 5.5
자바는 소문자f 또는 대문자 F가 없는 실수 리터럴을 double 타입으로 해석함. 그렇기 때문에 연산 결과는 double 타입 변수에 저장해야 함
float result = 1.5 + 2.3; // 컴파일 에러
//1.5와 2.3 모두 double 타입으로 해석하기 때문에 오버플로​
꼭 float에 저장해야 한다면 컴파일러에게 float 타입임을 알려주자
float result = 1.5f + 2.3f;​

 

수학에서 1을 2로 나누면 0.5가 정답이다. 하지만 코드를 짤 때 조심해야 한다.

int x = 1;
int y = 2;
double result = x / y;
System.out.println(result); // 0.0을 출력

위의 코드 실행결과는 0.0이다

왜냐하면 자바에서 정수끼리의 연산 결과는 정수가 되기 때문이다.

정상적으로 0.5를 출력하려면 정수 연산이 아니라 실수 연산으로 변경해야 한다.

즉, x와 y 둘 중 하나 또는 둘 모두 double 타입으로 변환해야 한다.

int x = 1;
int y = 2;
double result = (double) x / y;
System.out.println(result); // 0.5를 출력

만약 (double) (x / y)로 잘못 수정하면 0.5가 아니라 0.0을 얻는데 그 이유는 괄호 안의 연산이 먼저 수행되어서 다시 정수끼리 연산으로 처리되기 때문이다.

 

+ 연산에서의 문자열 자동 타입 변환

자바에서 + 연산자는 두 가지 기능을 제공함

  • 피연산자가 모두 숫자일 경우에는 덧셈 연산 수행
  • 피연산자 중 하나가 문자열일 경우에는 나머지 피연산자도 문자열로 자동 변환되어 문자열 결합 연산 수행

연산식에서 + 연산자가 연이어 나오면 앞에서부터 순차적으로 + 연산 수행

public static void main(String[] args) {
		int value = 1 + 2 + 3; // 3 + 3 -> 6
		String str1 = 1 + 2 + "3"; // 3 + "3" -> "33"
		String str2 = 1 + "2" + 3; // 1 + "2" = "12", "12" + 3 = "123"
		String str3 = "1" + 2 + 3; // "1" + 2 = "12", "12" + 3 = "123"
	}
특정 부분을 우선 연산하고 싶을 경우
앞에서부터 순차적으로 + 연산을 수행하지 않고 우선 연산하고 싶은 부분이 있다면 해당 부분을 괄호로 감싸주면, 괄호를 최우선으로 연산을 수행함
String str3 = "1" + (2 + 3); // "1" + 5 = "15"​

 

문자열을 기본 타입으로 강제 타입 변환

"12"와 "3.5"를 정수 및 실수 타입으로 변환해서 숫자 연산을 하는 경우

자바에서 문자열을 기본 타입으로 변환하는 방법은 아래와 같다.

변환 타입 사용 예
String -> byte string str = "10";
byte value = Byte.parseByte(str);
String -> short string str = "200";
short value = Short.parseShort(str);
String -> int string str = "300000";
int value = Integer.parseInt(str);
String -> long string str = "40000000000";
long value = Byte.parseLong(str);
String -> float string str = "12.345";
float value = Float.parseFloat(str);
String -> double string str = "12.345";
Double value = Double.parseDouble(str);
String -> boolean string str = "true";
boolean value = Boolean.parseBoolean(str);

문자열이 숫자가 아닌 다른 값이면 오류가 발생하므로 주의

 

반대로 기본 타입에서 문자열로 변경해야 할 경우도 있는데 이 때는 String.ValueOf()메소드를 이용하면 된다.

int a = 10;
String str = String.valueOf(a); // 10 -> "10"

또는

int a = 10;
String str = "" + a;

이렇게 하면 기본 타입에서 문자열로 변경할 수 있다.

댓글