Java9이전에는 내부적으로 유니코드중 하나인 UTF-16을 사용하기때문에 모든문자는 2바이트로 구성됩니다.
2바이트로 구성되었던 이유는 영문,숫자,특수문자를 표현하는 아스키코드는 1바이트로 표현이 가능했지만,
한글,한자 뿐아니라 세계적인 언어들을 사용하기위해서는 1바이트(8bit) 인 2^8 = 256 자로 전부 표현할수없게되어
자바에서는 유니코드를 사용합니다.
Java의 String은 내부적으로 문자를포함하는 char[]로 표현되었었고
String str = "abc";는 사실상 아래와 같습니다
char data[] ={'a', 'b', 'c'};
String str = new String(data);
그런데 String은 항상 2바이트가 필요한것은 아닙니다.
한문자만 필요한경우에는 1바이트만 제공해도 문제가없기때문에 자바9에서는 문자열을 최적화 하게되었습니다.
문자표현방식중 LATIN-1, UTF-16표현이 있는데 전자는 1바이트를 제공하게되고 후자는 2바이트를 제공하게됩니다.
자바9 이전에는 내부적으로 UTF-16만을 사용하여 모든문자가 2바이트로 구성되었지만
(JDK6에서 문자열 최적화하는 VM옵션이있었지만 의도치않은 성능결과로인해 JDK7에서 사라지긴했습니다)
자바9이후로는 LATIN-1표현을 사용하여 char[]가아닌 byte[]로 문자열을 저장하게 됩니다.
String 클래스를 조금 살펴보겠습니다
private final byte coder; // 인코딩방식 (LATIN-1, UTF-16)을 저장
String 클래스에는 coder라는 필드값이 존재하는데 위에서말한 인코딩방식(LATIN-1, UTF-16)을 식별하기위한 필드값입니다
기본적으로 문자열 최적화한다는 의미인 COMPACT_STRINGS값을 true로 주면서
문자열최적화가 디폴트값임을 알수있습니다
새 String을 할당할때에도 COMPACT_STRINGS이 맞다면 LATIN(1바이트)방식을 사용하여 인코딩방식과 값을 저장합니다
=> 기본값인 COMPACT_STRINGS 이 true이므로, 기본문자표현방식이 LATIN1임을 알수있습니다.
문자열의 길이를 구할때도 문자열의 유니코드단위수에 따라서 정해집니다
위의 indexOf()에서는 coder값을 확인후 그에 걸맞는 방식으로 내부로직을 수행합니다.
indexOf() 뿐아니라 charAt(), startsWith(),indexOf()등등 수많은 메서드에서 위와비슷한 흐름으로 진행됩니다
String a = new String("abcde"); // LATIN-1 문자표현식을 사용해도 충분하다. byte[]가 생성되어 저장된다
String b = new String("ab€€€"); // LATIN-1 문자표현식으로 €문자를 표현할수없다. 자바는 이때 UTF-16을 사용한다 char[]가 생성되어 저장된다
자바9 이전에는 String에서 1바이트만 필요한경우에도 UTF-16 문자표현방식으로 2바이트를 제공했지만, 자바 9이후로는 LATIN-1표현을 사용하여 char[]가 아닌 byte[]로 문자열을 저장한다. 메모리소비와 성능을 조금더 최적화 했다고 볼수있다.