[java] String 클래스와 StringBuffer

2023. 2. 9. 01:18· 책/Java의 정석
목차
  1. StringBffer
  2. 추가적으로 ~ StringBuilder 살짝 말하면
반응형

(클래스로더 공부해서 좀 더 추가하기)

C언어에서는 문자열을 char형의 배열로 다루었으나 Java에서는 문자열을 위한 String클래스를 제공한다.

  • String클래스는 문자열을 저장하고 이를 다루는데 필요한 메서드도 함께 제공
  • 변경 불가능한(immutable) 클래스이다.
    • 변경이 불가능한 클래스로 자바에서 불변 클래스의 종류로는 대표적으로 String, Boolean, Integer, Float, Long 등이 있다.

 

String클래스에는 문자열을 저장하기 위해서 문자형 배열 참조변수(byte[]) value를 인스턴스 변수로 정의해놓고 있다.

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
/*
@Stable값이 변경되지 않고 정확히 동일한 값을 반환한다고 컴파일러에 알리는 주석입니다.
이것은 항상 정적인 함수나 값에만 적용되어야 합니다.
*/
  • 인스턴스 생성 시 생성자의 매개변수로 입력받는 문자열은 이 인스턴스변수(value)에 문자형 배열(byte[])로 저장되는 것이다.
💡 String클래스는 앞에 final이 붙어 있으므로 다른 클래스의 부모가 될 수 없다. (상속 불가)

변경 불가능한(immutable) 클래스라고 말한 이유!!!

  • 한번 생성된 String인스턴스가 갖고 있는 문자열은 읽어 올 수만 있고, 변경할 수는 없다.
String str = "a";
str += 'b';

‘+’연산자를 이용해서 문자열을 결합한 경우 인스턴스 내의 문자열이 바뀌는 것이 아니라 새로운 문자열(”ab”)이 담긴 String인스턴스가 생성되는 것이다.

  • ‘+’연산자를 사용해서 문자열을 결합하는 것은 매 연산 시 마다 새로운 문자열을 가진 String인스턴스가 생성되어 메모리 공간을 차지하게 되므로 가능한 결합횟수를 줄이는 것이 좋다.
  • 문자열 간의 결합이나 추출등 문자열을 다루는 작업이 많이 필요한 경우는?
    • String클래스 대신 StringBuffer클래스를 사용하자
    • StringBuffer인스턴스에 저장된 문자열은 변경이 가능해 하나의 StringBuffer인스턴스만으로 문자열을 다루는 것이 가능하다.

 

문자열(String)의 비교

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

Stirng str1 = "abc";
String str2 = new String("abc");
  • String클래스의 생성자를 이용한 경우 new연산자에 의해서 메모리할당이 이루어지면서 항상 새로운 String인스턴스가 생성된다.
  • 문자열 리터럴은 이미 존재하는 것을 재사용하는 것이다.
public static void main(String[] args) {
String str1 = "abc";
String str2 = new String("abc");
String str3 = "abc";
String str4 = new String("abc");
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
System.out.println(System.identityHashCode(str3));
System.out.println(System.identityHashCode(str4));
}
/* 출력
453211571
796684896
453211571
757108857
*/

str1, str3은 “abc”가 저장되어 있는 메모리주소를 참조 (453211571번지)

str2, str4은 new연산자에 의해서 메모리할당이 이루어지면서 항상 새로운 객체의 주소를 참조변수가 참조한다.

  • equals()를 사용하면 String에서 오버라이딩 했기 때문에 값만 비교하므로 전부 “abc” → true
  • String인스턴스의 주소를 등가비교연산자 ‘==’로 비교했을 때는 결과가 다르다.
  • System.*out*.println(str1 == str3 ? true : false); → true
  • System.*out*.println(str2 == str4 ? true : false); → false

 

문자열 리터럴(String리터럴)

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

  • 같은 내용의 문자열 리터럴은 한번만 저장된다.
  • 문자열 리터럴도 String인스턴스이고, 한번 생성하면 내용을 변경할 수 없으니 하나의 인스턴스를 공유하면 되기 때문이다.
public static void main(String[] args) {
Scanner s1 = new Scanner(System.in);
String str1 = "abc";
String str2 = s1.nextLine();
String str3 = "a"+"bc";
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
System.out.println(System.identityHashCode(str3));
}
/* 출력
abc -> 사용자 입력
abc
abc
abc
356473385 "abc"
2136344592
356473385 "a" + "bc"
*/
  • ‘+’연산자를 사용해서 문자열을 결합하는 것은 매 연산 시 마다 새로운 문자열을 가진 String인스턴스가 생성되어 메모리 공간을 차지하게 되니까 달라질거라고 생각했는데 같은 내용의 문자열 리터럴은 한번만 저장되니까 컴파일 때 찾아서 하나만 저장하는거 같다.
  • scanner통해서 받으면 컴파일 이후 사용자 입력이 들어오면 그 때 채워지는걸로 알고 있어서 해봤는데 (C언어 링킹과정 느낌 아닐 수 있음) 생각해보니.. 리터럴도 아니고 Scanner클래스에서 받아오는거니까 당연히 아닌…
Scanner 보다는 성능상의 이유로 BufferedReader 사용하는 것이 좋다.

컴파일 → 클래스 파일 생성

클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 클래스 파일의 리터럴들이 JVM내에 있는 ‘상수 저장소(constant pool)’에 저장된다. (클래스 로더 공부해서 올려볼게요..)

 

빈 문자열(empty String)

public static void main(String[] args) {
char[] test = new char[0];
//길이가 0인 배열을 생성할 수 있다.
int[] test1 = {};
}

길이가 0인 배열을 내부적으로 가지고 있는 문자열이 바로 빈 문자열이다.

💡String str = "";   참조변수 s가 참조하고 있는 String인스턴스는 내부에 ‘new char[0]’과 같이 길이가 0인 char형 배열을 저장하고 있는 것이다.
String s = ""; //빈 문자열로 초기화 (Stirng s = null;)
char c = ''; //(x)char형 변수에는 반드시 하나의 문자를 지정해야 한다.
char c = ' '; //(O)공백은 가능하다.(char c = '\\u0000';
  • 변수를 선언할 때, 각 타입의 기본값으로 초기화 하지만 String은 참조형 타입의 기본값인 null 보다는 빈 문자열로, char형은 기본값인 ‘\u0000’대신 공백으로 초기화 하는것이 보통이다.

 

join()과 StringJoiner

join()은 여러 문자열 사이에 구분자를 넣어서 결합한다. (구분자로 문자열을 가르는 split()과 반대 작업으로 이해)

public static void main(String[] args) {
String books = "자바의정석,클린코드,DDD,TDD";
String[] arr = books.split(","); //,구분자를 통해서 배열에 하나씩 넣음
String str = String.join("-",arr); // 배열하나 꺼내고 구분자 넣고 배열꺼내고
System.out.println(str);
}
// 자바의정석-클린코드-DDD-TDD

java.util.StringJoiner클래스로 문자열 결합

public static void main(String[] args) {
StringJoiner sj = new StringJoiner(",","[","]");
String[] books = { "자바의정석","클린코드","DDD","TDD" };
for (String s : books){
sj.add(s); //add(s.toUpperCase())사용 가능
}
System.out.println(sj); //[자바의정석,클린코드,DDD,TDD]
}

join(),StringJoiner클래스는 JDK1.8부터 추가

 

 

 

String클래스 자주사용하는 메서드 조그만.... 너무많..

메서드 설명
char charAt(int index) 문자열에서 해당 위치(index)에 있는 문자를 반환
int length() 문자열의 길이를 반환
String substring(int 원하는 시작 인덱스, int 원하는 마지막 인덱스 문자열에서 내가 지정한 범위의 문자열을 반환(원하는 마지막 인덱스 문자는 반환 안된다)
boolean equals(Object obj) 문자열의 내용이 같은지 확인(같으면 true, 틀리면 false)
char[] toCharArray() 문자열을 문자배열(char[])로 변환해서 반환

 


StringBffer

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

  • String은 인스턴스 생성하고 문자열 변경 불가
  • 편집할 문자열의 길이를 고려하여 버퍼의 길이를 충분히 잡아주는 것이 좋다.
    • 문자열이 버퍼의 길이를 넘으면 버퍼의 길이를 늘려주는 작업이 추가로 수행되기 때문
  • StringBuffer클래스도 문자열을 저장하기 위한 char형 배열의 참조변수를 인스턴스 변수로 선언해 놓음

즉 StringBuffer클래스의 인스턴스 생성할 때, 적절한 길의의 char형 배열이 생성되고, 이 배열은 문자열을 저장하고 편집하기 위한 공간(buffer)으로 사용된다.

💡 StringBuffer인스턴스 생성할 때, 버퍼의 크기를 지정해주지 않으면 16개의 문자를 저장할 수 있는 크기의 버퍼를 생성한다.

 

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

  • 배열의 길이는 변경될 수 없으므로 새로운 길이의 배열을 생성한 후에 이전 배열의 값을 복사해야 한다.
//새로운 길이(newCapacity)의 배열을 생성한다. newCapacity는 정수값
char[] newValue = new char[newCapacity];
// 배열 value의 내용을 배열 newValue로 복사한다.
System.arraycopy(value,0,newValue,0,count);//count는 문자열의 길이
value = newValue //새로 생성된 배열의 주소를 참조변수 value에 저장.
  • StringBuffer클래스의 인스턴스 변수 value는 길이가 증가된 새로운 배열을 참조하게 된다.

System.arraycopy

System.arraycopy( 배열1, 배열1의 복사시작번호, 배열2, 배열2의 복사시작번호, 복사길이)의 형태를 띈다.
예제)
A={a, b, c, d, e};
B={가, 나, 다, 라};
System.arraycopy(A, 1, B, 3, 2); //A[1]부터 B[3]에 길이 2만큼 복사된다는 의미다.
B[3]=A[1] //B[3]에 A[1]의 값이 복사됨
B[4]=A[2] //길이가 2니까 그 다음 값인 B[4]에 A[2]
B={ B[0], B[1], B[2], A[1], A[2] }; //배열값은 { 가, 나, 다, b, c }가 된다.

한국말을 못해서 죄송합니다.. 그래도 예제 보면 이해할 수 있을거라고 생각합니다. >_<

 

 

StringBuffer의 변경 - append()

매개변수로 입력된 값(숫자,boolean)들도 문자열로 변환하여 StringBuffer인스턴스가 저장하고 있는 문자열 뒤에 덧붙인다.

StringBuffer sb = new StringBuffer("java");
sb.append("의"); //반환타입이 StringBuffer인데 자신의 주소를 반환
StringBuffer sb2 = sb.append(" ").append("정석");
//sb.append == sb 이기 때문에 연속적으로 append()를 호출하는것이 가능하다.
System.out.println("sb = " + sb);
System.out.println("sb2 = " + sb2); //sb와 같은 인스턴스라 출력이 동일하다.
💡 StringBuffer클래스에는 append()처럼 객체 자신을 반환하는 메서드들이 많이 있다.

 

StringBuffer의 비교

String클래스에서는 equals메서드를 오버라이딩해서 문자열의 내용을 비교하도록 구현되어 있지만 StringBuffer클래스는 equals메서드를 오버라이딩하지 않았다.

StringBuffer sb = new StringBuffer("abc");
String sb1 = sb.toString();
String sb2 = sb.toString();
System.out.println(sb1.equals(sb2)); //true 반환
  • StringBuffer클래스는 equals메서드를 사용해도 등가비교연산자(==)로 비교한 것과 같은 결과를 얻는다.
  • toString()은 오버라이딩 되어 있어 담고있는 문자열을 String으로 반환한다.
  • 비교할 때는 toString으로 String인스턴스를 얻은 다음 equlas메서드를 사용해서 비교해야 한다.

추가적으로 ~ StringBuilder 살짝 말하면

멀티쓰레드에 안전(thread safe)하도록 동기화되어 있다. (동기화 → StringBuffer의 성능 떨어뜨림)

  • 멀티쓰레드로 작성된 프로그램이 아닌 경우, StringBuffer의 동기화는 불필요하게 성능만 떨어뜨린다.
    • StringBuffer에서 쓰레드의 동기화만 뺀 StringBuilder 나온이유

StringBuilder는 StringBuffer와 완전히 똑같은 기능으로 작성되어 있다.

💡 성능향상이 반드시 필요한 경우를 제외하고는 기존에 작성한 코드에서 StringBuffer를 StringBuilder로 굳이 바꿀 필요는 없다.
반응형
저작자표시 비영리 변경금지 (새창열림)

'책 > Java의 정석' 카테고리의 다른 글

[java] 래퍼(wrapper)클래스 && Number클래스  (0) 2023.02.10
[java] Object클래스  (0) 2023.02.09
[java] 예외처리(3)  (1) 2023.02.07
[java] 예외처리(2)  (0) 2023.02.07
[java] 예외처리(1)  (1) 2023.02.07
  1. StringBffer
  2. 추가적으로 ~ StringBuilder 살짝 말하면
'책/Java의 정석' 카테고리의 다른 글
  • [java] 래퍼(wrapper)클래스 && Number클래스
  • [java] Object클래스
  • [java] 예외처리(3)
  • [java] 예외처리(2)
uhanuu
uhanuu
uhanuu
몸뚱아리부터 마음가짐까지
uhanuu
전체
오늘
어제
  • 분류 전체보기 (127)
    • 개발 (14)
      • Spring Boot (8)
      • 첫 번째 프로젝트 (4)
      • 코테 & 알고리즘 공부 (2)
      • Git (2)
    • 책 (57)
      • Java 언어로 배우는 디자인 패턴 입문 (6)
      • Java의 정석 (22)
      • SQL 첫걸음 (8)
      • 이펙티브 자바 (4)
      • 모던 자바 인 액션 (11)
      • 카프카 핵심 가이드 (6)
    • CS (4)
      • 컴퓨터 구조 (1)
      • 운영체제 (3)
    • Java (5)
    • DB (3)
    • Web (8)
    • 일상 정리 (0)
    • 클라우드 (4)
    • vue (2)
    • Kafka (4)
    • Reactive Programming (7)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Kafka
  • Producer

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.0
uhanuu
[java] String 클래스와 StringBuffer
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.