[Java] String 클래스

JTI·2022년 12월 1일
0

☕️  Java

목록 보기
33/59
post-thumbnail

💡 java.lang.String 클래스


✔️ 문자배열
: 문자열을 다루기 위한 클래스

  • 데이터(char[]) + 메서드(문자열 관련)

C언어에서는 문자열을 char형 배열로 표현하지만, 자바에서는 문자열을 위한 String이라는 클래스를 별도로 제공한다.

String 클래스에는 문자열과 관련된 작업을 할 때 유용하게 사용할 수 있는 다양한 메소드가 포함되어 있으며 이러한 String 클래스는 java.lang 패키지에 포함되어 제공된다.

❗️불변 객체(immutable object)

  • String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없다.
  • 덧셈(+) 연산자를 이용하여 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아니라 내용이 합쳐진 새로운 String 인스턴스가 생성된다.

그래서 덧셈 연사자(+)를 이용한 문자열 결합은 계속해서 해로운 인스턴스를 생성하기 때문에 성능이 떨어진다.

문자열의 결합이나 변경이 잦다면, 내용을 변경가능한 StringBuffer를 사용해야 한다.

✏️ 문자열의 비교


이 두 식을 비교해보자.

String str = "abc";
String str = new String("abc");

String str1 = "abc"; // 문자열 리터럴 "abc"의 주소가 str1에 저장됨
String str2 = "abc"; // 문자열 리터럴 "abc"의 주소가 str2에 저장됨

String str3 = new String("abc");// 새로운 String인스턴스를 생성
String str4 = new String("abc");// 새로운 String인스턴스를 생성


String literal로 생성한 객체는 내용이 같다면 같은 객체, 즉 동일한 메모리 주소를 가리키고 있다.

하지만 new 연산자로 생성한 String 객체는 내용이 같더라도 개별적인 객체임을 알 수 있다.

여기에는 어떤 원리가 숨어있는지, 밑의 JVM 구조와 함께 이해해 보도록 하자.

❗️ ' == ' 가 아닌 equals() 를 통해 내용을 비교

== 은 주소값을 비교한다.

  • String literal은 같은 주소값을 가지고 있으므로 True 가 나온다.
  • new 연산자로 생성한 String 객체는 다른 주소값을 나타내기 때문에 False 가 나온다.

💦 String Pool



new 연산자로 String 객체를 생성하지 않는 것이 좋다는 말을 자주 한다.

그 이유는, String literal로 생성하면 해당 String 값은 Heap 영역 내 String Constant Pool에 저장되어 재사용되지만, new 연산자로 생성하면 같은 내용이라도 여러 개의 객체가 각각 Heap 영역을 차지하기 때문이다.

(그림에는 생략되어 있지만) 생성된 String 객체는 Stack 영역에 저장된다.

Heap 영역에는 "Cat", "Dog"과 같은 '값'들이 들어가게 되는데, 그림의 우측을 보면 중요한 차이를 발견할 수 있다.

  • String literal로 생성한 객체는 String Pool에 들어간다.

  • String literal로 생성한 객체의 값(ex. "Cat")이 이미 String Pool에 존재한다면, 해당 객체는 String Pool의 reference를 참조한다. 그림에서 s1과 s2가 같은 곳을 가리키고 있는 것도 이 때문이다.

  • new 연산자로 생성한 String 객체는 같은 값이 String Pool에 이미 존재하더라도, Heap영역 내 별도의 객체를 가리키게 된다.

💡 빈 문자열 ("", empty string)


  • 내용이 없는 문자열. 크기가 0인 char형 배열을 저장하는 문자열이다.
String str = ""; // Str을 빈 문자열로 초기화
  • 크기가 0인 배열을 생성하는 것은 어느 타입이나 가능하다.
char[] chArr = new char[0]; // 크기가 0인 char배열
int[] iArr = {}; // 크기가 0인 int배열
  • 문자(char)와 문자열(String)의 초기화
String s = null; // 별로
char c = '\u000'; // 별로

String s = ""; // 빈 문자열로 초기화
char c = ' '; // 공백으로 초기화
  • 좋은 코드
String str1 = ""; // String str1 = new String(""); X
String str2 = ""; // String str2 = new String(""); X
String str3 = ""; // String str3 = new String(""); X

💡String 클래스의 생성자


✏️ String(char[] value)

  • 주어진 문자열(value)을 갖는 String 인스턴스를 생성한다.
char[] c = {'H','e','l','l','o'};

String s = new String(c); // Hello

반대로 String을 char로 바꿀때는 toCharArray() 를 쓴다.

✏️ String(StringBuffer buf)

  • StringBuffer (내용변경 가능한 문자열) 인스턴스가 갖고 있는 문자열과 같은 내용의 String 인스턴스를 생성한다.

  • StringBuffer ➡️ String

StringBuffer sb = new StringBuffer("Hello");

String s = new String(sb);// Hello

💡 String 클래스의 메서드


✏️ char charAt(int index)

  • 지정된 위치(Index)에 있는 문자를 알려준다.
  • 만약 해당 문자열의 길이보다 큰 인덱스나 음수를 전달하면, IndexOutOfBoundsException 오류가 발생한다.

✔️ 예제1

String s = "Hello";
String n = "0123456"

char c = s.charAt(1); // e
char c2 = n.charAt(1); // 1

✔️ 예제2

String str = new String("Java");
System.out.println("원본 문자열 : " + str);

for (int i = 0; i < str.length(); i++) {
    System.out.print(str.charAt(i) + " ");
}

System.out.println("\ncharAt() 메소드 호출 후 원본 문자열 : " + str);
[결과값]
원본 문자열 : Java
J a v a 
charAt() 메소드 호출 후 원본 문자열 : Java

✏️ int compareTo(String str)

  • 문자열(str)과 사전순서로 비교한다.
  • 같으면 0, 사전순으로 이전이면 음수, 이후면 양수를 반환한다.

    ❗️ 만약 문자열을 비교할 때 대소문자를 구분하지 않기를 원한다면, compareToIgnoreCase() 메서드를 사용하자.

✔️ 예제1

int i = "aaa".compareTo("aaa"); // 0
int i2 = "aaa".compareTo("bbb"); // -1
int i3 = "bbb".compareTo("aaa"); // 1

✔️ 예제2

String str = new String("abcd");
System.out.println("원본 문자열 : " + str);

System.out.println(str.compareTo("bcef"));
System.out.println(str.compareTo("abcd") + "\n");

System.out.println(str.compareTo("Abcd"));
System.out.println(str.compareToIgnoreCase("Abcd"));

System.out.println("compareTo() 메서드 호출 후 원본 문자열 : " + str);

✏️ String concat(String str)

  • 문자열(str)을 뒤에 덧붙인다.
  • 만약 인수로 전달된 문자열의 길이가 0이면, 해당 문자열을 그대로 반환한다.

✔️ 예제1

String s = "Hello";

String s1 = s.concat(" World"); // Hello World

✔️ 예제2

String str = new String("Java");
System.out.println("원본 문자열 : " + str);

System.out.println(str.concat("수업"));
System.out.println("concat() 메소드 호출 후 원본 문자열 : " + str);
[결과값]
원본 문자열 : Java
Java수업
concat() 메소드 호출 후 원본 문자열 : Java

✏️ boolean contains(CharSequence s)

  • 지정된 문자열(s)이 포함되었는지 검사한다.
String s = "abcdefg";

boolean b = s.contains("bc"); // true

❗️ interface CharSequence 을 구현한 class들
: CharBuffer, Segment, String, StringBuffer, StringBuilder

✏️ boolean startsWith(String prefix)

  • 주어진 문자열(prefix)로 시작하는지 검사한다.
String s = "java.lang.Object";

boolean b = s.startsWith("java"); // true
boolean b2 = s.starsWith("lang"); // false

✏️ boolean endsWith(String suffix)

  • 지정된 문자열(suffix)로 끝나는지 검사한다.
String file = "Hello txt";

boolean b = file.endsWith("txt"); // true

✏️ boolean equalsIgnoreCase(String str)

  • 문자열과 String 인스턴스의 문자열을 대소문자 구분없이 비교한다.
String s = "Hello";

boolean b = s.equalsIgnoreCase("HELLO"); // true
boolean b2 = s.equalsIgnoreCase("hello"); // true

✏️ int indexOf(int char)

  • 주어진 문자(char)가 문자열에 존재하는지 확인하여 위치(index)를 알려준다.
  • 못찾으면 -1을 반환한다.
String s = "Hello";

int idx1 = s.indexOf('o'); // 4
int idx2 = s.indexOf('k'); // -1

✏️ int indexOf(int char, int pos)

  • 주어진 문자(char)가 문자열에 존재하는지 지정된 위치(pos)부터 확인하여 위치(index)를 알려준다.
  • 못찾으면 -1을 반환한다.
String s = "Hello";

int idx1 = s.indexOf('e', 0); // 1
int idx2 = s.indexOf('e', 2); // -1 index가 2인 'l'을 시작기점으로 'e'를 찾음

✏️ int lastIndexOf(int ch)

  • 지정된 문자 또는 문자코드를 문자열의 오른쪽끝에서부터 찾아서 위치(index)를 알려준다.
  • 못찾으면 -1을 반환한다.
String s = "java.lang.Object"

int idx1 = s.lastIndexOf('.'); // 9 
int idx2 = s.indexOf('.'); // 4

s.lastIndexOf('.') 의 조심해야할 점은, 인덱스의 번호는 고정이기 때문에 뒤에서 셀때에 0부터 세면 안된다. s의 길이인 15부터 거꾸로 세야한다.

15(t) ,14(c) ,13(e), 12(j), 11(b), 10(O) ,9(.) ...

✏️ String[] split(String regex)

❗️ regex
: Regular Expression ➡️ 규칙이 있는 식 (정규식)

  • 문자열을 지정된 분리자(regex)로 나누어 문자열 배열에 담아 반환한다.
String animals = "dog,cat,bear";

String[] arr = animals.split(",");

// arr[0] = "dog"
// arr[1] = "cat"
// arr[2] = "bear"

✏️ String[] split(String regex, int limit)

  • 문자열을 지정된 분리자(regex) 로 나누어 문자열배열에 담아 반환한다.
  • 문자열 전체를 지정된 수(limit) 로 자른다.
String animals = "dog,cat,bear";

String[] arr = animals.split(",", 2); // 두 부분으로 나눈다.

//arr[0] = "dog"
//arr[1] = "cat,bear"

✏️ String substring(int begin) / (int begin, int end)

  • 주어진 시작위치(begin) 부터 끝 위치(end) 범위에 포함된 문자열을 얻는다.
  • 이때, 시작위치의 문자는 범위에 포함되지만, 끝 위치의 문자는 포함되지 않는다.

    ❗️ begin <= x < end

String s = "java.lang.Object";

String c = s.substring(10); // Object
String p = s.substring(5, 9) // lang

✏️ String toLowerCase()

  • String 인스턴스에 저장되어있는 모든 문자열을 소문자로 변환하여 반환한다.
String s = "Hello";

String s1 = s.toLowerCase(); // hello

✏️ String toUpperCase()

  • String 인스턴스에 저장되어있는 모든 문자열을 대문자로 변환하여 반환한다.
String s = "Hello";

String s1 = s.toUpperCase(); // HELLO

✏️ String trim()

  • 문자열의 왼쪽 끝과 오른쪽 끝에 있는 공백을 없앤 결과를 반환한다.
  • 문자열 중간에 있는 공백은 제거되지 않는다.

✔️ 예제1

String s = "   Hello World   ";

String s1 = s.trim() // Hello World

✔️ 예제2

String str = new String(" Java     ");
System.out.println("원본 문자열 : " + str);

System.out.println(str + '|');
System.out.println(str.trim() + '|');
System.out.println("trim() 메소드 호출 후 원본 문자열 : " + str);
[결과값]
원본 문자열 :  Java
  Java        |
Java|
trim() 메소드 호출 후 원본 문자열 :  Java

✏️ static String valueOf()

  • 파라미터 안에는 boolean, char, int, float, double, Object 다 가능하다.
  • 지정된 값을 문자열로 변환하여 반환한다.
  • 참조변수의 경우, toString() 을 호출한 결과를 반환한다.
String b = String.valueOf(true); // "true"
String c = String.valueOf('a'); // "a"

java.util.Date dd = new java.util.Date();
String date = String.valueOf(dd); // "Wed Jan 27 21:26:29 KST 2022"

References
: https://starkying.tistory.com/entry/what-is-java-string-pool
: https://cafe.naver.com/javachobostudy

profile
Fill in my own colorful colors🎨

0개의 댓글