String Class

rivermt·2023년 3월 29일
0

JAVA

목록 보기
4/9

String

변경 불가능한(immutable) 클래스

public final class String implements java.io.Serializable, Comparable {
  private char[] value;
  ...
}

한 번 생성된 String 인스턴스가 가지고 있는 문자열은 읽어 올 수 만 있고, 변경할 수 는 없다.

+ 연산자를 이용하여 문자열을 결합할 경우 인스턴스내의 문자열이 바뀌는 것이 아니라 새로운 문자열이 담긴 String 인스턴스가 생성되는 것이다.

따라서 +연산자를 사용해서 문자열을 결합하는 것은 매 연산마다 새로이 String 인스턴스를 생성하여 메모리 공간을 차지하게 되므로 가능한 한 결합횟수를 줄이는 것이 좋다.

문자열 간 결합 추출 등 문자열을 다루는 작업이 많이 필요한 경우 String 클래스 대신 StringBuffer 클래스를 사용하는 것이 좋다.

StringBuffer 인스턴스에 저장된 문자열은 변경이 가능하기 때문이다.

문자열의 비교

문자열을 만들 때는 문자열 리터럴을 지정하는 방법, String 클래스의 생성자를 사용해서 만드는 방법 이렇게 두 가지가 있다.

String str1 = "abc";							// 문자열 리터럴 "abc"의 주소가 str1에 저장됨
String str2 = "abc";							// 문자열 리터럴 "abc"의 주소가 str2에 저장됨
String str3 = new String("abc");	// 새로운 String 인스턴스 생성
String str4 = new String("abc");	// 새로운 String 인스턴스 생성

생성자를 이용한 경우 new에 의해서 메모리 할당이 이루어지고 항상 새로운 String 인스턴스가 생성된다.

그러나 문자열 리터럴은 이미 존재하는 것을 재사용한다.

  • 문자열 리터럴은 클래스가 메모리에 로드될 때 자동적으로 미리 생성된다.

equals()를 사용했을 때는 두 무자열의 내용을 비고하기 때문에 두 경우 모두 true를 결과로 얻는다.

하지만 각 String 인스턴스의 주소를 ==을 통해 비교했을 때는 결과가 다르다.

  • == 연산자는 두 개의 객체 도는 변수의 참조값이 같은지를 비교한다. 즉 두 객체나 변수가 동일한 메모리 위치를 참조하는지 비교한다.
  • 따라서 str3 == str4 의 결과가 false 가 된다. (각기 다른 인스턴스기 때문에 메모리의 위치가 다르기 때문)

문자열 리터럴

자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시 클래스 파일에 저장된다.

이때, 같은 내용의 문자열 리터럴은 한 번만 저장된다. 문자열 리터럴도 String 인스턴스이고, 한 번 생성하면 내용을 변경할 수 없으니 하나의 인스턴스를 공유하면 되기 때문이다.

클래스 파일에는 소스파일에 포함된 모든 리터럴의 목록이 있다. 해당 클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 이 리터럴의 목록에 있는 리터럴들이 JVM내에 있는 상수 저장소(constant pool)에 저장된다.

빈 문자열 (empty string)

char형 배열도 길이가 0인 배열을 생성할 수 있고, 이 배열을 내부적으로 가지고 있는 문자열이 바로 빈 문자열이다.

String s = ""; 과 같은 코드가 있을 때, 참조변수 s가 참조하고 있는 String 인스턴스는 내부에 길이가 0인 char형 배열을 저장하고 있다.

JAVA 에서는 C와 다르게 문자열 끝에 null이 붙지 않는다.

문자열은 내부적으로 char형 배열로 저장되고 , 문자열 끝은 null대신 배열의 길이로 결정된다.

일반적으로 변수를 선언할 때 String은 참조형 타입의 기본값인 null보다는 빈 문자열로 초기화 하는 것이 보통이다.

join()과 StringJoiner

join()은 여러 문자여 사이에 구분자를 넣어서 결합한다.

구분자로 문자열을 자르는 split()과 반대의 작업을 한다고 생각하면 이해하기 쉽다.

String animals = "dog,cat,bear";		
String[] arr = animals.split(",");	// 문자열을 ','를 구분자로 나눠서 배열에 저장
String str = String.join("-", arr); // 배열의 문자열을 '-'로 구분해서 결합
// 결과 : str = "dog-cat-bear"

StringJoiner을 사용하는 예제는 다음과 같다.

StringJoiner sj = new StringJoiner(",", "[", "]");
String[] strArr = {"aaa", "bbb", "ccc"};

for(String s : strArr){
  sj.add(s.toUpperCase());
}
//결과 : [AAA, BBB, CCC]

문자열과 인코딩 변환

getBytes(String charsetName)을 사용하면, 문자열의 문자 인코딩을 변경할 수 있다.

자바는 UTF-16을 사용하지만, 문자열 리터럴에 포함되는 문자들은 OS의 인코딩을 사용한다. 한글 윈도우즈의 경우 문자 인코딩으로 CP949를 사용하며, UTF-8로 변경하려면 다음과 같이 해야한다.

byte[] utf8_str = "가".getBytes("UTF-8");		// 문자열을 UTF_8로 변환
String str = new String(utf8_str, "UTF-8"); // byte 배열을 문자열로 변환

기본형 값을 String으로 변환

숫자에 빈 문자열 ""을 더해주거나 valueOf()을 사용하면 된다. 이때 성능은 valueOf()가 더 좋다고 한다.

valueOf() 메서드는 내부적으로 미리 생성된 StringBuilder 객체를 사용하여 문자열을 생성한다.

StringBuffer와 StringBuilder

StringBuffer 클래스는 내부적으로 문자열 편집을 위한 버퍼를 가지고 있으며 인스턴스를 생성할 때 그 크기를 지정할 수 있다.

String 클래스와 다르게 문자열 변경이 가능하다.

StringBuffer의 생성자

StringBuffer 클래스의 인스턴스를 생성할 때, 적절한 크기의 char형 배열이 생성되고, 이 배열은 문자열을 저장하고 편집하기 위한 버퍼로 사용된다.

만일 버퍼의 크기가 작업하려는 문자열의 길이보다 작을 때는 내부적으로 버퍼의 크기를 증가시키는 작업이 수행된다.

이때, 배열의 길이는 변경될 수 없어서 새로운 길이의 배열을 생성한 후 이전 배열의 값을 복사하게 된다.

StringBuilder

StringBuffer쓰레드 세이프하도록 구현되어 있어, 여러 쓰레드에서 동시에 접근하더라도 안전하게 사용할 수 있다고 한다.

하지만 동기화 과정이 성능을 떨어트리게 된다.

StringBuilderStringBuffer에서 동기화만 빼고 완전히 똑같은 기능으로 작성되어 있다.

profile
화이팅!!

0개의 댓글