기존의 다른 언어는 문자열을 char형의 배열로 다루었으나 자바는 String 클래스를 제공한다.
public final class String {
private final byte[] value;
...
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
this.coder = "".coder;
}
/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*/
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
String 클래스에는 문자열을 저장하기 위해서 문자형 배열 참조변수(char[]) value를 인스턴스 변수로 정의해놓고 있다. 인스턴스 생성 시 생성자의 매개변수로 입력받는 문자열은 이 인스턴스변수(value)에 문자형 배열 (char[])로 저장되는 것이다.
String 클래스는 앞에
final
이 붙어 있으므로 다른 클래스의 조상이 될 수 없다.
한번 생성된 String 인스턴스가 갖고 있는 문자열은 읽어 올 수만 있고, 변경은 할 수 없다.
예를 들어 '+' 연산자를 이용해 문자열을 결합하는 경우에도 문자열이 바뀌는 것이 아니라 새로운 인스턴스가 생기는 것이다. 따라서 문자열 연산 시마다 새로운 인스턴스로 메모리 공간을 차지하게 되므로 가능한 결합횟수를 줄이는 것이 좋다.
문자열간의 결합이나 추출 등 문자열을 다루는 작업이 많이 필요한 경우에는 String 클래스 대신 StringBuffer
클래스를 사용하는 것이 좋다. StringBuffer
인스턴스에 저장된 문자열은 변경이 가능하니 하나의 인스턴스만으로 문자열을 다루는 것이 가능하다.
String은 두가지 방법으로 생성이 가능하다.
String str1 = "hoon";
String str2 = "hoon";
String str3 = new String("hoon");
String str4 = new String("hoon");
String 클래스의 생성자를 이용하는 경우에는 New 연산자에 의해서 메모리할당이 이루어지기 때문에 항상 새로운 String 인스턴스가 생성된다. 하지만 문자열 리터럴은 이미 존재하는 것을 재사용하는 것이다.
자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다. 이 때 같은 내용의 문자열 리터럴은 한번만 저장된다. 문자열 리터럴도 String 인스턴스고, 한번 생성하면 내용을 변경할 수 없으니 하나의 인스턴스를 공유하면 되기 때문이다.
해당 클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 이 리터럴의 목록에 있는 리터럴들이 JVM 내에 있는 상수 저장소 (constant pool)에 저장된다.
참고로 String Constant Pool은 기존에는 method area의 상수값 전용 메모리에 (Perm 영역) 따로 저장되어졌는데, 런타임중 메모리 증가로 인한 OutOfMemory 예외를 발생시킬 수 있어 Java7 이후로는 객체와 함께 Heap 메모리영역에서 관리하고 있다.
💡 빈 문자열
- 변수를 선언할 때, String은 참조형 타입이지만 null이 아닌 빈 문자열로 초기화 된다.
String s = "";
에서 참조 변수 s는new char[0]
인스턴스의 주소를 저장하고 있다.
charAt(int)
: 문자 추출, 인덱스는 0부터 시작String a = "훈이야 안녕";
char c = a.charAt(0);
System.out.println(c);
//result
훈
indexOf()
: 문자열 안에서 단어가 시작하는 인덱스 찾기String a = "훈이야 안녕";
System.out.println(a.indexOf("훈이"));
System.out.println(a.indexOf("짱구"));
//result
0
-1
length()
: 글자수, 빈 공간 포함trim()
: 앞 뒤 공백 잘라냄 String trim = " hoon ";
System.out.println(trim + trim.length());
System.out.println(trim.trim() + trim.trim().length());
//result
hoon 9
hoon4
split()
: 문자열을 단어들로 분리할 수 있다. String 배열로 반환한다.String[] tokens = "I am a bot".split(" ");
for (String token : tokens) {
System.out.println("token = " + token);
}
//출력
token = I
token = am
token = a
token = bot
valueOf()
: 기본 타입값을 문자열로 전환 (boolean, char, int, long, double, float)'그만'이라 입력할 때까지 단어 갯수 세기
import java.util.Scanner;
public class StringTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
String input = sc.nextLine();
if (input.equals("그만")) {
break;
}
String[] tokens = input.split(" ");
int result = tokens.length;
System.out.println(input + " " + result);
}
}
}