본문 바로가기

DEVELOPER/Java

[JAVA 파헤치기] 문자 타입 'char' 와 문자열 'String' 의 진실


안녕하세요😎 백엔드 개발자 제임스입니다 :)

자바 언어를 공부하기 시작하신 분이라면, 자료형에 대해서 배웠을 것입니다. 주로 자료형 또는 데이터 타입이라고 부르는데요. 변수에 담길 값의 형태를 나타내 주는 중요한 개념입니다. 이러한 자료형에는 다양한 종류와 명칭이 있습니다.  포스팅을 시작하기 전에 기본 타입 자료형에는 어떤 종류가 있는지 알아보도록 하겠습니다.


기본 타입(Primitive type)      

  • 데이터의 실제 값을 의미
  • 정수 타입, 실수 타입, 문자 타입, 논리 타입으로 분류

자바의 기본 타입(primitive type)

위 그림에서 보이는 내용들이 기본 타입에 해당합니다.

이제 오늘 포스팅 주제를 소개하겠습니다. 이번 포스팅은 문자 타입의 char와 문자열을 나타내는 String에 대해서 자세하게 정리하고, 두 가지를 비교해보려고 합니다. 평소에 저는 문자를 다룰 때 아무 생각없이 char와 String을 사용했습니다. 하지만 가끔 제가 원했던 결과가 나오지 않고, 정수 값을 반환하거나 에러를 발생하는 경우가 종종 있었습니다. 이에 저는 char와 String에 대해서 정확하게 알아야 할 필요가 있다고 판단했고, 이렇게 정리하게 되었습니다.

그럼 이제 자세하게 알아보도록 하겠습니다.


 


문자 타입 : char


# 요약
1) char는 Character의 약자
2) 단 하나의 문자만 저장
3) 2byte
4) char 타입의 리터럴은 작은 따옴표(' ')로 감싸서 표현
5) 컴퓨터 내부에 저장될 땐 정수로 치환 (아스키 코드)

 

01. char의 진실!

char는 기본형 타입에서 문자 타입으로 분리되었지만, 사실상 2 바이트의 정수입니다. 이 부분이 굉장히 중요한데요. 그 이유는 실제로 컴퓨터는 문자를 구별할 수 없습니다. 즉, 컴퓨터 안에는 절대 문자가 저장될 수 없을뿐더러, 모든 것이 숫자로 저장되는 것입니다.

그렇다면 char는 대체 어떻게 저장되는 것일까요?

사람과 컴퓨터가 언어를 교환하기 위해서 만들어진 코드가 있는데요. 대표적으로는 아스키코드(ASCII code)와 유니코드(unicode)가 있습니다. 따라서 우리가 char형 변수의 문자를 선언하게 되면, 해당 문자는 아스키코드의 규칙에 맞게 숫자로 치환이 되어 컴퓨터에 저장되게 됩니다.

* 아스키코드(ASCII code)
1) 미국 표준 부호 체계로 영문자, 숫자, 특수 문자에 고유의 숫자를 부여한 것
2) 7비트의 조합으로 이루어져 총 128(2^7) 개를 사용
3) 영문자만 존재하여 한글과 타 언어는 표현 X
-> 이 점을 보완한 것이 유니코드(16비트)

이제 이러한 사실을 코드를 통해서 직접 알아볼까요?

 

02. 직접 실행하면서 char 분석하기

1) char타입의 문자 선언과 출력

char c = 'A';

// 변수 c 출력하기
System.out.println(c);

// 선언 없이 문자 출력하기
System.out.println('A');

1번 코드 실행 결과

  • 결과는 모두 A가 나옵니다. 따라서 char 타입의 리터럴을 호출할 시에는 선언한 문자 그대로 나오는 것을 알 수 있습니다.

2) char 타입의 c를 정수(아스키코드)로 변환

  • 해당 문자의 정수인 아스키코드값을 확인하기 위해서 char 타입에서 int 타입으로 형 변환을 해줍니다.
  • 방법은 아래 코드와 같습니다.
char c = 'A';
int c1 = 'A';

System.out.println((int)c);
System.out.println((int)'A');
System.out.println(c1);

 

2번 코드 실행 결과

  • 결과는 모두 65가 나오는 것을 알 수 있습니다.
  • 따라서 대문자 A의 정수 값(아스키코드)은 65입니다.
다른 문자의 아스키코드는 아스키코드표를 참고해주세요.

3) char 타입 변수와 또 다른 char 타입 변수 연산하기

  • 이번에는 char 타입의 변수끼리 더하고 출력하겠습니다.
char c1 = 'A';
char c2 = 'A';

System.out.println(c1 + c2);

System.out.println('A' + 'A');

3번 코드의 결과

  • 결과는 놀랍게도 AA 가 아닌, 모두 정수 130이 출력되었습니다.
  • 이는 각각 할당된 문자 리터럴이 컴퓨터에 저장될 때 아스키코드값으로 치환이 되었고, 더하기 연산자를 사용하면서 int로 변형이 발생한 것입니다. 즉, 정수 65와 65가 더해진 것이죠.

4) char 타입 변수와 정수 연산하기

  • 이번에는 문자에 정수를 더해보겠습니다.
char c1 = 'A';

System.out.println(c1 + 1);

  • 보다시피 결과는 65에서 1이 더해진 66이 나왔습니다.
  • 이번에도 역시 정수로 연산이 되었습니다.
  • 그렇다면 이 상황에서 다시 char로 형 변환하여 출력하면 어떻게 될까요?
char c1 = 'A';

// 수동 형변환을 진행합니다.
System.out.println((char)(c1 + 1));
바이트 크기가 큰 타입(int:4byte)에서 작은 타입(char:2byte)으로 변환하기 때문에 수동으로 타입 변환을 진행합니다.

66을 문자로 타입 변환

  • 결과는 문자 B가 나왔습니다.
  • 즉, 문자 A의 아스키코드 65에서 1을 더 하여 나온 66을 문자로 변환하게 되면, 문자 B가 되는 것입니다.


지금까지 char 타입에 대해서 알아보았는데요. 이와 같이 자꾸만 변환이 되는 char 타입으로 인해서 다양한 것을 할 수 있거나 혹은 까다로운 개발을 할 수도 있겠다는 것을 알았습니다. 추가로 아스키코드와 유니코드에 대해서는 별도로 자세하게 알아볼 필요가 있습니다. 😊

여기서부터는 문자열 String에 대해서 알아보도록 하겠습니다.

우리는 위에서 문자 'A'와 'A'를 더했을 때 130이 된 것을 확인했습니다. 하지만 정수가 아닌 단순하게 'AA'가 되기를 원했다면 어떻게 해야 하는 것일까요?

이처럼 정수로 변환되지 않은 채 문자끼리 연결하기 위해 사용하는 것이 문자열 String입니다. 이제 자세하게 알아보겠습니다.

 

문자열 클래스 : String


#요약
1) 자바에서 제공하는 문자열 클래스
2) 문자(char)들의 배열을 의미
3) String 클래스 타입은 큰 따옴표(" ")로 감싸서 표현
4) 미리 구현된 다양한 메서드를 통해서 다룰 수 있음

 

01. String의 진실!

이번에는 코드와 같이 보도록 하겠습니다.

1) 먼저 String은 단순히 타입이 아닙니다. 제목에서도 알 수 있듯이 자바에서 구현된 클래스인데요. 이에 따라 실제로 선언할 때는 변수에 값을 저장하는 방식이 아닌 하나의 객체를 생성하고, 해당 객체에 문자들을 연결시키는 방식입니다.

실제 선언 방식은 아래와 같습니다.

// new 연산자를 사용해서 객체를 생성하고 문자열을 대입하는 방식
String 변수 = new String("문자열");

// 하지만 변수에 직접 대입하는 방식으로도 사용이 가능!
String 변수 = "문자열";

 

2) String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없습니다. 이러한 객체를 불변 객체(immutable object)라고 하는데요. 즉, 덧셈 연산자를 사용해서 문자열과 문자열을 더한다면, 새로운 String 인스턴스가 생성되는 것이죠. 아래 예시를 보면 str1, str2를 더한 str3은 새로운 인스턴스인 것입니다.

String str1 = "Hello";
String str2 = "JAVA";

String str3 = str1 + str2; // "HelloJAVA"

 

3) 위에서 선언하는 방식을 보았을 때, 두 가지가 있다는 것을 알았습니다. 마치 비슷한 방식인 것 갖지만 실제로 비교해보면 차이가 있다는 것을 알 수 있습니다.

String을 타입으로 하여 변수에 문자열 리터럴을 직접 선언했을 때
String str1 = "JAMES";
String str2 = "JAMES";

System.out.println(str1 == str2); // true
  • 결과는 true가 나옵니다.

 

new 연산자를 사용해서 String 객체를 생성하는 방식
String str1 = "JAMES";
String newStr = new String("JAMES");

System.out.println(str1 == newStr); //false
  • 이번에는 false가 나왔습니다.

 

🧐  왜 위와 같은 결과가 나왔을까요?                         

먼저 변수에 문자열 리터럴을 직접 선언했을 때 참조값(주소 값)을 확인해보겠습니다. 그렇다면 아래와 그림과 같은 형태인데요.

변수에 문자열 리터럴을 직접 선언한 방식

String에서 문자열 리터럴을 선언할 때 리터럴이 같으면 변수는 같은 참조값(주소 값)으로 할당을 받게 됩니다. 따라서 '==' 연산자를 사용했을 때 true를 반환한 것입니다.

반면 객체를 생성하는 방식은 아래 그림과 같이 새로운 참조값(주소값)으로 할당을 받습니다. 따라서 '==' 연산자에서 false를 반환한 것입니다.

객체를 생성한 방식

마지막 Point!
String str = "JAMES"와 같이 선언했을 때, 사실 변수에는 한 개의 값만 들어갈 수 있습니다.
따라서 참조값을 가진 str이 생성되었을 때 JAMES 문자들이 변수 안에 들어가는 것이 아닌 연결되는 것입니다.

 

02. String은 char와 어떻게 다른가?

당연스럽게도 쓰는 방법과 리터럴 등이 다릅니다. 그 이유는 char는 문자, String은 문자열을 받기 때문입니다. 이 외에도 다른 차이는 무엇이 있을까요?

먼저 String은 클래스라는 점과 char는 기본형 타입이라는 점에서 차이가 있을 수 있는데요. 이러한 점으로 아래와 같은 차이가 발생합니다.

// String 은 빈문자열과 null로 초기화 가능
String str = ""; 
String str1 = null;

// char 는 빈문자열(공백X) 과 null로 초기화 불가능
char ch = ''; // X
char ch = null; // X
* TIP
Java.lang에서 제공하는 Wrapper 클래스인 Character와 Integer를 통해서 기본 데이터 타입의 값을 객체 형식으로 표현하고, 더 자세하게 다룰 수 있습니다.
* TIP2
char 타입 변수에 리터럴로 유니코드를 작성하면 null로 초기화가 가능합니다!

ex) char ch = '\u0000' // 10진수로는 0에 해당하는 유니코드, null로 표현이 가능

 

String과 char의 차이점 중 추가로는 String을 출력했을 땐 문자 그대로 출력한다는 것이고, char는 자칫하면 정수로 나타난다는 것입니다. 가령 '안'이라는 문자와 '녕'이라는 문자를 연결해서 '안녕'이라고 표현하고 싶을 때도 말입니다. 이러한 경우에 어떻게 문자들을 더해서 문자열로 표현할 수 있을까요?

자세한 것은 아래에서 확인해보도록 하겠습니다.

 

03. char를 문자열로 변환하는 방법

  • String.valueOf(charrArr)
    -> java.lang.String 클래스의 valueOf() 메서드는 char 배열을 파라미터로 받아서 String으로 변환하여 리턴합니다.
char a = '안';
char b = '녕';

String test = String.valueOf(a) + String.valueOf(b);

System.out.println(test); // 안녕

 

  • Character 클래스의 toString()
    -> Character 클래스의 toString() 메서드를 통해서 Char를 String으로 반환할 수 있습니다.
char a = '안';
char b = '녕';

String test = Character.toString(a) + Character.toString(b);

System.out.println(test); // 안녕

 

  • 문자를 빈 문자열과 연결하여 문자열로 변환
char a = '안';
char b = '녕';

String test = "" + a + b;

System.out.println(test); // 안녕

 

여기까지 char와 String에 대해서 자세하게 알아보았습니다.

사실 위 내용들을 다 알지 못하여도, 개발을 할 때 큰 문제가 발생하는 것은 아닌데요. 그래도 이렇게 자세하게 알고 나면, 다양한 방법으로 활용할 수 있을 것 같습니다.

반응형