[F-Lab 모각코 챌린지 1일차] String
String 클래스
String 클래스는 자바에서 정말 많이 사용하는 클래스이다.
클래스 중에서 더하기 연산(+)을 제공하는 클래스는 String 밖에 없다. 일반적인 객체에도 더하기 연산이 가능하지 않나? 일반적인 객체에 더하기 연산이 되는 것은
toString()메소드가 호출되는 것이지 더하기 연산을 제공하는 것은 아니다.String 클래스의 선언부를 살펴보자.
final키워드가 쓰인 것을 확인할 수 있다. 따라서 String 클래스는 자식 클래스를 만들 수 없다.String 클래스는
Serializable,Comparable,CharSequence인터페이스를 구현하고 있다.public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // 내용생략 }
String 클래스의 생성자들
String(byte[] bytes) // 1
String(byte[] bytes, charsetName) // 2
- String 생성자는 엄청 많은데 그 중 많이 사용되는 생성자만 알아보자. 1번째 생성자는 현재 사용 중인 플랫폼의 캐릭터 셋을 사용하여 제공된 byte 배열을 디코딩한 String 객체이다. 2번째 생성자는 지정한 이름을 갖는 캐릭터 셋을 사용하여 지정한 byte 배열을 디코딩한 String 객체이다.
- 생성자의 매개변수로 받는 byte 배열은 어떻게 생성할까? String 클래스는 현재 문자열을 byte 배열로 변환하는
getBytes()메소드를 제공한다. - 한글을 처리하기위해 자바에서 많이 사용하는 캐릭터 셋은 UTF-16이다.
- 자바에서 한글이 몇 바이트를 점유하는지 알아두는 것은 중요하다. 캐릭터 셋이 EUC-KR이면 한글 한 글자를 표현하기 위해 2바이트가 필요하고, 캐릭터 셋이 UTF-16이면 3바이트가 필요하다.
- 문자열 생성 시,
""로 생성한 것과new키워드를 사용해 생성한 것은 어떤 차이가 있을까?- String은 참조자료형이기 때문에
new키워드를 사용해서 만들 수 있다. 이때 String 타입의 객체는 일반적인 객체들과 똑같이 JVM 메모리 영역 중 heap 영역에 생성된다. - str1과 str2는 서로 다른 객체의 주소값이 저장되어있기 때문에
==연산자를 사용해 비교하면 false가 나온다. (객체끼리==연산자로 비교하면 객체의 주소 값을 가지고 비교함) - String은 일반적인 객체와 조금 다르게 취급되는데 리터럴("")을 사용해 String을 생성하면 JVM heap 영역 내에 있는 constant pool 영역에 저장된다. 이 constant pool에 저장 된 값들은 재사용이 가능하다. s1 변수에 "Cat"을 할당하면 constant pool에 "Cat"이 저장되고 s2 변수에도 "Cat"을 저장하면 constant pool에 이미 "Cat" 문자열 값이 존재하기 때문에 이미 존재하는 그 값을 참조한다.
- new 키워드로 생성한 String 객체는 constant pool에 그 값이 이미 존재한다고 하더라도 heap 영역 내 별도의 객체를 가리킨다.
- String은 참조자료형이기 때문에
String s1 = "Cat";
String s2 = "Cat";
String s3 = new String("Cat");
String s4 = "Dog";
// == 비교는 객체의 주소값을 비교
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
// equals()를 이용한 비교는 문자열 값을 비교
System.out.println(s1.eqauls(s3)); // true
문자열 비교
equals() vs ==
==연산자는 기본자료형에서는 실제 값을 비교하지만 참조자료형에서는 주소값을 비교한다.Object 클래스의
equals()메소드 역시 객체의 주소값을 비교한다.참조자료형의 인스턴스 변수값들을 비교하고 싶다면 Object 클래스의
equals()메소드를 오버라이딩해서 사용하면 된다. (오버라이딩 하지 않고 그냥equals()메소드를 사용하면 객체의 주소값(hashCode()메소드를 호출하여 리턴받은 값)을 비교하게 된다)equals()메소드를 오버라이딩 할 때, 반드시 5가지 조건을 충족시켜야한다.equals()메소드를 오버라이딩 할 때,hashcode()메소드도 같이 오버라이딩 해야한다.equals()메소드를 오버라이딩해서 두 객체가 서로 같다(인스턴스 변수값을 비교해서 그 값들이 같으면 true 리턴하도록 오버라이딩함)고 얘기할 순 있겠지만 두 객체의 주소값까지 같지는 않기 때문이다. 즉,equals()메소드의 결과가 true인데hashcode()메소드의 값은 서로 다르게 된다. 같은hashcode()메소드의 리턴값이 같도록 하려면hashcode()메소드 역시 Object 클래스에서 제공하는 그대로 사용하면 안 된다.String 클래스의
equals()메소드는 객체 주소값이 아닌 문자열 그 자체의 값을 비교하도록 오버라이딩 되어있다.String s1 = "cc"; String s2 = "cc"; System.out.println(s1.equals(s2)); // true String s3 = new String("cc"); String s4 = new String("cc"); System.out.println(aa.equals(bb)); // true(문자열 비교)
절대 사용해선 안 되는 메소드
public void internCheck() {
String s1 = "java";
String s2 = "java";
String s3 = new String("java");
s3.intern();
System.out.println(s1==s2); // true
System.out.println(s1==s3); // false를 기대했는데 intern() 메소드 때문에 true 나옴
System.out.println(s1.equals(s3)); // true
}intern()메소드는new키워드로 생성한 문자열 객체라고 할지라도 constant pool에 해당 값이 있으면 pool에 있는 값을 참조하는 객체를 리턴한다. 만약 풀에 해당 값이 없으면 그 값을 풀에 저장한다. 그래서intern()메소드 수행 후에, 문자열은==연산자로도 동일한지 비교할 수 있다.- intern() 메소드를 사용하면 시스템의 심각한 성능 저하를 발생시킬 수도 있다.
intern()메소드로 억지로 pool에 값을 할당하도록 만들면 pool에 저장되는 영역은 한계가 있기 때문에 그 영역에 대해서 별도로 메모리 청소를 해야한다.
StringBuffer와 StringBuilder

- String immutable한 객체다. 한번 만들어지면 그 값을 더이상 바꿀 수 없다. String 문자열을 더하면(+) 새로운 String 객체가 생성되고 기존 객체는 버려진다. 이 객체는 쓰레기가 되며 GC의 대상이 된다.
- 이렇게 불변한 String 클래스의 단점을 보완한 클래스가 StringBuffer와 StringBuilder다. StringBuffer는 thread safe 하고 StringBuilder는 thread safe 하지않다.(자바의신2권 진도 나간 후, 쓰레드에 대해 추가작성 할 것) 두 클래스는 문자열을 더하더라도 새 객체를 생성하지 않는다. 두 클래스가 객체를 더할 땐, (+) 기호를 사용하진 않고 append()를 사용한다.
- jdk5 이상부터 String의 더하기(+) 연산을 할 경우, 컴파일 할 때 자동으로 StringBuffer로 변환해준다.
- 하나의 메소드에서 문자열을 생성해 더할 경우엔 StringBuilder를 사용해도 상관없다. 어느 클래스에 문자열을 더하기 위해 인스턴스 변수가 선언 되었고 여러 쓰레드에서 이 변수를 동시에 접근하는 일이 있으면 반드시 StringBuffer를 사용해야만 한다.
📚참고
자바의신
https://hs-archive.tistory.com/28
https://www.digitalocean.com/community/tutorials/what-is-java-string-pool
https://www.scaler.com/topics/java/stringbuffer-in-java/
'JAVA' 카테고리의 다른 글
| [F-Lab 모각코 챌린지 6일차] equals(), hashCode() (0) | 2023.06.13 |
|---|---|
| [F-Lab 모각코 챌린지 5일차] Call by Value, Call by Reference in Java/어노테이션 (0) | 2023.06.12 |
| [F-Lab 모각코 챌린지 4일차] Garbage Collector (0) | 2023.06.11 |
| JVM 메모리 구조 (2) | 2023.06.10 |
| [F-Lab 모각코 챌린지 2일차] 자바의 구동방식/Class Loader, Nested Class (0) | 2023.06.09 |
댓글
이 글 공유하기
다른 글
-
[F-Lab 모각코 챌린지 5일차] Call by Value, Call by Reference in Java/어노테이션
[F-Lab 모각코 챌린지 5일차] Call by Value, Call by Reference in Java/어노테이션
2023.06.12 -
[F-Lab 모각코 챌린지 4일차] Garbage Collector
[F-Lab 모각코 챌린지 4일차] Garbage Collector
2023.06.11 -
JVM 메모리 구조
JVM 메모리 구조
2023.06.10 -
[F-Lab 모각코 챌린지 2일차] 자바의 구동방식/Class Loader, Nested Class
[F-Lab 모각코 챌린지 2일차] 자바의 구동방식/Class Loader, Nested Class
2023.06.09