티스토리 뷰

Java/Class

2. String Class

알 수 없는 사용자 2018. 10. 17. 02:42


이번 포스팅에서는

우리가 편리함을 모르고

사용하고 있는 String 클래스에 대해서

알아보도록 하겠습니다.


=========================================================


String Class




1. String Class : What?


 자바 프로그래밍을 처음 시작한 사람이라면 String을 기본 데이터형의 일종이라고 생각했을 수도 있습니다. 실제로 String은 문자열을 개발자가 좀 더 편리하게 생성하고 기본 데이터형처럼 관리하게 하기 위해 만들어진 객체입니다.


 실제로 문자열을 만들기 위해서는 char형의 배열로 다루어야 합니다. 문자 하나하나를 이어서 문자열로 만드는 것이죠.



자바에서도 이처럼 문자열을 char형의 배열로 만들어 다루는데 char[] 변수가 String 클래스에 멤버변수로 존재하고 이를 편리하게 다룰 수 있게 해주는 메소드를 구현해 두었습니다.

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

[ String 클래스의 char형 배열 ]


 자바를 공부하기 전에 C와 같은 다른 언어를 공부하셨다면 문자열이 만들어지는 원리를 알기 때문에 String 클래스에 더욱 감사함(?)을 느끼죠.


String도 Object 클래스와 마찬가지로 java.lang 패키지에 존재하는 클래스입니다. 때문에 String도 import 하지 않아도 사용할 수 있습니다.

또한 String은 immutable 클래스입니다. immutable은 '변경 불가능한'이라는 뜻으로 한번 생성된 String 인스턴스가 가진 문자열은 읽어 올 수만 있고, 변경할 수는 없습니다. 예를 들어, 문자열끼리의 덧셈에서 기존의 String 인스턴스가 변경되는 것이 아니라 새로운 String 인스턴스에 두 개의 문자열을 담는 것이기 때문에 메모리 측면에서 비효율적인 상황이 발생합니다.






2. String Class : How?


문자열 생성하는 법에는 두 가지 방법이 있습니다. 


첫 번째는 문자열 리터럴을 지정하는 방법입니다. 마치 int와 double과 같은 기본 데이터형처럼 사용할 수 있도록 설계되어 있습니다.

문자열 리터럴은 클래스가 메모리에 로드될 때 자동으로 미리 생성되기 때문에 만약 같은 값의 문자열을 각기 다른 두 개의 변수에 저장한다면 그 두 개의 변수는 같은 문자열 리터럴 주소를 참조하게 됩니다.

public class Source01_String {
public static void main(String[] args) {
        String c1 = "프로그램"; // 문자열 리터럴 "프로그램"의 주소가 c1에 저장됨
        String c2 = "프로그램"; // 문자열 리터럴 "프로그램"의 주소가 c2에 저장됨
        System.out.println(c1 == c2); // true

}
}



두 번째는 String 클래스의 생성자를 이용하는 방법입니다. 

일반 클래스의 객체를 생성하는 것과 같이 String에도 생성자가 정의되어 있습니다. 때문에 new 연산자를 통해서 String 객체를 생성할 수 있습니다. 이때는 new 연산자에 의해서 메모리 할당이 이루어지는 것이기 때문에 문자열의 실질적인 값은 같아도 두 개의 변수는 서로 다른 String 객체를 참조하게 됩니다.

public class Source01_String {
public static void main(String[] args) {
String s3 = new String("프로그램"); // 새로운 String 인스턴스 생성
String s4 = new String("프로그램"); // 새로운 String 인스턴스 생성
System.out.println(s3 == s4); // false
}
}






3. String Class : Method?



String 클래스에는 많은 메소드가 정의되어있습니다. 그런데... 자주 사용할만한 것들만 해도 아주 많습니다.. 

하지만 메소드 자체의 내용이 어렵진 않기 때문에 String 클래스의  API 문서를 한번 읽어보는 것이 좋습니다.


[String 클래스에 정의된 생성자]


생성자만 해도 이렇게 많습니다.. 

솔직히 생성자로 String 객체를 생성할 일은 거의 없다고 생각하지만, 그래도 한 번쯤은 읽고 해석해보는 것도 나쁘지 않다고 생각합니다.



public class Source02_String {
public static void main(String[] args) {
String str = "사면초가초";

int len = str.length(); // 문자열의 글자(char[]의 크기)
System.out.println("length == " + len); // 5

char c = str.charAt(0); // 전달되는 인덱스에 대한 char 출력
System.out.println(c); //
System.out.println(c == ''); // char는 기본 데이터 형과 같아 == 로 비교가능

char[] ar = str.toCharArray(); // 문자열 -> char[] 반환
for(int i=0;i<ar.length;i++) {
System.out.println(ar[i]); // ,,,
}

int s1 = str.indexOf(''); // 해당 문자의 인덱스반환 (없으면 -1 반환, 여러 개면 첫번째 인덱스 반환)
System.out.println("s1 = " + s1); // s1=2

int s2 = str.indexOf("면초"); // 문자열로도 인덱스반환 (시작점 반환)
System.out.println("s2 = " + s2); // s2=1

int s3 = str.lastIndexOf(''); // 뒤에서부터 찾아 인덱스 반환 (문자열도 마찬가지로 가능)
System.out.println("s3 = " + s3); // s3=4

int s4 = str.indexOf('',4); // 시작 인덱스를 지정하여 탐색가능
System.out.println("s4 = " + s4); // s4=4

String s5 = str.substring(1,3); // 자신의 문자열에서 일부분을 추출하여 새로운 문자열 생성(이상~미만)
System.out.println("s5 = " + s5); // s5=면초

String s6 = str.substring(2); // 지정 인덱스부터 끝까지 새로운 문자열 생성
System.out.println("s6 = " + s6); // s6=초가초

String data = "사면초가,풍전등화,진퇴양난,설상가상,전화위복";
String[] s7 = data.split(","); // 특정 문자열로부터 분리시켜 배열로 반환
for(int i=0;i<s7.length;i++) {
System.out.println(s7[i]); // 사면초가 풍전등화 진퇴양난 설상가상 전화위복
}

String s8 = data.replace(',', '-'); // 특정문자를 변경하여 새로운 String 생성
System.out.println(s8); // 사면초가-풍전등화-진퇴양난-설상가상-전화위복

String s9 = data.replace("풍전등화", "????"); // 문자열도 변경가능
System.out.println(s9); // 사면초가-????-진퇴양난-설상가상-전화위복

String p = " 가나다라 "; // 공백이 있는 문자열 생성(공백도 문자로 취급)
System.out.println(p); // 가나다라

String s10 = p.trim(); // 문자열 처음과 끝의 공백을 제거하는 기능
System.out.println(s10); // 가나다라

// equals : 문자구성이 같은지 확인
// boolean endWith(String) , boolean startWith(String) : 해당 문자열로 시작한다던가 끝난다던가
// int compareTo(String) : 크기비교 (abcd... , 가나다라... 순으로 커짐), 작으면 음수, 같으면 0, 크면 양수
// boolean matches(String) : 특징 패턴(정규식)에 부합하는지 확인
String[] names = "관우,조조,조운,황충,하후돈,마초,사마의,제갈량,하후인".split(",");
for(int i=0; i<names.length; i++) {
String s = names[i];
System.out.println(s + " ... " + s.equals("관우"));
System.out.println(" ... " + s.startsWith("하후") + " ... " + s.endsWith(""));
System.out.println(" ... " + s.compareTo("조조"));
System.out.println(" ... " + s.matches("[-]{1}"));
}
}
}


String 클래스의 메소드는 너무 방대하고 실제로 알아야 할 메소드를 간추린다 해도 너무 많아서 다 다루기는 제한이 있습니다ㅠㅠ

그래서 실제로 각 메소드가 사용해서 어떻게 동작하나 볼 수 있도록 예제 코드로 대체했습니다.

몇 가지 메소드 빼고는 단순히 문자열 바꾸기나, 단어 선택하는 것과 같이 단순한 기능들이라 API에서 해당 메소드 기능을 살펴보고 예제 코드만 봐도 충분하다고 생각합니다.


- equals() :

 다음에 Collection을 다룰 때도 많이 언급될 메소드입니다. 

String을 new 연산자를 통해 인스턴스 두 개를 생성했을 때 같은 문자열을 가졌을지라도 == 연산자를 통해서는 서로 다른 객체라고 인식한다 했습니다. 

이때 겍체 값이 아닌 실제 객체 안에 들어 있는 데이터 값으로 객체간에 비교를 위해 존재하는 메소드입니다. 

이 메소드는 Object에서 오버리이딩한 것으로 다른 클래스에서도 많이 사용되니 어떤 경우에 사용되고 String 클래스에서는 어떻게 오버라이딩 했는지만 알아두면 될 것 같습니다.


- compareTo() : 

이 메소드 또한 추후에 많이 볼 메소드입니다.

주로 데이터의 크기를 비교하여 정렬하고자 할 때 사용합니다. 전달받은 객체안에 데이터를 비교하여 작으면 음수, 같으면 0, 크면 양수를 반환해야합니다.


- matches() :

 특정 패턴에 부합하는지 확인하는 메소드입니다. 주어진 문자열이 원하는 패턴에 일치하는지 찾아내는 메소드인데 이때 패턴을 정규식이라고 합니다.

정규식에 대해선 다음 포스팅에서 다루겠습니다.


- format() :

 static으로 선언된 메소드로 객체를 생성하지 않아도 사용할 수 있습니다. 형식화된 문자열을 만들어내는 간단한 방법인데 printf()와 사용법이 완전 같습니다.



=======================================================================================================


## String Constant Pool

 

String 객체를 생성하는 방법을 소개할 때 new 연산자를 통해서 생성하면 서로 다른 객체라 판단하고 문자열 리터럴로 생성하면 같은 객체로 판단하는 이유는 String Constant Pool에 있습니다.

 

 문자열 리터럴으로 String을 선언할 경우 내부적으로 String의 intern() 메소드를 호출합니다. intern() 메서드는 주어진 문자열이 String Constant Pool에 존재하는지 검색하고 존재한다면 String Constant Pool에 존재하는 문자열 리터럴 값에 대한 주소 값을 반환하고 없다면 String Constant Pool에 문자열 리터럴을 생성하고 그에 대한 새로운 주소값을 반환합니다. 즉 한번 String Constant Pool에 담아진 문자열은 다시 생성하지 않고 재사용하는 것입니다.


 하지만 new 연산자를 통해 생성될 때는 intern() 메소드가 호출되지 않기 때문에 String Constant Pool에 대해 검사를 하지 않고 객체 값을 반환하게 되는 것이죠.

따라서 new 연산자를 통해 생성된 인스턴스일지라도 intern() 메소드를 수동으로 호출해준다면 == 연산자를 통해 true의 값을 얻어낼 수 있습니다.






'Java > Class' 카테고리의 다른 글

5. Wrapper Class  (0) 2018.10.22
4. 정규표현식(Regular Expression) : java.util.regex 패키지  (0) 2018.10.19
3. StringBuffer & StringBuilder  (0) 2018.10.18
1. Object Class  (0) 2018.10.16
0. APIs & Class  (0) 2018.10.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함