Java+Spring Boot

[Java] String 클래스 특징과 메서드

노력형 천재 호소인 2023. 6. 5. 18:24

1. 객체를 생성하는 두가지 방법 : 리터럴 대입 vs new String();

자바의 문자열은 String 객체로 생성된다. String 은 reference 타입이기 때문에 스택영역에 객체의 참조값이 저장된다. 이 얘기를 하고 넘어가는 이유는 String 객체를 생성하는 두가지 방법에 따라서 같은 내용의 문자열을 초기화 할 때 스택 영역에 저장되는 참조값이 달라질 수 있기 때문이다.

 

1-a. 리터럴

String name = "김현수";
String age;
age = "30";

리터럴(Literal) 은 '문자 그대로의' 라는 뜻의 영단어다. 그 의미와 일맥상통하게, 리터럴로 객체를 생성하는 건 위와 같이  문자열(리터럴)을 그대로 타이핑 해서 변수에 대입하면 끝이다.

 

자바는 리터럴 대입으로 문자열을 선언&초기화할 때, 문자열 리터럴이 동일하면 String 객체를 공유하도록 설계되어 있다.

String name1 = "김현수";
String name2 = "김현수";

위와 같이 같은 리터럴을 name1, name2에 대입할 경우 스택 영역에서 두 변수가 갖는 참조값이 같다. 다시말해서 name1과 name2는 같은 String 객체를 참조한다. 보통 다른 reference타입같은 경우(배열이나 클래스 등등..) 값 자체가 같다고 해도 객체가 따로 생성되는데..! 

 

1-b. new String();

1-a의 특성은 리터럴 대입 한정적으로 나타나는 특성이고,

String name1 = new String("김현수");
String name2 = new String("김현수");

이렇게 new String으로 객체를 생성하게 되면 name1과 name2의 스택영역에서 참조하는 참조값은 달라진다. 즉, 두 객체가 서로 다른 객체로 만들어진다는 뜻이다.

 

정리하자면, 문자열을 리터럴로 생성하느냐, new 연산자로 생성하느냐에 따라 비교연산자의 결과가 달라질 수 있다.

String name1 = "김현수";
String name2 = "김현수";
String name3 = new String("김현수");

System.out.println(name1 == name2);     //true
System.out.println(name1 == name3);     //false

 

2. String 클래스의 메서드 

2-a. equals()

문자열은 우리가 실제로 쓸 때, 참조값이 의미있는게 아니라 그 내용이 의미가 있기 때문에 String  객체는 동등연산자로 비교하는 건 의미가 없다. (참조값을 비교하기 때문) 

따라서 String 클래스는 equals() 라는 메서드를 제공한다. equals는 동일한 객체든 다른 객체든 상관 없이 내부 문자열만을 비교하는 메서드이다.

String name1 = "김현수";
String name2 = "김현수";
String name3 = new String("김현수");
String blank = "";	//빈 문자열

System.out.println(name1.equals(name2));    //true
System.out.println(name1.equals(name3));    //true
System.out.println(blank.equals(""));	    //true

2-b. charAt()

문자열에서 특정 위치의 문자를 얻고 싶다면 이 메서드를 사용하면 된다. charAt()은 파라미터로 인덱스를 받는다.

String name = "henLog";
System.out.println("4번째 글자는 : " + name.charAt(3));

//(혹시나 해서.. 프로그래밍 언어에서 인덱스는 0부터 시작하니까 4번째 글자는 인덱스 3입니다.)

2-c. length()

문자열에서 문자의 개수를 반환하는 메서드.

String name = "hen Log";
System.out.println("총 글자수 : "+name.length());	//공백 포함해서 "7" 이 출력 됨

2-d. replace()

특정 문자열을 다른 문자열로 대체하는 메서드. replace("대체 될 문자열", "대체 할 문자열")

String name = "hen Log";
String hen = "핸";
System.out.println("replace : "+name.replace("hen","핸"));	//replace : 핸 Log
System.out.println("replace : "+name.replace("hen",hen));	 //replace : 핸 Log
System.out.println("replace : "+name.replace("han",hen));    //replace : hen Log     
//"han" 이라는 문자열은 name에 없으므로 그냥 name이 출력 됨

하나 언급 할 것은, String 객체의 문자열은 변경이 불가한 특성을 갖는다. 이를 '불변(immutable) 클래스' 라고 하는데, 이 말은 replace() 를 사용하여 문자열을 대체 한 String객체는 그 전의 객체와는 다른 객체라는 의미이다. 다시말해, 위 코드에서 name.replace(...) 은 name과는 다른 새로운 객체이다.

String oldName = "hen Log";
String newName = "핸 Log";
System.out.println(oldName == newName);	//false

2-e. substring()

문자열에서 특정 위치의 문자열을 잘라내어 가져오고 싶다면 substring() 메서드를 쓰면 된다. 이 메서드는 파라미터로 한개 또는 두개의 정수를 받을 수 있다. 

substring(int 시작index) 시작index에서 끝까지 잘라내기
substring(int 시작index, int 마지막index) 시작index에서 마지막index 앞까지 잘라내기

두번째 케이스 같은 경우에는, 왜 하필 마지막index 앞까지 잘라내는지 의문일 수 있다. 이거 근데 파이썬에선 '슬라이싱' 이라고 부르는 건데 자바에선 슬라이싱이라고 안하는거같음...(제 생각입니다.)

슬라이싱이 뭐냐면, 앞에서부터 글자에 숫자(index)를 매기는게 아니라, 첫글자 앞 부터, 글자와 글자 사이에 숫자(index)를 매기는 거라고 생각하시면 됩니다. (구글에 "파이썬 슬라이싱" 검색 고고)

String juminBeonho = "941114-1234567";
String firstSub = juminBeonho.substring(0, 6);
String secondSub = juminBeonho.substring(7);

System.out.println(firstSub);	//941114	
System.out.println(secondSub);	//1234567

2-f. split()

문자열이 구분자를 사용해 여러 개의 문자열로 구성돼있을 때, 쓰면 편한 메서드. 구분자 기준으로 문자열을 잘라서 만든 여러 문자열들을 String[] 배열에 저장하고 반환한다.

String info = "이름,나이,성별,취미";
String[] arr = info.split(",");		//{"이름","나이","성별","취미"}
for (String s : arr) {
    System.out.println(s);
}

/*
이름
나이
성별
취미
*/