본문 바로가기
Java/Java Basic

[Java Basic] 26. java.lang.String 클래스

by Rosmary 2022. 8. 15.
728x90
반응형

 

 

 

 

이번 포스팅에서는 프로그래밍을 진행하면서 빼놓을 수 없는 문자열과 관련된 내용에 대해 알아보려한다. 문자열의 경우 C에서 문자 배열을 통해 구현하도록 되어 있으나, 이 과정이 번거롭기 때문에 Java에서는 String이라는 클래스를 제공하여 조금 더 간편하게 문자열을 표시할 수 있도록 하고 있다. String 클래스에 대한 본론으로 들어가보자.

 

 

 

1. String 클래스 특징

 

 

(1) Java 문자열은 문자 배열로 선언이 가능하다.

 

서두에서 언급한 내용대로, Java의 문자열은 문자(char) 배열과 동일한 의미를 가진다.  String 클래스의 Documentation을 보면 지금까지 선언한 String 참조타입 변수 선언 형태를 문자 배열로도 동일하게 구현할 수 있음을 알 수 있다.

 

 

 

 

참고로 문자 배열 형태는 println()의 오버로딩으로 인해 배열 내 값이 모두 한 줄로 출력된 뒤 개행이 이루어진다. 하지만 printf()나 print() 매서드는 얄짧없이 배열 주소가 반환된다. print()와 printf() 매서드는 매개 변수로 문자열 배열을 오버로딩하지 않았기 때문이다.

 

 

 

 

 

(2) String 변수의 선언 방법에 따라 값이 메모리에 저장되는 방식이 달라진다.

 

대표적인 String 변수의 선언은 바로 리터럴 값을 참조변수에 대입하는 방식과 새 String 인스턴스를 생성하는 방법이 있다. 문자열 자체가 화면에 출력되는 결과는 동일하지만 두 방식은 메모리에 값이 저장되는 방식은 완전히 다르다. 먼저 리터럴로 저장하는 방식을 보자.

 

 

리터럴로 저장된 값은 클래스 파일의 특정 부분에 저장된다. 코드에서 str1 참조변수에 대입된 값인 "test"는 컴파일 시 Main.class 파일에 저장된다. 다음 참조변수인 str2도 "test" 값이 대입되나 이미 클래스 내에 존재하는 값이므로 동일한 "test" 값을 클래스 파일에 저장하지 않고 저장된 값을 참조하도록 한다. Main.class 파일이 컴파일 및 실행되면, 클래스 파일에 저장된 단 하나의 "test" 값이 메모리에 적재되며, str1, str2는 메모리에 적재된 이 "test"를 참조하게 된다. 

 

반면 새 인스턴스로 문자열을 생성하는 경우, 클래스 파일에 문자열 값이 저장되지 않고, 컴파일과 실행을 거치면서 생성한 인스턴스에 대한 문자열이 메모리에 적재된다.

 

 

 

 

(3) Java String 참조변수 값은 변경이 불가능하다

 

그리고, String 클래스의 Documentation을 보면, String 참조변수는 값이 지정되고 나면 변경이 불가능(their values cannot be changed after they are created)하다고 기재되어 있다. 이러한 특성을 Immutable(변경할 수 없음)이라고 하며, 이 때문에 String 참조변수의 경우 값이 변경되는 경우 매모리에서 아래와 같은 현상이 발생하게 된다.

 

 

 

즉, str1이 기존에 참조하고 있던 메모리의 값이 변경되는 것이 아니라 새 대입 값이 다른 메모리에 적재되고 str1이 생성된 새 값이 저장된 메모리를 참조하게 되는 것이다. 그렇기 때문에 값의 변경 뿐만 아니라, 문자열 합산 작업 역시 합산된 문자열 결과를 저장할 메모리 공간이 별도로 필요하게 된다.

 

 

 

 

연산 전에 str1, str2가 동일한 메모리를 가리키고 있었으나, 문자열 연산 이후 str1이 다른 메모리 주소를 가리키고 있음을 위의 코드에서 확인할 수 있다. 이 때문에 Java에서는 문자열의 연산이 어쩔 수 없이 많이 필요한 프로그램을 제작하는 경우, Immutable 형태의 String 클래스가 아닌 mutable 특성을 가지는 StringBuffer 클래스를 사용한다. StringBuffer는 이번 포스팅의 마지막에 알아볼 예정이다(혹은 작성하는 내용에 따라 다음 포스팅에서...) 

 

String 클래스 사용 시 주의해야할 특징은 거진 살펴보았다. 이제, String 클래스에 정의된, 자주 사용하는 매서드에 대해 알아보려 한다.

 

 

 

2. String 클래스의 유용한 매서드

(1) char charAt(int index)

charAt() 매서드는 Java 포스팅 초기에도 잠깐 소개한 매서드다. 문자열의 특정 index 값을 문자(char)로 반환한다.

 

 

 

유용하게 사용할 수 있는 예시로는 주민등록번호 뒷 7자리 중 첫 자리를 추출하여 성별을, 혹은 두 번째 자리를 추출하여 출생신고 지역을 판단하는 것이 있다.



(2) boolean startsWith(String word), endsWith(String word)

startsWith()와 endsWith() 매서드는 문자열의 시작과 끝 단어가 특정 문자열로 시작/끝나는지 여부를 반환하는 매서드다. 

인자로는 시작 및 끝에 포함된 단어를 문자열로 넣어주면 된다. 인자의 대소문자를 구분하기 때문에 만약 위의 예시에서 str1이 Wo가 아닌 wo로 시작되는지를 물어보면 결과가 출력되지 않는다. 아래의 예시에서 초록 박스 내의 코드를 보면 된다.

 

실수하기  쉬운것이 매서드 이름의 오기다. start, end가 아니라 복수형을 쓴다. startsWith, endsWith

 

 

startsWith() 매서드는 시작과 끝 뿐만 아니라 특정 index가 인자의 단어로 시작/끝나는지도 확인할 수 있다. 오버로딩된 매서드는 아래와 같은 형태를 띈다.

 

startsWith(String prefix, int index)  :  index 위치에서 prefix 단어가 시작되는지 여부를 확인.

 

 

 

 

index를 지정하지 않는 경우, 두 번째 인자는 null 값으로 처리된다. 반환되는 값은 boolean 값으로, 조건 일치 여부를 반환한다. 

 

 

(3) boolean contains(CharSequence agrs)

 

contains() 매서드는 매개 인자로 들어간 문자열이 포함되었는지 여부를 반환하는 매서드다. 매개 인자의 참조타입이 CharSequence라고 표시되어 있는데, String의 매서드들을 포함하는 인터페이스가 CharSequence다. 

 

 

사용 방법은 startsWith(), endsWith() 매서드보다 간단하다. 이 두 매서드와 마찬가지로 contains() 역시 매개 인자의 대소문자를 구별한다.

 

 

 

(4) boolean equals(String string), boolean equalsIgnoreCase(String string2)

 

equals 및 equalsIgnoreCase는 서로 다른 문자열 참조변수가 가지는 문자열 값 자체를 비교하는 함수다. 

 

 

 

equals() 매서드만 사용하는 경우, 대소문자가 다른 경우 서로 다른 값으로 인식하지만, equalsIgnoreCase()는 대소문자 상관없이 알파벳의 일치 여부를 확인한다. 따라서 equalsIgnoreCase()는 사전에서 단어를 찾는 프로그램 작성 시 많이 사용한다.

 

 

(5) int indexOf()

 

문자열의 특정 위치에 어떠한 문자가 위치했는지 확인하는 charAt() 매서드와 반대의 기능을 하는 매서드가. indexOf()다. indexOf()는 인자의 문자 또는 문자열이 포함되어 있는 경우, 문자열 내 인자 위치를 반환한다. 만약 결과가 없는 경우 -1을 반환한다.

 

이 indexOf()는 다른 매서드들과 달리 많은 오버로딩으로 인해 3가지 방식으로 사용이 가능하다.

 

indexOf( int ch )   ->   매개 인자를 문자의 아스키 코드(정수형)로 입력한다.

indexOf( int ch, int index )   ->   매개 인자를 문자의 아스키 코드(정수형)와 해당 문자를 찾기 시작할 index(정수형)을 입력한다.

indexOf( String str ) -> 매개 인자를 문자열로 입력한다.

 

 

 

 

(6) String [] split(String delimeter), String substring(int startIdx, int endIdx)

 

split()과 substring은 특정 문자열을 기준점을 잡고 나누어주는 역할을 하는 매서드다. 차이점은 split()이 구분자(delimeter)로 잘라낸 단어들을 문자열 배열에 저장하는 반면, substring()는 특정 위치의 잘라낸 단어만 문자열로 저장한다는 것이다.

 

 

 

(7) String toLowerCase(), String toUpperCase()

 

toLowerCase()와 toUpperCase()는 문자열 전체를 소문자 또는 대문자로 전환한 결과를 반환하는 매서드다. 

 

 

 

 

(8) static String valueOf()

 

String.valueOf() 매서드는 매개인자로 지정된 값을 전부 문자열로 변경하는 기능을 한다. 즉, 매개변수 타입은 String을 제외한 기본형 자료형 타입과 Object 객체 타입이 모두 들어올 수 있다. 

 

 

 

참조형 객체타입의 경우, toString() 오버라이딩 매서드의 결과가 출력된다. 또한 valueOf()로 반환되는 모든 값은 String 타입으로 변환되기 때문에 당연히 getClass() 매서드의 결과가 java.lang.String으로 출력된다.

 

문자형을 제외한 기본형 타입의 래퍼 클래스(Boolean, Integer, Short 등등 기본형을 클래스 형태로 만든 것을 의미한다)들은 parse로 시작하는 매서드들을 가지고 있는데, 이들 매서드는 문자열을 각자의 클래스 이름에 맞는 기본형 타입으로 변환해주는 역할을 한다. 자세한 것은 추후 포스팅 할 래퍼 클래스(Wrapper Class)에서 다시 알아볼 것이다.

 

 

 

 

(9) String trim()

 

trim() 매서드는 인스턴스의 문자열의 양 끝에 공백이 포함되는 경우, 공백을 삭제한 문자열 값을 되돌려준다.

 

 

 

 

보통 사용자로부터 입력값을 받는 어플리케이션(프로그램) 작성 시 주로 사용하는데, 특정 형태의 값 입력 시 실수로 공백을 추가하는 경우, 이를 제거할 때 유용하다. trim() 매서드는 문자열의 양 끝에 존재하는 공백만을 삭제하며, 문자 사이의 공백은 건드리지 않는다.

 

 

 

(10) String join(String delimeter, String word1, String word2 ....) 과 StringJoiner 클래스

 

join() 매서드는 매개 인자에 지정된 여러 단어를 delimeter로 연결한 문자열로 반환하는 기능을 가진다. 서로 다른 정보를 화면에 표시할 때, 단어 사이 구분이 될 수 있도록 구분자를 넣은 문자열 결과를 반환한다.

 

 

 

여기서 더 나아가 함께 표시하고자 하는 정보를 괄호나 기타 문자열로 감싸주는, join() 매서드의 상위 역할을 하는 클래스도 존재한다. StringJoiner라고 java.util 패키지 내에 존재하는 클래스이며, 이 클래스의 인스턴스를 생성하고, 묶고자 하는 문자열을 배열 형태로 저장한 뒤 반복문을 통해 StringJoiner 클래스의 add() 매서드를 적용해주면 된다. 

 

 

StringJoiner 인스턴스 생성 시, 인자는 Delimeter, preWrapper, postWrapper 문자열을 입력해주면 된다. 참고로 문자열 배열 형태가 아닌 일반 문자열로 StringJoiner 클래스의 add 매서드를 사용하게 되는 경우 해당 단어만 StringJoiner에 적용된다.

 

 

 

 

(11) String.format();

 

이번 포스팅의 String 클래스 마지막 매서드다. 이 format() 매서드는 Python을 하신 분들이라면 아주 익숙한 매서드다. Python의 formatting과 동일한 역할을 하며, Java에서는 System.out.printf() 대용으로 사용하기 좋은 매서드다.

 

 

 

String.format()의 장점은 명확하다. 서로 다른 타입의 변수를 하나의 문자열 내에 묶을 수 있다는 것이다. 만약 이 format() 함수가 없다면 변수마다 일일이 valueOf() 매서드를 적용한 값을 별도의 변수를 만들어 저장해야하기 때문에 메모리 소모가 있을 수 밖에 없다.

 

 

 


 

 

원래 이번 포스팅에서 StringBuffer와 StringBuilder 클래스도 함께 다루려 했는데, 생각보다 포스팅 작성 시간이 길어져 다음으로 넘겨야 할 듯 하다. 

 

다음 포스팅에서는 StringBuffer와 StringBuilder 클래스 + 문자 인코딩 변환에 대해 알아보려 한다.

 

 

 

 Fin.

 

반응형

댓글