String: 문자열 자료형
// 리터럴 방식
String str1 = "Hello World!";
String str2 = "안녕하세요 😆 반갑습니다~ 🖐️🖐️🖐️";
// 빈 문자열 가능
String str3 = "";
// 인스턴스 생성 방식
String str4 = new String("나중에 자세히 배웁니다.");
// 리터럴 방식도 내부적으로는 인스턴스 생성 방식대로 처리됨
위에 코드를 보면 알 수 있겠지만, 지금까지 배워온 자료형(int,float,double,char)는 범위가 정해져 있었다. 데이터 하나에 지정된 메모리 용량이 있던 것이다. 문자열은 이와는 다르게 기존 원시 자료형과는 다른 참조 자료형이다.
String hl1 = "Hello";
String hl2 = "Hello";
String wld = "World";
// 리터럴끼리는 == 을 사용하여 비교 가능
boolean bool1 = hl1 == hl2; // true
boolean bool2 = hl1 == wld; // false
String hl3 = new String("Hello");
String hl4 = new String("Hello");
String hl5 = hl4;
// 💡 인스턴스와 비교하려면 .equals 메소드를 사용해야 함
// 특별한 경우가 아니면 문자열은 .equals로 비교할 것
boolean bool3 = hl3 == hl4; // false
boolean bool4 = hl1.equals(hl2); // true
boolean bool5 = hl1.equals(hl3); // true
boolean bool6 = hl3.equals(hl4); // true
boolean bool7 = wld.equals(hl2); // false
// 같은 곳을 참조하는 인스턴스들
boolean bool8 = hl4 == hl5; // true
위의 코드의 디버깅 결과를 보면 신기한 점이 있다. hl1 변수와 hl2 변수는 각각 리터럴 형식으로 생성되었고, hl3 변수와 hl4 변수는 인스턴스 방식으로 생성되었다. hl1과 h12를 ==을 사용하여 비교하였더니 true가 나왔는데, 인스턴스로 생성된 hl3와 hl4를 비교하니 false가 나왔다. 이와 같이 특별한 경우가 아니면 문자열은 .equals로 비교하는 것이 더 좋다.
또한 한가지 신기한 부분을 더 발견할 수 있는데, 인스턴스로 생성된 hl4를 그대로 대입한 hl5 변수는 == 을 사용해서 hl4 와 비교해도 true가 나오는 것을 볼 수 있다. 이러한 차이들은 자바가 내부적으로 문자열을 어떻게 다루는지를 알아야 알 수 있다. 간단하게 얘기하면
==: 같은 종이인가?equals: 같은 글이 적혀있는가?

자세하게 설명하자면 너무 길어서 간단하게 말하자면 리터럴로 생성된 것은 String constant pool이라는 곳에 중복이 없게 저장된다. 예를 들어 hl1 변수가 "Hello" 로 선언된 후, hl2 변수도 "Hello" 로 선언되면 저 String constant pool 에서 기존에 있는 "Hello" 를 바라보게 하는 것이다.
반면 클래스의 인스턴스로 선언된 경우 그 외의 영역에 하나하나 따로 저장이 된다. 따라서 == 즉 같은 종이냐고 묻는 것에는 false 가 반환되지만, 그 종이에 적힌 내용이 같냐를 묻는 equals 에는 true 를 반환하는 것이다.
이것 역시 중요한데 자바에서 이런 참조자료형을 = 을 통해 대입하게 되면 값을 복사해서 주는 것이 아니라, 값의 주소를 넘겨주게 된다. 따라서 hl4 와 hl5 를 == 으로 비교해도 true 가 나오는 것이다.
따라서 결론적으로 그냥 문자열을 비교할때는 어지간해서는 .equals 를 쓰자.
String str_a1 = "안녕";
boolean bool_a1 = str_a1.equals("안녕"); // true
// 💡 리터럴로 선언했어도 객체 인스턴스로 만들어짐
// 때문에 객체의 기능인 메소드 사용 가능
boolean bool_a2 = "안녕".equals("안녕"); // true
boolean bool_a3 = "안녕".equals(str_a1); // true
String str_b1 = "Hello, ";
String str_b2 = "World!";
// + 연산자: 이어붙여진 결과를 반환
String str_b3 = str_b1 + str_b2;
// str_b3 : "Hello, World!"
// += 연산자:
// 1. ⭐️ 해당 변수에 문자열을 이어붙임 (부수효과)
String str_c1 = "나는 아무 생각이 없다. ";
str_c1 += "왜냐하면 ";
// 2. 그 결과를 반환
String str_c2 = str_c1 += "아무 생각이 없기 때문이다.";
boolean bool_c = (str_c1).equals(str_c2);
// str_c1 : "나는 아무 생각이 없다. 왜냐하면 아무 생각이 없기 때문이다."
// str_c2 : "나는 아무 생각이 없다. 왜냐하면 아무 생각이 없기 때문이다."
하나 얘기하고 가자면, 문자열에서는 += 만 가능하다. -= 는 불가하다. 당연하게 *= 이나 /= 도 불가하다.
// ⚠️ 상수에는 적용할 수 없음
final String str_d = "헬로";
str_d += "월드"; // 불가
int intNum = 123;
float fltNum = 3.14f;
boolean bool = true;
char character = '가';
String str_d1 = "자, 이어붙여볼까요? ";
// 💡 문자열에 다른 자료형을 더하면 문자열로 이어붙여짐
String str_d2 = str_d1 + intNum + fltNum + bool + character;
// str_d2 = "자, 이어붙여볼까요? 1233.14true가"
// 💡 타 자료형으로부터 문자열로 변환
String str1 = String.valueOf(true);
String str2 = String.valueOf(false);
String str3 = String.valueOf(123);
String str4 = String.valueOf(3.14f); // str4 = "3.14"
String str5 = String.valueOf('가');
String str6 = true + ""; // "true"
String str7 = 123.45 + ""; // "123.45"
// 이런식으로 그냥 빈문자열과 더해줘도 된다.
이제 문자열을 타 자료형으로 변환하는 것을 보겠다. 아래 코드를 보자.
String str123 = "123";
// 문자열을 정수 자료형으로 변환하기
byte bytNum = Byte.parseByte(str123);
short srtNum = Short.parseShort(str123);
int intNum = Integer.parseInt(str123);
long lngNum = Long.parseLong(str123);
// 해당 자료형의 Wrapper클래스.parse자료형 이런식으로 써주면 된다.
// 대소문자 무관 'true'일 때 true 반환
boolean bool1 = Boolean.parseBoolean("TRUE"); // true
boolean bool2 = Boolean.parseBoolean("true"); // true
boolean bool3 = Boolean.parseBoolean("T"); // false
Character같은 경우에는 parse로 바꿔주는게 아니다.
String strA = "A";
// 다음 강에 배울 메소드
char chr = strA.charAt(0);
// 괄호안에 인덱스를 넣어주면 된다.
// ⚠️ 런타임 에러 발생. 하나씩 주석해제해서 테스트
// '실행'으로 테스트하거나, 디버그 후 콘솔 탭에서 확인해볼 것
//byte bytNum2 = Byte.parseByte("12345");
//int intNum2 = Integer.parseInt("123.45");
//double dblNum2 = Integer.parseInt("하나");
바로 위에 코드는 컴파일 단계에서는 오류가 안나지만, 실행을 하면 오류가 난다. 자료형에 맞는대로 넣어주지를 않았기 때문이다.
String str1 = "문자열에 "큰따옴표가" 안 들어가요";
String str2 = "엔터도 안 들어가요. 못 믿겠으면 넣어봐.";
이스케이프 표현
\": 큰따옴표\': 작은 따옴표\n: 줄바꿈\t: 탭\\: 백슬래시 하나
// 실행하여 확인
String str = "문자열에 \"큰따옴표\"도,\n엔터도 넣을 수 있다고?";
System.out.println(str);
String table = "언어\t\t종류\t\t\t\t자료형\nJava\tcompiled\t\t정적\nPython\tinterpreted\t\t동적";
System.out.println(table);
char singleQuote = '\'';
System.out.println(singleQuote);
String path = "C:\\Document\\MyCodings";
System.out.println(path);
다음에는 문자열의 메소드들을 살펴볼 것이다.