본문 바로가기

프로그래밍/JAVA

[JAVA] String 클래스

1. String 클래스

 1.0 들어가기 앞서

    

    new 연산자 필요없이 문자열은 str1처럼 만들어주는 것이 가능하다.

    왜냐? 문자열은 사용 빈도가 높기 때문에 편의를 제공해주는 것이다.


 1.1 String 클래스의 특징


  문자열을 만드는 두 가지 방법이 존재한다.


① 문자열 리터럴을 지정하는 방법

 ※ 상수(constant) : 변하지 않는 변수 (final을 이용해 지정)

 ※ 리터럴(literal) : 변수 및 상수에 저장되는 값 자체 (메모리에 저장된 값)

   정수 리터럴 : 10, 1, 1000 등

   실수 리터럴 : 10.5, 0.7 등

   문자 리터럴 : "hihi", "what are you doing?" 등 실제 저장되는 값을 의미


② String 클래스의 생성자를 사용해서 만드는 방법


아래 코드를 통해 문자열을 만드는 방법을 살펴보도록 하자.

class exercise
{
public static void main(String[] args) {
String str1 = "abc"; // ① 문자열 리터럴을 지정하는 방법
String str2 = "abc"; // ① 문자열 리터럴을 지정하는 방법

System.out.println("String str1 = \"abc\";");
System.out.println("String str2 = \"abc\";");

if(str1 == str2) {
System.out.println("str1 == str2 ? true"); // true
} else {
System.out.println("str1 == str2 ? false");
}

if(str1.equals(str2)) {
System.out.println("str1.equals(str2) ? true"); // true
} else {
System.out.println("str1.equals(str2) ? false");
}
System.out.println(); // 엔터

String str3 = new String("\"abc\""); // ② String 클래스의 생성자를 사용해서 만듦
String str4 = new String("\"abc\""); // ② String 클래스의 생성자를 사용해서 만듦

System.out.println("String str3 = new String(\"abc\");");
System.out.println("String str4 = new String(\"abc\");");

if(str3 == str4) {
System.out.println("str3 == str4 ? true");
} else {
System.out.println("str3 == str4 ? false"); // false
}

if(str3.equals(str4)) {
System.out.println("str3.equals(str4) ? true"); // true
} else {
System.out.println("str3.equals(str4) ? false");
}
}
}


1. 문자열 지정은 "문자열의 내용"을 비교한다. 따라서 모두 true값을 반환한다.

String str1 = "abc"; // 문자열을 리터럴로 생성
String str2 = "abc"; // 문자열을 리터럴로 생성


[ 리터럴로 문자열을 생성한 경우 ] "문자열"이 같으면 하나의 String인스턴스를 참조한다.


str1 == str2 ?  true

str1.equals(str2) ?  true


== 연산자는 주소값을 비교한다. 따라서 true를 반환

eqauls 메서드를 사용했을 때는 두 문자열의 내용을 비교 (※ 내용을 비교하도록 오버라이딩 됨)



String str3 = new String("\"abc\"");
String str4 = new String("\"abc\"");

str3 == str4 ?  false

str3.equals(str4) ?  true

[ 생성자로 문자열을 생성한 경우 ] 서로 다른 인스턴스를 가짐


String s1 = "AAA";
String s2 = new String("AAA");

이때 s1 == s2 일까? 서로 다른 메모리 값을 가지고 있으므로 false를 반환한다.


s2 = s2.intern(); // 새로 추가된 부분

if(s1==s2){
System.out.println("true");
} else
System.out.println("false");


s2 = s2.intern() 이후에 s1==s2의 결과값은 true이다.


intern()은 String인스턴스의 문자열을 'constant pool'에 등록한다.

쉽게 말해서, 임시적인 창고라고 생각하면 된다. 

등록하고자 하는 문자열이 'constant pool'에 존재하는 경우 그 문자열의 주소값을 반환한다.


쉽게 설명하면 우리가 흔히 사용하는 문자열 선언 방법 두 가지가 있다.

1. String a = "ABC"

2. String b = new String("ABC") 


보통 1번과 같은 방법을 자주 사용할 것이다.

이 경우에 String 클래스 내에는 intern()이라는 메소드가 존재한다.

상수 풀(constant pool)에 "ABC"를 등록하여 같은 값이 있으면 해당 주소값을 반환한다.


이런 수영장(pool)에 상수의 주소값이 담겨있다고 생각해보자

위에서 new 생성자를 이용해 AAA를 만들었을지라도 String s2 = new String ("AAA")

s2 = s2.intern()으로 이 수영장을 돌아다니면서 AAA 문자열을 상어처럼 찾아다닌다.

따라서 s1 == s2 가 되는 것이다.


세부학습


<1번 예제>

String a = "ABC";

String b = "ABC";

a == b 의 결과값은?


결과값 : true

해설 : 리터럴을 사용하여 생성할경우 내부적으로 new String("ABC") 메서드 호출 후 

String.intern( ) 메소드가 호출( = costant pool 에 등록 ) 되고 인스턴스를 공유한다.


<2번 예제>

String a = "ABC";

String b = new String("ABC");

a == b 의 결과값은?


결과값 : false

해설 : new String을 이용했기 때문에 intern() 메소드가 호출되지 않는다. 

새로운 heap에 객체를 만들고 그 객체의 레퍼런스를 반환한다.


<3번 예제>

 String s1 = new String("ABC");

 String s2 = new String("ABC"+"D");

 String s3 = "ABCD";


System.out.println(s1 == s2);

System.out.println(s1 == s3);

System.out.println(s2.intern() == s3);


결과 : true, true, false

해설 : s2는 객체 생성을 통해 힙(Heap) 영역을 가리키고 

s3는 상수(리터럴 값)로 선언되었기 때문에 상수 풀(constant pool)을 가리킨다.

그런데 intern() 메소드를 통해 상수풀에서 먼저 ABCD라는 문자열을 찾아다닌다.

그래서 s2.inter() == s3 의 값이 true가 되는 것이다.


복습

"String 클래스 내에서" equals() 메소드는 "대상의 내용"을 비교

== 연산자는 "대상의 주소값"을 비교

String[] words = { new String("aaa"), new String("bbb"), new String("ccc") };
1.  System.out.println(words[0] == "aaa");
2. System.out.println(words[0].equals("aaa"));


위 코드에서 출력값은? 

1번은 false값을 출력하고.

2번은 true값을 출력한다.


1번에서 ==는 주소값을 비교하는 연산자다.

words[0]은 주소값을 가리키는 참조변수인데 " aaa " 라는 문자열과 비교하고 있으니 false를 반환한다.


2번에서 equals 메서드는 내용물을 비교하는 메소드니까 true를 반환한다.



 1.2 빈 문자열(empty string)


String s = " " ; // 빈 문자열로 초기화

char c = ' ';    // 공백으로 초기화


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


기본형 → 문자열

String String.valueOf (boolean b)

String String.valueOf (char c)

String String.valueOf (int i)

String String.valueOf (long l)

String String.valueOf (float f)

String String.valueOf (double d)


문자열 → 기본형

boolean Boolean.getBoolean (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)


class exercise
{
public static void main(String[] args)
{

String[] numbers = { "1", "2", "3", "4", "5" } ;
String result1 = "";
int result2 = 0;

for (int i=0; i<numbers.length; i++){
result1 += numbers[i];
result2 += Integer.parseInt(numbers[i]); // 문자열 → 정수형으로 바꿈                                                                       // Interger.parseInt(String s)
}

System.out.println("result 1 : " + result1);
System.out.println("result 2 : " + result2);
} // end of main
} // end of class


result 1 : 12345

result 2 : 15


문자열을 정수형(int)로 값을 변환하는 코드이다.

만약 문자열에 '공백' 이나 '문자'가 있는 경우에는 예외가 발생할 수 있다.


String[] numbers = { "1a", "2", "3", "4", "5" } ;


문자열 배열 "1"에 a라는 문자가 들어있는 경우

변환 예외(NumberFormatException)이 발생할 수 있다.



그러나 소숫점(.)이나 float형 값을 의미하는 f같은 자료형 접미사는 허용된다.