공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 

 

 

String 클래스

  다른 언어에서는 문자열을  char 형 배열로 다뤄야 하나, 자바에는 문자열을 위한  String 클래스가 따로 있다.  String 클래스는 문자열을 저장하고 다루는데 필요한 메서드를 제공한다. 

 

 

변경 불가능한(immutable) 클래스

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

 String 클래스는 문자열을 저장하기 위해서 문자형 배열 변수( char[ ]  value 를 인스턴스 변수로 정의해 놓았다. 인스턴스 생성 시 생성자의 매개변수로 입력받는 문자열은 이 인스턴스 변수인  value 에 문자형 배열( char[ ] )로 저장되는 것이다. 그리고 한번 생성된  String 인스턴스가 갖고 있는 문자열은 읽어올 수만 있고 변경할 수는 없다.  String 타입의 문자열을 변경하는 경우 실제로는 문자열이 변경되는 것이 아니라 새로운 문자열이 담긴  String 인스턴스가 생성되는 것이다.  String 클래스를 이용해서 문자열을 다루는 것은 매 연산마다 새로운  String 인스턴스를 생성하게 만드므로 메모리 공간을 많이 차지하게 된다. 그래서 문자열간의 결합이나 추출 등 문자열을 다루는 작업이 많이 필요한 경우에는  String 클래스 대신  StringBuffer 클래스를 사용하는 것이 좋다.  StringBuffer 인스턴스에 저장된 문자열은 변경이 가능하므로 하나의  StringBuffer 인스턴스 만으로도 문자열을 다루는 것이 가능하다.

 

 

 

문자열 비교

String s1 = "abc";	//문자열 리터럴 "abc"의 주소가 s1에 저장됨
String s2 = new String("abc");	//새로운 String 인스턴스를 생성

문자열을 만드는 방법은 위의 코드처럼 2가지가 있다. 두 번째 방법인  String 클래스의 생성자를 이용하는 경우에는  new 연산자에 의해서 메모리 할당이 이뤄지고, 새로운  String 인스턴스가 생성된다. 반면에 첫 번째 방법으로 하게 되면 이미 존재하는 문자열 리터럴의 주소 값을 가리키게 된다.(문자열 리터럴은 클래스가 메모리에 로드될 때 자동적으로 미리 생성됨)

 

 

package Example;

public class Example {
	public static void main(String[] args) {
		//new연산자 없이 생성할 경우, 이미 생성되어있는 문자열 리터럴 값을 참조하게 되므로 같은 주소값을 가리키게됨
		String s1 = "abc";
		String s2 = "abc";
		
		System.out.println("s1 == s2 ? " + (s1 == s2));
		System.out.println("s1.equals(s2) ? " + s1.equals(s2));
		
		System.out.println();
		
		//new연산자로 생성할 경우 각각 다른 객체가 생성되어 주소값이 달라짐
		String s3 = new String("abc");
		String s4 = new String("abc");
		
		System.out.println("s3 == s4 ? " + (s3 == s4));
		System.out.println("s3.equals(s4) ? " + s3.equals(s4));
	}
}

 

실행결과

위의 설명을 확인할 수 있는 예제이다.  new 연산자를 사용하지 않으면 문자열이 같은 경우 전부 같은 문자열 리터럴을 가리키기 때문에  == 연산자로 비교하나  equals 로 비교하나 차이가 없다.( true )

하지만  new 연산자를 이용하면 서로 다른 객체가 생성되므로 주소를 비교하는  == 연산자를 사용하게 되면 같은 값이라도 다른 객체이기 때문에 (주소가 달라서) 다르다고 나온다.  equals 를 해야 내용을 비교해서  true 라고 출력된다. ( equals 도 본래는 주소 값을 비교하므로  false 가 나와야 하지만  String 클래스의  equals   Object   equals 를 문자열의 내용을 비교하도록 오버라이딩 한 것이라서  true 가 나오는 것이다!)

 

 

 

 

문자열 리터럴

자바 소스파일에 포함된 모든 문자열 리터럴은 컴파일 시에 클래스 파일에 저장된다. 이때 같은 내용의 문자열은 한 번만 저장된다.  String 클래스의 인스턴스들은 한번 생성하면 값을 변경할 수 없기 때문에 하나의 인스턴스를 공유하는 게 효율적이기 때문이다. 클래스 파일에는 소스파일에 포함된 모든 리터럴의 목록이 있는데, 해당 클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 이 리터럴의 목록에 있는 리터럴들이 JVM내에 있는 상수 저장소(constant pool)에 저장된다. 

 

 

 

 

빈 문자열(Empty String)

자바에서 배열의 길이를  0 으로 설정할 수 있는 것처럼  char 형 배열도 길이가  0 인 배열을 생성할 수 있다. 그리고 이 배열을 가지고 있는 문자열을 빈 문자열이라고 한다. 예를 들어  String s = ""; 인 경우 참조 변수  s 가 참조하고 있는  String 인스턴스는 내부에  new char[0] 과 같이 길이가  0 인  char 형 배열을 저장하고 있는 것이다.

 String   char 배열이므로 빈 문자열(길이가 0)로 초기화할 수 있지만  char 형 변수에는 반드시 하나의 문자를 지정해야 한다! 일반적으로 변수를 선언할 때 각 타입의 기본값으로 초기화 하지만  String 은 참조형 타입의 기본값인  null 이 아닌 빈 문자열로,  char 형은 기본값인  \u0000 대신 공백으로 초기화한다. 

+  \u0000 은 유니코드의 첫 번째 문자로 빈문자이다.

 

 

 

 

String클래스의 생성자와 메서드

메서드 설  명
String(String s) 주어진 문자열( s )를 갖는  String 인스턴스 생성
String(char[ ] value) 주어진 문자열( char 배열인  value )를 갖는  String 인스턴스 생성
String(StringBuffer buf)  StringBuffet 인스턴스인  buf 가 갖고있는 문자열과 같은 내용의  String 인스턴스 생성
char charAt(int index) 지정된 위치( index , 0부터 시작)에 있는 문자를 알려준다.
int compareTo(String str) 문자열( str )과 사전순서로 비교한다.
(같으면  0 , 이전이면  음수 , 이후면  양수 (떨어진 숫자만큼)를 반환)

int i = "a".compareTo("a"); → 0반환
int i2 = "a".compareTo("c"); → -2반환
int i3 = "e".compareTo("a"); → 4반환
String concat(String str) 문자열( str )을 뒤에 덧붙임
boolean contains(CharSequence s) 지정된 문자열( s )이 포함되었는지 검사
boolean endsWith(String suffix) 지정된 문자열( suffix )로 끝나는지 검사
boolean equals(Object obj) 매개변수로 받은 문자열( obj )과  String 인스턴스의 문자열을 비교
(문자열이 다르거나  Obj 가  String 이 아닌경우  false 를 반환)
boolean equalsIgnoreCase(String str) 대소문자의 구분없이  String 인스턴스의 문자열을 문자열( str )과 비교
int indexOf(int ch) 주어진 문자( ch )가 문자열에 존재하는지 확인하여 위치( index )를 반환
(index는 0부터 시작하고, 못찾으면 -1을 반환)
int indexOf(int ch, int pos) 주어진 문자( ch )가 문자열에 존재하는지 지정된위치( pos )부터 확인하여 위치( index )를 알려준다. (index는 0부터 시작하고, 못찾으면 -1을 반환)
int indexOf(String str) 주어진 문자열( str )이 존재하는지 확인하여 그 위치( index )를 반환
(index는 0부터 시작하고, 못찾으면 -1을 반환)
String intern( ) 문자열을 상수풀(constant pool)에 등록
이미 상수풀에 같은 내용의 문자열이 있을 경우에는 그 문자열의 주소값을 반환
int lastIndexOf(int ch) 지정된 문자 또는 문자코드( ch )를 오른쪽 끝에서부터 찾아 위치( index )를 반환
(못찾으면 -1을 반환)
int lastIndexOf(String str) 지정된 문자열( str )을 인스턴스의 문자열 끝부터 찾아 위치( index )를 반환
(못찾으면 -1을 반환)
int length( ) 문자열의 길이 반환
String replace(char old, char nw) 문자열 중의 문자( old )를 새로운 문자( nw )로 모두 바꾼 문자열을 반환
String replace(CharSequence old, CharSequence nw) 문자열의 문자열( old )을 새로운 문자열( nw )로 모두 바꾼 문자열을 반환
String replaceAll(String regex, String replacement) 문자열 중에서 지정된 문자열( regex )와 일치하는 것을 새로운 문자열( replacement )로 모두 변경
String replaceFirst(String regex, String replacement) 문자열 중에서 지정된 문자열( regex )와 일치하는 것중, 첫번째 것만 새로운 문자열( replacement )로 변경
String[ ] split(String regex) 문자열을 지정된 분리자( regex )로 나누어 문자열 배열에 담아 반환

String s1 = "one,two,three";
String[ ] s2 = s1.split(","); → s2배열에 ,를 기준으로 나뉜 3개의 배열이됨
String[ ] split(String regex, int limit) 문자열을 지정된 분리자( regex )로 나누어 문자배열에 담아 반환하되 문자열 전체를 지정된 개수( limit )로 나눈다.

String s1 = "one,two,three";
String[ ] s2 = s1.split(",", 2); → s2배열에 ,를 기준으로 나누되 2개의 배열이 됨!
boolean startsWith(String prefix) 주어진 문자열( prefix )로 시작하는지 검사
String substring(int begin)
String substring(int begin, int end)
주어진 시작위치( begin )부터 끝위치( end )범위에 포함된 문자열을 얻는다.
(※ 시작위치는 포함되지만 끝위치는 포함되지 X ,  begin <= x < end )
String toLowerCase( )  String 인스턴스에 저장되어 있는 모든 문자열을 소문자로 변환하여 반환
String toUpperCase( )  String 인스턴스에 저장되어 있는 모든 문자열을 대문자로 변환하여 반환
String trim( ) 문자열의 왼쪽 끝과 오른쪽 끝에 있는 공백을 없앤 결과를 반환.
(문자열 중간에 있는 공백은 제거되지 X)
String toString( )  String 인스턴스에 저장되어 있는 문자열을 반환
static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(float f)
static String valueOf(double d)
static String valueOf(Object o)
지정된 값을 문자열로 변환하여 반환
참조변수의 경우,  toString( ) 을 호출한 결과를 반환

 

 

  ■ join( )과 StringJoiner 

  JDK1.8부터  join( ) 과  java.util.StringJoiner 을 사용할 수 있게 되었다.

package Example;

public class Example {
	public static void main(String[] args) {
		
		String s1 = "one,two,three";
		String[] s2 = s1.split(",");  // s2 = {"one","two","three"};
		String s3 = String.join("-", s2);  // "-"를 사이에 붙여서 이어준다.
		
		System.out.println(s3);
	}
}

 

실행결과

 join( ) 은  split 과 반대로 문자열 사이에 구분자를 넣어서 결합한다.

 

 

 

package Example;

import java.util.StringJoiner;

public class Example {
	public static void main(String[] args) {
		
		StringJoiner sj = new StringJoiner(",", "[", "]");
		String[] strArr = {"aaa", "bbb", "ccc"};
		
		for(String s : strArr) {
			sj.add(s);	//sj에 s의 요소들을 추가(결합)
		}
		
		System.out.println(sj.toString());
	}
}

 join( ) 말고도  java.util.StringJoiner 클래스를 이용해서 문자열을 결합할 수도 있다.

 

 

 

 

유니코드의 보충 문자

위의 표에 있는 함수들 중에 매개변수의 타입이 문자임에도  int 형으로 다루는 것들이 있는 이유는 확장된 유니코드 때문이다. 유니코드는 원래 2byte인 16bit 문자 체계인데 글자를 다 표현할 수가 없어서 20bit로 확장하게 되었다. 그래서 하나의 문자를  char 타입으로 다루지 못하고,  int 타입으로 다룰 수밖에 없었다. 이때 확장에 의해 새로 추가된 문자들을 보충 문자(supplementary characters)라고 하는데 매개변수가  int ch 인 것들은 보충 문자를 지원하는 메서드들이고, 매개변수가  char ch 인 것들은 지원하지 않는다고 생각하면 된다.

 

 

 

 

문자 인코딩 변환

byte[] utf8_str = "가".getByte("UTF-8");	//문자열을 UTF-8로 변환
String str = new String(utf8_str, "UTF-8");	//byte배열을 문자열로 변환

서로 다른 문자 인코딩을 사용하는 컴퓨터끼리 데이터를 주고받을 때는 적절한 인코딩이 꼭 필요한다.  getByte(String charsetName) 을 사용하면, 문자열의 인코딩을 다른 인코딩으로 변경할 수 있다. 자바가  UTF - 16 을 사용하지만 문자열 리터럴에 포함되는 문자들은 OS의 인코딩을 사용한다. 한글 윈도우즈의 경우 문자 인코딩으로  CP949 ( 0XB0A1 )를 사용하며,  UTF - 8 ( 0xEAB080 )으로 변경하려면 위의 코드처럼 쓰면 된다. 

 System.out.println(java.nio.charset.Charset.availableCharSets( ); 로 사용 가능한 문자 인코딩 목록을 출력할 수 있다.

 

 

 

 

String.format( )

형식화된 문자열을 만든다.  print( ) 와 사용법이 똑같다.

 

 

 

 

기본형과 문자열간의 변환 방법

기본형 → 문자열  문자열 → 기본형
String String.valueOf(boolean b)
String String.valueOf(char c)
String String.valueOf(int i)
byte, short를 문자열로 변경할 때도 valueOf(int i)를 사용

String String.valueOf(long l)
String String.valueOf(float f)
String String.valueOf(double d)
boolean        Boolean.parseBoolean(String s)
byte        Byte.parseByte(String s)
short        Short.parseShort(String s)
int        Integer.parseInt(String s)
long        Long.parseLong(String s)

float        Float.parseFloat(String s)
double        Double.parseDouble(String s)

기본형으로 변환할 때는 기본형이 아닌 래퍼 클래스(wrapper class)로 변환되며, 이는 기본형을 클래스로 표현한 것들이다.

 

+  parseInt( )   parseFloa( ) 같은 메서드는 문자열에 공백 또는 문자가 포함되어 있는 경우 변환할 때 예외( NumberFormatException )이 발생할 수 있으므로 꼭 문자열 양끝에 공백을 제거해 주는  trim( ) 을 같이 사용해주는 것이 좋다.(   - ,  . 같은 것들이나  float 형 값을 뜻하는  f 같은 자료형 접미사는 허용된다.)

 

 

 

+ Recent posts