
자바로 코드를 짜다 보면 이런 코드를 마주칠 때가 있습니다.
char a = 'A';
char b = 'B';
System.out.println(a + b);
직관적으로는 "AB"가 출력될 것 같습니다. 문자 두 개를 더했으니 문자열이 이어붙는 게 자연스러워 보이니까요. 그런데 실제로 실행해보면:
131
숫자가 나옵니다. 왜 이런 일이 생길까요?
자바에서 char는 "문자처럼 보이지만 사실은 숫자"입니다. 정확히는 유니코드 코드값을 저장하는 16비트 정수 타입입니다. 'A'라는 문자는 내부적으로 65라는 숫자로 저장되어 있고, 'B'는 66입니다.
char a = 'A';
int code = a; // 암묵적으로 int로 변환 가능
System.out.println(code); // 65
이걸 직접 확인해보면:
System.out.println((int) 'A'); // 65
System.out.println((int) 'B'); // 66
System.out.println((int) 'a'); // 97
System.out.println((int) '0'); // 48
즉 char는 글자 모양을 가진 게 아니라, "이 숫자는 이 글자에 대응된다"는 약속(유니코드 테이블)을 가지고 있는 정수일 뿐입니다.
자바의 + 연산자는 피연산자의 타입을 보고 동작이 결정됩니다. char나 int 같은 숫자 타입끼리 +를 만나면, 자바는 이걸 그냥 산술 연산(더하기)으로 처리합니다.
char a = 'A'; // 65
char b = 'B'; // 66
System.out.println(a + b); // 65 + 66 = 131
여기서 한 가지 더 알아둘 점은, char + char 연산의 결과는 char가 아니라 int로 자동 승격(promotion)된다는 것입니다. 그래서 131이라는 결과의 타입은 int입니다.
char a = 'A';
char b = 'B';
// char result = a + b; // 컴파일 에러! int를 char에 바로 못 넣음
int result = a + b; // 정상 동작, 131
만약 131을 다시 문자로 보고 싶다면 명시적으로 char로 캐스팅해야 합니다.
char result = (char) (a + b);
System.out.println(result); // 131에 해당하는 유니코드 문자가 출력됨 (보통 보이지 않는 특수문자)
반대로 + 연산자의 한쪽에 String이 있으면 동작이 완전히 바뀝니다.
char a = 'A';
String b = "BC";
System.out.println(a + b); // "ABC"
자바는 + 연산에서 피연산자 중 하나라도 String이면, 다른 쪽을 자동으로 String으로 변환한 뒤 문자열 결합을 수행합니다. 이건 자바 언어 명세에 정의된 동작으로, String.valueOf()를 자동으로 호출해주는 것과 비슷합니다.
char a = 'A';
String b = "BC";
// 자바 내부적으로는 대략 이렇게 처리됨
String result = String.valueOf(a) + b;
// "A" + "BC" = "ABC"
즉 + 연산자의 의미가 "숫자 더하기"에서 "문자열 이어붙이기"로 완전히 바뀌는 거죠. 어느 쪽으로 동작할지는 String이 연산에 끼어있는지 여부가 결정합니다.
char + String이든 String + char든 결과는 동일하게 문자열 결합입니다.
char a = 'A';
String b = "BC";
System.out.println(a + b); // "ABC"
System.out.println(b + a); // "BCA"
다만 여러 개를 한 줄에 더할 때는 왼쪽부터 순서대로 계산되기 때문에 순서에 따라 결과가 크게 달라질 수 있습니다.
char a = 'A';
char b = 'B';
String c = "";
System.out.println(a + b + c); // "131" !!
System.out.println(c + a + b); // "AB"
a + b + c: 먼저 a + b가 계산되는데, 둘 다 char라서 131(int)이 됩니다. 그 다음 131 + c에서 c가 String이라 131이 문자열 "131"로 변환되어 합쳐집니다. 결과는 "131".c + a + b: 맨 앞에 String이 있어서 c + a부터 이미 문자열 결합으로 시작합니다. "" + 'A' → "A", 그다음 "A" + 'B' → "AB".같은 변수 셋을 더해도 어디서부터 String이 끼는지에 따라 결과가 완전히 달라지는 셈입니다.
| 연산 | 결과 | 이유 |
|---|---|---|
char + char | int (코드값의 합) | 둘 다 숫자 타입이라 산술 연산으로 처리됨 |
char + int | int (코드값 + 숫자) | 마찬가지로 산술 연산 |
char + String | String (문자열 결합) | String이 있으면 다른 피연산자가 String으로 자동 변환됨 |
String + char | String (문자열 결합) | 순서가 바뀌어도 동일하게 동작 |
a + b + c (혼합) | 왼쪽부터 순서대로 계산, String 등장 시점부터 문자열 결합 시작 | 연산자 결합 규칙(왼쪽 우선)을 따름 |
핵심은 한 가지입니다. + 연산에 String이 하나라도 있으면 전체가 문자열 결합으로 동작하고, 없으면 숫자 타입끼리의 산술 연산으로 처리된다. 이 규칙만 기억해두면 'A' + 'B'가 131이 나오는 이유도, 반대로 'A' + "BC"가 "ABC"가 되는 이유도 한 번에 설명됩니다.
자바에서 문자와 문자열을 다룰 때 흔히 마주치는 함정이니, 코드를 짤 때 + 연산자 양쪽의 타입이 무엇인지 한 번 더 확인하는 습관을 들이면 좋을 것 같습니다.