String 객체(문자열) 생성 방법 두 가지
1. 리터럴 할당을 통해 생성하는 방법(일반적으로 사용하는 방법)
-> 상수풀(Constant Pool)에서 동일한 문자열이 존재하는지 검사 후 존재하지 않으면 새로 생성하고, 존재하면 해당 주소값을 리턴함
2. 일반적인 클래스 인스턴스를 생성하는 방법(new 연산자를 사용하는 방법)
-> new 연산자에 의해 Heap 메모리 공간에 문자열 객체(=인스턴스)를 생성하며, 동일한 문자열을 가진 객체가 존재하더라도 무조건 새로 생성함
String s1 = "Hello";
String s2 = "Hello";
// 생성된 s1과 s2는 문자열 내용도 같고, 주소값도 같다!
// 동등비교연산자를 사용한 두 문자열의 주소값 비교
if(s1 == s2) {
System.out.println("s1과 s2는 주소값이 같다!");
} else {
System.out.println("s1과 s2는 주소값이 다르다!");
}
if(s1.equals(s2)) {
System.out.println("s1과 s2는 문자열 내용이 같다!");
} else {
System.out.println("s1과 s2는 문자열 내용이 다르다!");
}
System.out.println("----------------------------------------");
String s3 = new String("Hello");
String s4 = new String("Hello");
// -> 생성된 s3과 s4는 문자열 내용은 같지만 주소값이 다르다
// 동등 비교 연산자를 사용한 두 문자열의 주소값 비교
if(s3 == s4) {
System.out.println("s3과 s4는 주소값이 같다!");
} else {
System.out.println("s3과 s4는 주소값이 다르다!");
}
// String 클래스의 오버라이딩 된 equals() 메서드를 사용한
// 두 문자열의 내용 비교
if(s3.equals(s4)) {
System.out.println("s3과 s4는 문자열 내용이 같다!");
} else {
System.out.println("s3가 s4는 문자열 내용이 다르다!");
}
}
String 클래스
- 문자열 데이터를 처리하는 클래스
- 리터럴을 사용하여 문자열을 직접 생성하거나(추천!) new 연산자를 사용한 인스턴스 생성 시 생성자에 문자열을 전달하여 생성
-> 리터럴 사용 시 해당 문자열 존재 여부를 상수풀에서 검사한 후 중복되는 문자열이 없으면 생성하고, 중복될 경우 주소값을 리턴하므로 메모리 공간 낭비가 줄어들게 됨
-> new 연산자 사용 시 문자열 중복 여부와 무관하게 문자열 객체 생성
- 문자열 내용 비교 시 동등비교(==) 연산보다 equals() 메서드 사용
- 문자열을 생성하면 String 클래스 내부적으로 char[]로 관리됨
-> 개발자의 편의를 위해 별도의 String 클래스를 만들어서 제공
-> 배열 형태이므로 배열 인덱스와 동일한 인덱스 번호를 사용(첫 글자 인덱스 0번, 마지막 글자 인덱스는 문자열 길이 -1)
< String 클래스의 메서드 >
- 문자열 수정, 검색, 치환 등 다양한 작업을 수행하는 메서드를 제공
- String 객체는 불변 객체이므로 원본 문자열을 수정하지 않고 각종 작업을 수행할 경우 수정된 데이터를 문자열로 새로 생성함
-> 문자열 수정이 빈번할 경우에는 메모리 낭비가 심하므로 StringBuilder 또는 StringBuffer 클래스를 활용해야 함
String s1 = "Java Programming";
String s2 = " 아이티윌 부산 교육센터 ";
String s3 = "자바/JSP/클라우드";
System.out.println(s1); // toString() 메서드 생략됨
System.out.println(s1.toString()); // 저장된 문자열을 리턴
System.out.println("--------------------------------");
// length() : 문자열 길이(문자열을 분리해놓은 배열 크기) 리턴
System.out.println("s1.length : " + s1.length()); // 16
// equals() : 문자열 비교(대소문자 구별하여 비교)
System.out.println("s1.equals(JAVA PROGRAMMING) : "
+ s1.equals("JAVA PROGRAMMING"));
// equalsIgnoreCase() : 문자열 비교(대소문자 구별하지 않고 비교)
System.out.println("s1.equalsIgnoreCase(JAVA PROGRMMING) : "
+ s1.equalsIgnoreCase("JAVA PROGRAMMING"));
// charAt() : 특정 인덱스에 위치한 문자 1개 리턴
System.out.println("s1.charAt(5) : " + s1.charAt(5)); // P
// substring() : 특정 범위 문자열(= 부분 문자열) 추출
// 1) substring(int beginIndex) : 시작 인덱스부터 끝까지 문자열 추출
System.out.println("s1.substring(5) : " + s1.substring(5));
// 2) substring(int beginIndex, int endIndex) : 시작인덱스 ~ 끝인덱스 -1까지 추출
System.out.println("s1.substring(5,11) : " + s1.substring(5, 11));
// => 5번 인덱스(P) 부터 11번 인덱스(m) - 1 한 (a)까지 추출 : "Progra"
System.out.println("s1.substring(5,12) : " + s1.substring(5, 12));
// => 5번 인덱스(P) 부터 12번 인덱스(m) - 1 한 (m)까지 추출 : "Program"
// concat() : 문자열 결합(결합(연결)연산자보다 연산 속도가 빠름)
System.out.println("s1.concat(!) : " + s1.concat("!")); // Java Programming!
System.out.println(s1 + "!"); // Java Programming!
// indexOf() : 특정 문자 또는 문자열의 인덱스 리턴
// => 문자열의 앞쪽(첫번째 인덱스)부터 탐색
// => 탐색할 문자 또는 문자열이 존재하지 않을 경우 -1 리턴
System.out.println("s1.indexOf('a') : " + s1.indexOf('a'));
// => 앞에서부터 문자 a 를 탐색하여 처음 만나는 인덱스 1 리턴
System.out.println("s1.indexOf('x') : " + s1.indexOf('x'));
// => 존재하지 않는 문자이므로 -1 리턴
System.out.println("s1.indexOf(a) : " + s1.indexOf("a"));
// => 앞에서부터 문자열 "a" 를 탐색하여 인덱스 1 리턴
System.out.println("s1.indexOf(Program) : " + s1.indexOf("Program"));
// => 앞에서부터 문자열 "Program" 을 탐색하여 시작 인덱스 5 리턴
// lastIndexOf() : 문자열 탐색 시 뒤에서부터 탐색하여 인덱스 리턴
// => 탐색 순서를 역순으로 할 뿐, 인덱스 번호 자체가 바뀌지는 않음
System.out.println("s1.lastIndexOf('a') : " + s1.lastIndexOf('a'));
// => 뒤에서부터 문자 a 를 탐색하므로 "Java Programming" 의
// Program 부분의 a 가 탐색되어 인덱스 번호 10 리턴
// replace() : 특정 문자 또는 문자열 치환
// => 동일한 문자 또는 문자열이 존재할 경우 모두 치환
System.out.println("s1.replace('a','@') : " + s1.replace('a', '@'));
// => 소문자 a 를 찾아 모두 @ 기호로 치환하므로
// "Java Programming" -> "J@v@ Progra@mming"
System.out.println("s1.replace(a, @) : " + s1.replace("a", "@"));
// => char 타입 대신 String 타입 문자열도 지정 가능
System.out.println("s1.replace(Java, Python) : " + s1.replace("Java", "Python"));
// toUpperCase(), toLowerCase() : 알파벳(영문자) 대소문자 변환 가능
System.out.println("s1.toUpperCase() : " + s1.toUpperCase());
System.out.println("s1.toLowerCase() : " + s1.toLowerCase());
// trim() : 문자열 앞 뒤의 불필요한 공백 제거
// => 주의! 문자열 사이의 공백은 제거하지 않음
System.out.println("교육기관은 " + s2 + "입니다!");
System.out.println("교육기관은 " + s2.trim() + "입니다!");
// contains() : 문자열 포함 여부 리턴
System.out.println("s2.contains(부산) : " + s2.contains("부산"));
System.out.println("s2.contains(강남) : " + s2.contains("강남"));
System.out.println("---------------------------------------");
// split() : 특정 기준으로 문자열 분리
// => 분리된 문자열은 배열로 관리됨
// => 분리에 사용되는 기준 문자열을 구분자(= 분리자, Delimeter) 라고 함
// => 구분자를 지정하는 규칙은 정규표현식을 따름(나중에 배움)
// String s3 = "자바/JSP/클라우드";
// => 문자열을 "/" 기호를 기준으로 분리하여 배열로 관리 가능
String[] subjectArr = s3.split("/");
// => 문자열을 "/" 기호 기준으로 분리하여 String[] 배열 타입으로 리턴
// => "자바", "JSP", "클라우드" 형태로 분리되어 배열에 저장됨
for(int i = 0; i < subjectArr.length; i++) {
System.out.println(subjectArr[i]);
}
// 만약, "." 기호를 구분자로 지정하는 경우
// 정규표현식에서 특수기호로 사용되어 모든 문자를 구분자로 지정하게 됨
// => 모든 문자가 분리 기준이 되어 제거됨
String s4 = "안녕하세요. 자바 프로그래밍입니다.";
// String[] strArr = s4.split("."); // 모든 문자열이 제거되므로 사용 불가
//
// for(int i = 0; i < strArr.length; i++) {
// System.out.println(strArr[i]);
// }
// 정규표현식 규칙에 따라 . 기호를 구분자로 지정해야 할 경우 \\. 사용
String[] strArr = s4.split("\\.");
for(int i = 0; i < strArr.length; i++) {
System.out.println(strArr[i]);
}
System.out.println("========================");
// String.format() 메서드
// 특정 문자열을 형식 지정문자(%?)와 결합하여 형식을 갖춘 문자열로 리턴
// => printf() 메서드와 형식 지정문자 동일
String name = "홍길동";
int age = 20;
double height = 180.7;
// => 위의 세 가지 데이터를 형식 지정문자를 사용하여 출력
System.out.printf("이름 : %s, 나이 : %d, 키 : %.1f\n", name, age, height);
// 위의 세 가지 데이터를 결합한 문자열을 리턴받아 저장
String formatStr =
String.format("이름 : %s, 나이 : %d, 키 : %.1f\n", name, age, height);
System.out.println("생성된 회원 정보는 " + formatStr);
System.out.println("=======================================");
// toCharArray() : 문자열을 char[] 배열로 리턴
String s5 = "admin123!";
char[] charArr = s5.toCharArray(); // a, d, m, i, n, 1, 2, 3, ! 로 분리됨
for(int i = 0; i < charArr.length; i++) {
System.out.println(charArr[i]);
}
// Arrays.toString() : 배열 내의 모든 데이터를 문자열로 결합하여 리턴
System.out.println(Arrays.toString(charArr)); // [a,d,m,i,n,1,2,3,!]
TEST
package string;
public class Test2 {
public static void main(String[] args) {
/*
* String 클래스 메서드 연습
* ------------------------------------------------------
* 1. 주민등록번호(jumin)를 입력받아 성별(남 또는 여) 및 외국인 판별
* - 입력형식 : "XXXXXX-XXXXXXX"
* - 판별조건
* 1) 뒷자리 첫번째 숫자(문자데이터)가 1 또는 3 : "남성" 출력
* 2) 뒷자리 첫번째 숫자(문자데이터)가 2 또는 4 : "여성" 출력
* 3) 뒷자리 첫번째 숫자(문자데이터)가 5 또는 6 : "외국인" 출력
*
*/
// jumin 변수 선언
String jumin = "031010-3123456";
// 주민등록번호 뒷자리 첫번째 숫자 추출 => 문자로 저장
// System.out.println(jumin.charAt(7)); // '3'
char genderNum = jumin.charAt(7);
// if 또는 switch~case 판별
// if문을 사용할 경우
if(genderNum == '1' || genderNum == '3') {
System.out.println(jumin + " : 남성!");
} else if(genderNum == '2' || genderNum == '4') {
System.out.println(jumin + " : 여성!");
} else if(genderNum == '5' || genderNum == '6') {
System.out.println(jumin + " : 외국인!");
} else {
System.out.println(jumin + " : 잘못된 주민번호!");
}
// switch~case 문을 사용하는 경우
switch(genderNum) {
case '1' :
case '3' : System.out.println(jumin + " : 남성!"); break;
case '2' :
case '4' : System.out.println(jumin + " : 여성!"); break;
case '5' :
case '6' : System.out.println(jumin + " : 외국인!"); break;
default : System.out.println(jumin + " : 잘못된 주민번호!");
}
System.out.println("=============================================");
/*
* 2. subString() 메서드 활용
* 문자열에 포함된 내용(주소) 중에서 실제 주소 부분만 추출하여 출력
* - 입력 형식 : "Address:주소..."
* ex) "Address:부산광역시 부산진구 동천로 109 삼한골든게이트"
* - 출력 형식 : "Address:" 부분을 제외한 나머지 주소만 추출하여 출력
* => "부산광역시 부산진구 동천로 109 삼한골든게이트" 출력
*/
String address = "Address : 부산광역시 부산진구 동천로 109 삼한골든게이트";
System.out.println("주소 : " + address.substring(10));
/*
* 3. split() 메서드 활용
* 문자열에 포함된 정보를 특정 기준 문자열(구분자)을 기준으로 분리하여
* 항목별로 출력
*/
String address2 =
"Address:부산광역시 부산진구 동천로 109,Floor:7층,Tel:051-803-0909";
// 1. 콤마(,)를 기준으로 각 항목 분리
// => 분리된 문자열은 String[] 배열로 저장
String[] strArr = address2.split(",");
for(int i = 0; i < strArr.length; i++) {
System.out.println(strArr[i]);
}
System.out.println("------------------------------------------");
// 2. 1번의 결과에서 콜론(:)을 기준으로 항목명과 항목 내용을 분리하여
// 내용 부분(주소, 층, 전화번호)만 출력
// ex) 부산광역시 부산진구 동천로 109 7층 051-803-0909 출력
// strArr[0] = "Address:부산광역시 부산진구 동천로 109"
// String[] strArr2 = strArr[0].split(":");
// strArr2[0] = Address, strArr2[1] = 부산광역시 부산진구 동천로 109
// System.out.println(strArr2[1]);
// strArr[1] = "Floor:7층"
// strArr2 = strArr[1].split(":");
// strArr3[0] = Floor, strArr3[1] = 7층
// System.out.println(strArr2[1]);
for(int i = 0; i < strArr.length; i++) {
// System.out.println(strArr[i]);
String[] strArr2 = strArr[i].split(":");
// => 분리된 문자열의 1번 인덱스가 실제 데이터이므로
// System.out.print(strArr2[1] + " "); // 1번 인덱스 데이터를 반복 출력
// 분리된 결과를 별도의 배열에 저장하지 않고
// 1번 인덱스 데이터를 바로 출력 가능
// -> 1회성으로 접근 후 제거해도 무관할 경우 사용
System.out.println(strArr[i].split(":")[1]);
// -> 분리된 결과의 1번 인덱스 문자열을 출력
}
}
}
StringBuffer와 StringBuilder
- String 클래스는 한 번 생성되면 그 내부의 문자열이 변경되지 않음
- String 클래스를 사용하여 문자열을 계속 연결하거나 변경하는 프로그램을 사용하면 메모리 낭비가 심함
- 이때, StringBuffer 또는 StringBuilder를 활용하여 문자열을 변경하거나 연결
- 두 클래스는 크게 차이가 없으며 스레드가 동작하는 멀티 스레드 프로그램이라면 문자열의 안전한 변경을 보장하는 StringBuffer 클래스를 사용하고, 스레드가 동작하지 않는 프로그램이라면 실행 속도가 좀 더 빠른 StringBuilder 클래스를 사용
String str = new String("Java");
System.out.println("str 문자열 주소 : " + System.identityHashCode(str));
// => 인스턴스가 처음 생성될 때 메모리 주소 : 1651191114
System.out.println(str); // Java
// => System.out.println(str.toString());
str = str + " and";
System.out.println("str 문자열 주소 : " + System.identityHashCode(str));
// => str 문자열 주소 : 1586600255 (변경됨!)
System.out.println(str); // JAVA and
// => "JAVA and"의 문자열을 갖는 메모리 영역이 새로 생성되었음을 알 수 있음.
// => 기존의 "JAVA" 문자열을 갖는 메모리 영역은 참조하는 변수가 없을 경우
// 자바에서 제공하는 가비지 컬렉터에 의해서 자동으로 사라짐
str = str + " JSP";
System.out.println("str 문자열 주소 : " + System.identityHashCode(str));
// => str 문자열 주소 : 474675244
System.out.println(str);
str = str + " Programming is fun!!";
System.out.println("str 문자열 주소 : " + System.identityHashCode(str));
// => str 문자열 주소 : 932583850
System.out.println(str);
System.out.println("-------------------------------------------");
String str2 = new String("Java");
StringBuilder buffer = new StringBuilder(str2);
// => String으로부터 StringBuilder 생성
System.out.println("연산 전 buffer 메모리 주소 : "
+ System.identityHashCode(buffer));
// => 인스턴스가 처음 생성될 때의 메모리 주소 : 212628335
buffer.append(" and");
System.out.println("연산 후 buffer 메모리 주소 : "
+ System.identityHashCode(buffer));
// => 연산 후 buffer 메모리 주소 : 212628335
buffer.append(" JSP");
System.out.println("연산 후 buffer 메모리 주소 : "
+ System.identityHashCode(buffer));
buffer.append(" Programing is fun!!");
System.out.println("연산 후 buffer 메모리 주소 : "
+ System.identityHashCode(buffer));
// toString()를 통해 String 클래스 변환
str2 = buffer.toString();
System.out.println(str2);
System.out.println("새로 만들어진 str2 문자열 주소: "
+System.identityHashCode(str2));
'⛏️ > JAVA' 카테고리의 다른 글
[JAVA] 31. math 클래스 (0) | 2023.10.24 |
---|---|
[JAVA] 30. Wrapper 클래스 (1) | 2023.10.17 |
[JAVA] 28. 오브젝트 (0) | 2023.10.11 |
[JAVA] 27. 인터페이스 (0) | 2023.10.05 |
[JAVA] 26. 추상 메서드, 추상 클래스 (0) | 2023.10.05 |