Language

왜 'a'는 String type이 될 수 없을까? feat. SCP

YATTA! 2024. 10. 27. 19:55

char을 큰 따옴표로 묶거나 String을 작은 따옴표로 묶으면 type 에러가 발생합니다. 

char c = "a"; // error
String s = 'a'; // error

 

🤓 왜 'a'는 String type으로 쳐주지 않는 걸까요?

왜 리터럴 타입으로 받을 때 따옴표로 둘을 구분해야하는지 의문을 가져보신 분들이 있을 것 같습니다.

해당 글에서는 둘을 구분해야하는 이유를 알아보고, String의 동작 방식을 정리해보려고 합니다. feat. char vs String

 


'a'와 "a"가 달라야 하는 이유

char은 Primitive 타입이고 String은 Reference 타입입니다.

Primitive 타입은 기본 데이터 타입으로 값을 직접 저장합니다. 반면 Reference 타입은 이름과 같이 메모리 주소를 참조하여 저장합니다. 또한 char는 2 바이트의 고정 크기를 갖지만, String은 동적으로 크기가 달라집니다. 이렇게 둘은 저장하는 공간과 처리 방식이 다르기때문에, 리터럴로 받을 때도 문법적으로 구분할 필요가 있습니다.

 

💡 c/c++도 타입을 따옴표로 구분합니다. 자바도 c와 c++ 규칙을 그대로 따라 따옴표로 구분을 하게 된 것 같습니다.

 

기본 타입과 참조 타입

Char는 값 자체가 저장되어 있어 == 연산자를 통하여 값을 비교할 수 있습니다. 

char a = 'test'; char b = 'test'; 을 비교할 경우 ture가 나오게 됩니다.

 

그러나 String은 '메모리 주소'를 저장합니다.

String s1 = new String("test"); String s2 = new String("test"); 를 비교할 경우 false가 나오게 됩니다.

이처럼 String은 문자열의 내용이 같더라도 메모리 주소가 다르다면 false가 반환될 수 있습니다. 만약 둘을 비교하고 싶으면 equals 메서드를 사용해야 합니다.

 

그렇다면 String type은 == 으로 비교하면 무조건 false가 나올까요?

 

String만의 특별한 저장 공간

String a = "test";
String b = "test";

위에서 String은 메모리 주소를 참조한다고 했습니다. a == b를 할 경우 false가 나와야하지 않을까? 생각하실 수도 있겠지만, 리터럴로 값 대입을 할 경우 a == b는 true가 나오게 됩니다.

 

그것은 바로 String만의 특별한 메모리 영역이 있기 때문입니다.

String Constant Pool(SCP)라는 영역으로 동일한 문자열이 메모리에 중복 저장되지 않도록 관리하는 역할을 합니다. 같은 문자열이면 캐싱이 되는 것입니다. 그래서 아래 그림과 같이 a와 b는 같은 문자열을 참조하게 되고, a == b는 true가 나오게 됩니다.

그런데 한 가지 의문이 생길 수 있습니다. 위에서 new String(); 으로 값을 만들어 비교했을 때는 false가 나왔다고 했으니까요.

직접 리터럴로 대입한 값과는 다르게 new를 통해 생성한 객체는 Heap 영역에 위치하게 됩니다. 리터럴로 String을 생성할 때와 new로 생성할 때의 차이가 될 것 같습니다.

 

String을 쓸 때 하나 주의할 점은, SCP에 저장된 문자열은 변경이 불가능해 값 자체를 수정할 수 없다는 것입니다. (Heap 영역 객체도 마찬가지)

 

Char 타입은 언제 활용할 수 있을까?

보안상 민감한 정보는 언제나 char[]을 사용하면 좋습니다.

비밀번호를 예시로 들 수 있을 것 같습니다.

 

앞에서 말했다시피 String은 불변입니다. String에 저장된 데이터는 가비지 컬렉션이 실행될 때까지 남아있을 수밖에 없습니다. 다른 상황에서는 장점이 될 수 있지만, 외부에 노출되지 말아야 할 정보를 다룰 때는 오히려 취약점이 될 수 있습니다.

반면 char[]은 수동으로 데이터를 지워버릴 수 있습니다. 배열을 덮어써 버리기만 하면 기존 값은 더이상 남아있지 않게 됩니다. 

 

또한 String은 출력 가능성이 높습니다. 비밀번호를 다루는 기능을 구현하고 있다고 했을 때, 어딘가에 출력되거나 저장될 확률이 있습니다. 하지만 char[]을 사용하면 실수로 출력하더라도, 비밀번호가 직접 노출되지 않습니다. char[] 타입 변수를 출력하면 배열에 들어있는 문자가 아니라 배열의 주소가 출력되기 때문에 콘솔이나, 외부 저장소에 비밀번호가 찍혀버리는 일을 최대한 방지할 수 있다는 장점이 있습니다.

 

위와 같은 내용은 평소 생각해보지 못했던 내용인데, char[]의 새로운 활용법을 알게 되어서 좋았던 것 같습니다. 관련한 공식 문서 링크에서 자세한 내용을 확인하실 수 있고, 스택 오버플로우 글도 읽어보시는 걸 추천드립니다.

 

마무리하며

char과 String의 차이를 정리해보았습니다. 너무 기초적인 내용이라 정리할까 말까 고민했지만, 타입을 이해하는 데 도움이 되셨으면 좋겠습니다. 잘못된 정보나 피드백이 있다면 댓글 부탁드립니다. 끝까지 읽어주셔서 감사합니다. 😼

 

 

☄️ 관련 글

baeldung - char vs string

stack over flow - char[] password

java 언어 사양

geeksforgeeks - scp

 

 

'Language' 카테고리의 다른 글

스트림은 느긋하고 싶다  (2) 2024.10.13