복습 / 과제 설명
https://laker99.tistory.com/20?category=1065834
- Calendar 클래스 로 날짜 시간 요일 까지 출력
- 새로 만드는게 아니라 시스템으로부터 구해오는 클래스라서 Calendar 클래스는 new 연산자로 객체 못만듬

Calendar 객체 생성법
1. 

Calendar c1 = new GregorianCalendar


- 이미 형성된 상속관계, 자식 클래스인 GregorianCalendar 로 객체를 만들어서 왼쪽의 부모에게 전달 = 레퍼런스 형변환
- 자식 객체가 부모에게 전달 = 업캐스팅
- 세번째 형변환인 레퍼런스 형변환이며, 두 클래스 사이에 상속관계가 전제되어야만 가능함

2. 

Calendar c = Calendar.getInstance();


- Calendar 클래스 안의 정적메소드 getInstance() 메소드 사용해서 객체를 구해옴, Calnedar 객체를 받음 
* 객체 = 인스턴스

- 년월일시분초 -> Calendar의 정적필드를 이용해서 구해야함(API 문서)
- 클래스명.필드명 으로 필드 사용
- 연도 구해올땐 Calendar.YEAR 필드로 get함수써서 구함

 

int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1; // 0~11 이므로 +1 해주기
int d = c.get(Calnedar.DATE);

int h1 = c.get(Calendar.HOUR); // 12시간
int h2 = c.get(Calendar.HOUR_OF_DAY); // 24시간

int ap = c.get(Calendar.AM_PM); // 오전 0 오후 1
int w = c.get(Calendar.DAY_OF_WEEK); //1~7 을 돌려줌

- 1,2,3,4,5,6,7 로 일정히 증가하므로 숫자를 요일로 변환시켜주기 위해서는 String[] 클래스 배열을 사용한다 

 

		int w = c.get(Calendar.DAY_OF_WEEK);//1~7
		System.out.println("w="+w);
		// 1:일, 2:월, 3:화, 4:수, 5:목, 6:금, 7:토
		String[] week={"일","월","화","수","목","금","토"};
		
		System.out.println(week[w-1]+"요일");

- 이렇게 배열인덱스와 맞춰주면 됨 
- "금" 은 6이 나오는데 String배열에는 인덱스 5번이므로 -1 해줌

 

문자열 처리 클래스 종류
- String, StringBuffer, StringTokenizer
1. String : 문자열을 저장함, 가장 빈도 높은 사용
2. StringTokenizer : 여러 문자들을 구분기호로 파싱할때 사용
3. StringBuffer - 가장 빈도 낮지만 알아야함

문자열 처리 클래스 차이
- 3개의 클래스가 기능이 조금씩 다르다.
- 메모리 상에서 데이터 처리하는데 차이가 있다
- String 클래스의 메소드 아주 많다

String 클래스와 메소드
- 자바에서 가장 사용빈도 높은 클래스
- java.lang 패키지 안, import필요 없다
- 지원되는 메소드 100개 넘음

 

String 클래스 예제1

- StringTest00.java

package p2022_07_01;

class StringTest00 {
	public static void main(String[] args) {
		String str1 = new String("Java Programming");
		String str2 = new String("Java Programming");

		if (str1 == str2) { // 주소 비교
			System.out.println("같다");
		} else {
			System.out.println("다르다"); // 다르다
		}
		String str3 = "Java Programming";
		String str4 = "Java Programming";

		if (str3 == str4) {
			System.out.println("같다"); // 같다
		} else {
			System.out.println("다르다");
		}

		if (str1.equals(str3)) { // 값 비교
			System.out.println("같은 값");
		} else {
			System.out.println("다른 값");
		}
	}
}
다르다
같다
같은 값

- String 클래스만 new를 써도 되고 그냥 String name = "mimi" 라고 할 수도 있다
- new연산자 쓸때마다 매번 힙메모리상에 새로운 공간을 생성하라는 표시
- 힙메모리상에 "Java Programming"을 저장하고 있다

 

- 여기서 str3와 str2의 주솟값이 같을까? 즉 같은 "Java Programming"일까?
-> 아니다 위에서든 밑에서든 new를 쓰면 그냥 단독으로 새로운 공간 가지는거임

- str3에서 힙에 Java Programming 만들어졌으므로
- String str4 = "Java Programming"; 하면 그냥 str4는 이미 str3때 만들어진 값의 주솟값을 리턴받음
-> str3 == str4 같다 (같은 주소다)

 

그림

 

참조형의 비교대상 2개
1. 비교연산자로 주솟값 비교
2. equals로 값을 비교

 

String 클래스 예제2
- ConnectString.java

package p2022_07_01;

public class ConnectString {
	
    public static void main( String[] args ) {
	// String 객체 선언
	String gemini = "gemini";
	String johnharu = "johnharu";
		
	// 두 String 객체를 "+" 연산 수행
	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );
	System.out.println( "gemini" + "johnharu" );

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );
    }
}
geminijohnharu
geminijohnharu
geminijohnharu100

 

위 예제 부분1

	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );

 

- 객체 + 객체 를 쓰면 주솟값이 아닌 가리키는 값들끼리를 연결해준다

 

위 예제 부분2

	System.out.println( "gemini" + "johnharu" );

- 이렇게해도 연결되어 출력된다

 

String형 자료형과 기본자료형 변수끼리 결합(위 예제 부분3)

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );

- String형 자료형과 기본자료형 변수끼리 산술적인 연산 +가 안된다
- 붙어서 geminijohnharu100이 출력되고 결과는 전체가 String형으로 바뀜

 

String 클래스 예제3(String과 메모리)

- StringTest01.java

package p2022_07_01;

// String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면
// 변경된 값을 힙메모리 영역에 다시 저장 한다.

// Garbage Collection 기능 (쓰레기 수집 기능)
// : 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능

class StringTest01 {

  public static void main(String[] args) {
    String str1 = "Java Programming";
    
	str1.toUpperCase();              // 대문자로 변환
    System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)
	System.out.println(str1.toUpperCase()); //대문자 변환된 내용 출력

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);          //대문자 변환된 내용 출력
  }    
}
Java Programming
JAVA PROGRAMMING
JAVA PROGRAMMING

 

위 예제의 부분1

	str1.toUpperCase();              // 대문자로 변환
   	System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)

- 왜 위의 예제에서 str1.toUpperCase() 하면 str1의 값을 출력했을때 대문자로 변환되어 출력되지 않을까?
- String class는 값의 변화가 일어나면 변경된 값을 힙메모리상에 저장시킴
- 하지만 이 변경된 값을 재사용하지 못할때는 가비지 콜렉터가 변경이 되더라도 지워버림
- 즉 대문자로 변경이 되었지만 가비지콜렉터 기능때문에 재사용을 못하기 때문에 그 값을 지워버리고 처음 원래의 값(소문자)을 출력시킴

 

- Java Pro 에서 str1.toUpperCase() 를 쓰면 바뀐 내용(대문자) 를 힙메모리상에 새로 저장해줌
(그림 있음 2번번호)
- 하지만 접근하는방법이 없고, 재사용이 안되기 때문에 가비지 콜렉터가 지워버림
- 그래서 str1을 출력하면 원래값을 출력함
- 힙메모리상에서 값의 변화가 일어나면 매번 그걸 힙메모리상에 따로 새로 저장하기 때문이다

 

위 예제의 부분2

System.out.println(str1.toUpperCase());

 

- 한번 대문자로 출력한 후 참조하는 방법이 없으므로 없어짐(그림 3번 표시)
- 이 이후 str1을 출력시 다시 Java Programming으로 나옴

 

변경된 값 재사용
- str2처럼 이 바뀐 결과를 저장하는 새로 힙에 생긴 공간의 주솟값을 저장을 해야함(그림 4번 표시)

위 예제의 부분3

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);

- 이 str2가 새로바뀐 결과가 저장된 힙메모리의 공간을 받아서 주솟값을 저장해야만 재사용가능하고 str2를 통해 그 바뀐 결과를 출력 할 수 있다
- 즉 가리켜주는 객체 없으면 값이 사라짐 재사용되지 않는 힙메모리 값은 가비지콜렉터가 지움

 

그림

 

값이 변할때 메모리 처리
- String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면 변경된 값을 힙메모리 영역에 다시 저장 한다.

 

Garbage Collection 기능 (쓰레기 수집 기능)
- 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능
- 자동 메모리 관리 기능임
- 개발자가 메모리 관리 신경 크게 안써도 됨

+ StringBuffer 클래스
- 메모리상에 문자열 저장하는건 공통적이지만 String과 달리 새로운 공간에 저장하진 않는다

 

변경된 값을 재사용하기

String original = "Java Programming"
String lowerCase = original.toLowerCase(); //java programming
String upperCase = original.toUpperCase(); //JAVA PROGRAMMING

- String은 이렇게 변경된 값의 공간의 주소를 저장할 변수가 있어야 재사용 가능하다.

 

String 클래스 메소드

 

String클래스의 toUpperCase() 메소드
- 문자열을 대문자로 바꿔주는 메소드

String클래스의 toLowerCase() 메소드
- 문자열을 소문자로 바꿔주는 메소드

String클래스의 length() 메소드
- 한글이든 영문이든 몇글자인지를 구해준다.
- 한칸 비어있는 공백도 1글자로 인식함
- 문자열의 길이를 구해준다. 글자수를 구해줌

String클래스의 length() 메소드 예제

- FindBlankIndex.java

package p2022_07_01;

public class FindBlankIndex {
    public static void main( String[] args ) {
		
	String message = "Java program creates many objects.";
	
	// message의 길이를 구함.
	// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
	int len = message.length();

	System.out.println(len);  // len = 34;

	// message 중에서 ' '을 찾음
	for( int i=0 ; i<len ; i++ ) {
	    char c = message.charAt( i );
		if( c == ' ' ) { //공백의 인덱스 번호를 구해서 출력
		    System.out.println( "index = " + i );
		}
	}//for end
    }
}

- 공백이나 . 까지도 한글자로 포함
- 반환형 int, 문자열의 길이를 리턴
-  for문으로 루프 돌려서 0부터 len보다 작을때까지 즉 len 만큼 for문을 돌림

 

length vs length() vs size()
- 배열의 크기를 구해주는 length 속성 -> 속성이므로 ()가 없다
- String 자료가 몇글자인지 구해주는 length() 메소드 -> 메소드이므로 ()
- 자료구조에 저장된 원소의 개수를 구해주는 size() 메소드 -> 메소드이므로 ()

String클래스의 중 charAt() 메소드
- 매개변수 int 이고 안에 인덱스 번호가 들어감
- 리턴형은 char임 즉 인덱스를 받아서 거기에 해당하는 문자를 가져옴.
- 인덱스는 0번부터 시작

그림

String클래스의 중 charAt() 메소드 예제

package p2022_07_01;

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

		String message = "Java program creates many objects.";

		// message의 길이를 구함.
		// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
		int len = message.length();

		System.out.println(len); // len = 34;

		// message 중에서 ' '을 찾음
		for (int i = 0; i < len; i++) {
			char c = message.charAt(i);
			if (c == ' ') { // 공백의 인덱스 번호를 구해서 출력
				System.out.println("index = " + i);
			}
		} // for end
	}
}
34
index = 4
index = 12
index = 20
index = 25

- ' ' 즉 공백이 인덱스 몇변이 있는지 출력해줌 (공백을 찾아주는 코드)

 

String클래스의 indexOf() 메소드
- charAt과 반대기능의 메소드
- 특정 문자의 인덱스번호를 구해주는 메소드
- 찾고자하는 문자가 없을때는 -1을 리턴함
- API 문서에서 indexOf() 메소드 찾아보면 메소드 오버로딩 되어있다

String클래스의 indexOf() 메소드 예제1

	String message = "Java program creates many objects.";
	int index1 = message.indexOf( 'a' );

- 출력 : 1
- a란 문자의 index 번호를 구해와라
- a가 여러개 있을땐, 가장 먼저 나오는 a의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제2

	String message = "Java program creates many objects.";
	int index2 = message.indexOf( 97 );

- 출력 : 1
- 97은 10진수 아스키 코드값이므로 거기에 해당하는 영문자를 찾아줌
- 이 영문자를 찾아서 인덱스를 가져와줌
- 10진수 아스키코드(97) 에 해당되는 문자('a')의 인덱스 번호를 구함.
- 이 97을 65로 바꾸면? -> 'A'를 찾는데 찾고자하는 문자가 없으므로 -1을 리턴함

 

String클래스의 indexOf() 메소드 예제3(매개변수가 2개)

	String message = "Java program creates many objects.";

	//index번호 13번째 이후에서 'a'의 인덱스 번호를 구함
	int index3 = message.indexOf( 'a', 13 ); 
	System.out.println( index3 );

- index번호가 13번 이후에 가장 먼저나오는 'a' 의 인덱스 번호를 찾아라
- 즉 c(13) 부터 찾아라 그 'a' 는 16이 나옴
- 이렇게 위치가 지정될땐 그 이후의 문자를 찾고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제4(매개변수가 String)

	String message = "Java program creates many objects.";

	// 가장 먼저 나오는 'av'의 인덱스 번호를 구함
	int index4 = message.indexOf( "av" );
	System.out.println( index4 );

- 출력 : 1
- Java의 av 이므로 결과는 1
- 문자 한글자가 아니라 문자열이 들어가는 경우임
- 가장 먼저 나오는 av의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제5(매개변수가 2개)

	String message = "Java program creates many objects.";

	// index번호 12번 이후에 나오는 'man'의 인덱스 번호를 구함
	int index5 = message.indexOf( "man", 12 );
	System.out.println( index5 );

- 이렇게 위치가 지정될땐 그 이후의 문자열의 인덱스번호를 주고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제6(결과가 없는 경우)

	String message = "Java program creates many objects.";
	// 찾는 문자가 없는 경우에는 -1을 리턴한다.
	int index6 = message.indexOf( "java" );
	System.out.println( index6 );

- 출력 : -1
- 소문자 java가 없다 찾고자하는 결과없으면 -1 리턴한다
- 이 indexOf 메소드는 대소문자를 구분한다

 

String클래스의 trim() 메소드
- 문좌열 좌,우의 공백을 없애주는 역할

String클래스의 equals() 메소드
- boolean equals()
- 값을 비교하는 역할
- 가리키는 값들끼리 비교함

 

String클래스의 trim() 메소드 / equals() 메소드 예제

package p2022_07_01;

public class TrimTest {

    public static void main( String[] args ) {
    	
//    trim() : 문좌열 좌.우의 공백을 없애주는 역할
//    boolean equals() : 값을 비교하는 역할
	String str1 = new String( "gemini   " );
	String str2 = new String( "   gemini " );

	System.out.println( str1.equals( str2 ));
	System.out.println( str1.trim().equals( str2.trim()));
    }
}

- str1 가 가리키는 gemini 문자열 오른쪽에 공백이 있다
- str2 가 가리키는 gemini 문자열 왼쪽에 공백이있다
- 공백도 메모리상에 공간을 차지함

 

위 예제 부분1

	System.out.println( str1.equals( str2 )); //false

- 공백도 문자로 인식하므로 서로 다른 값으로 인식함.

 

위 예제 부분2

	System.out.println( str1.trim().equals( str2.trim()));

- 서로 같은값임. 
- str1.trim()은 str1이 가리키는 문자열 오른쪽 공백 없애줌(좌,우 모두)
- str2.trim()은 str2이 가리키는 문자열 왼 공백 없애줌(좌,우 모두)
- 둘다 gemini만 남게되고 값이 같으므로 true리턴

 

String클래스의 replace() 메소드
- 문자열에서 첫번째 매개변수 값을 두번째 매개변수 값으로 변환시켜줌
ex) replace("자바","JAVA") : "자바"를 "JAVA"로 치환

 

String클래스의 replace() 메소드 예제1
- ReplaceEx.java

package p2022_07_01;

public class ReplaceEx {

	public static void main(String[] args) {

	//p506
	//replace("자바","JAVA") : "자바"를 "JAVA"로 치환
		
		String oldStr = "자바는 객체지향 언어 입니다.";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
	}

}
자바는 객체지향 언어 입니다.
JAVA는 객체지향 언어 입니다.

 

String클래스의 replace() 메소드 예제2

 

		String oldStr = "자바는 객체지향 언어 입니다. 자바";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
자바는 객체지향 언어 입니다.
자바 JAVA는 객체지향 언어 입니다.JAVA

- "자바" 가 여러개 있어도 다 JAVA로 바꿈

 

+ String클래스는 메소드를 통해 값의 변화가 일어나면 매번 힙메모리상의 새로운공간에 바뀐값을저장함

 

String클래스의 substring() 메소드
- 일부 문자열만 추출
- 메소드 오버로딩되어있다
- 매개변수가 2개인 경우, 매개변수가 1개인 경우 추출하는 범위가 달라진다.

1. 매개변수 2개인경우
- 시작과 끝 인덱스를 지정한다
- 하지만 실제 우리가 추출하는건 하나 적게 추출함 즉 begInindex ~ endIndex-1까지 추출

2. 매개변수 1개인경우
- 시작 인덱스만 지정한다
- 시작 인덱스로부터 끝까지 추출하라는 의미

String클래스의 substring() 메소드 정리
- substring() : 전체 문자열에서 특정 범위의 문자를 추출하는 역할
- substring(n) : index번호 n번 부터 끝까지 추출
- substring(n1, n2) : index번호 n1번 부터 (n2-1)번 까지 추출

 

String클래스의 substring() 메소드 예제1(매개변수 1개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 끝까지 추출		
	String str1 = message.substring( 13 );
	System.out.println( str1 );
creates many objects.

- c가 13번 위치였다. 즉 13부터 모두 추출
- 13은 인덱스 번호 13번부터 끝까지 추출해서 결과를 str1 변수에 저장하고 출력시켜라는 의미

 

String클래스의 substring() 메소드 예제2(매개변수2개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 15번까지 추출
	String str2 = message.substring( 13, 16 );
	System.out.println( str2 );
cre

- c는 13, r은 14, e는 15 (15까지 추출)
- beginIndexNum이 13번 endIndexNum이 16인데 실제로는 13부터 15번까지 추출함

 

- 여기서 str1과 str2는 변경된 문자열을 가리킴(저장)
- 자바는 substring 메소드만 제공함

 

String클래스의 substring() 메소드 예제3
- SubstringEx.java
- substring() 이용해서 한글자 추출하기
- substring(그 글자 인덱스, 그 다음글자 인덱스)
+ string값 비교에 == 쓰지말고 equals쓰기

package p2022_07_01;

public class SubstringEx {

	public static void main(String[] args) {

//아래와 같이 주민번호가 있을때, 남자인지 여자인지 판별하는 프로그램을 작성하세요?

		String jumin = "900101-2233456"; // 2000년 이후 남자는 3번, 여자는 4번
		String gender = jumin.substring(7, 8);

		if (gender.equals("1") || gender.equals("3")) {
			System.out.println("남자");
		} else if (gender.equals("2") || gender.equals("4")) {
			System.out.println("여자");
		}
	}

}

- 문자끼리 비교하는거니 gender.equals("1") 라고 "1"이라고 문자를 넣어야지 숫자 1을 넣으면 안됨!
-  if-else로 해도 되지만 주민번호 첫자리 수 5(귀화한분들) 이런 경우도 있으므로 안전상 if-elseif로 해야한다

 

위 예제 부분1

		String gender = jumin.substring(7, 8);

- 이렇게 해야 7번 인덱스의 문자열을 가져옴

 

String클래스의 substring() 메소드 예제4

- 키보드로 주민번호를 입력받는다, 주민번호 문자로 받아야함(문자열 클래스로 이것저것 할 것 이므로)
- 앞자리 6자리가아니면 메세지 뿌림
- 뒷자리 7자리가아니면 메세지 뿌림 
- 이런걸 유효성 검사라고 한다
- 그리고 이 모든게 완벽한 값이면 입력한 주민번호가 남자인지 여자인지도 판별

package p2022_07_01;

import java.util.Scanner;

public class JuminCheck {

	public static void main(String[] args) {
// 키보드로 주민번호를 입력 받아서 남자인지 여자인지를 판별하는 프로그램을 작성하세요?
// 단, 주민번호 앞자리는 6자리, 뒷자리는 7자리 인지를 유효성 검사를 한다.

		// 키보드로 주민번호 입력받기
		Scanner sc = new Scanner(System.in);
		System.out.println("주민번호 앞자리를 입력 하세요?");
		String jumin1 = sc.nextLine();

		System.out.println("주민번호 뒷자리를 입력 하세요?");
		String jumin2 = sc.nextLine();

		// 남녀
		String g = jumin2.substring(0, 1); // 0번 인덱스 추출한다는 의미

		// 유효성 검사 & gender
		if (jumin1.length() != 6) {
			System.out.println("주민번호 앞자리 6자리를 입력하세요.");
		} else if (jumin2.length() != 7) {
			System.out.println("주민번호 뒷자리 7자리를 입력하세요.");
		} else if (g.equals("1") || g.equals("3")) {
			System.out.println("남자");
		} else if (g.equals("2") || g.equals("4")) {
			System.out.println("여자");
		} else {
			System.out.println("똑바로 입력 하세요.");
		}

	}
}

- if-elseif-else문 처리기때문에 처음 주민번호 앞자리 6자리가 아니면 더이상 아래쪽을 실행안함.
- 주민번호 앞자리 6자리인데 뒷자리 7자리 아니면 두번째에 걸림 아래 실행 안함
- 둘다 개수가 맞으면 이제야 남/녀 검사를함
- 주민번호는 6,7 다 맞는데 뒷자리 첫번째가 1234가 아니면 마지막인 else 구문에서 걸린다

 

+ String클래스의 split() 메소드
- 이후 뒤에서 자세히 설명함(StringTokenizer 클래스 공부 이후)
- 전체 문자에서 구분기호를 가지고 문자를 추출할때 사용함
- @ 나 / 등의 정규 표현식을 구분자로 해서 문자를 자름 이걸 파싱이라고함
- 결과를 돌려주는 자료형은 String형 1차원 배열로 돌려줌

 

+ Strping클래스의 split() 메소드는 은 StringTokenizer 와 비슷한 역할을 하지만 더 쓰기 편하다

+ String클래스의 split() 메소드 오버라이딩
- split(String regex)
- split(String regex, int limit)

 

String 클래스와 메모리 정리
- String 클래스는 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- 재사용은 값을 받아주는 변수가 있을때만 사용가능하고 변경된정보에 접근이 불가능하면 가비지 콜렉터가 지움

사용빈도
String >>> StringTokenizer >>>>> StringBuffer 

 

String, StringTokenzier, StringBuffer

- 공통적 특징 : 힙메모리상에 문자를 저장함
- 하지만 메모리상에 데이터를 처리하는부분이 다름 (메모리상에 문자를 저장하는 방식이 다름)
- String : 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- StringBuffer : 버퍼라는 기억장소를 쓰기때문에 값의 변화가 일어나더라도 새로운 공간에 값을 저장하지 않음. 시작 주소값이 바뀌지 않음. 값을 계속 누적하는 경우에 이 클래스 쓰는 경우가 있다

 

StringBuffer
- 사용빈도 낮음
- StringBuilder 와 비슷한 기능(이건 안함)
- StringBuffer도 java.lang에 있어서 import 안해도 됨
- Buffer라는 임시 기억공간에 문자열을 저장함, 기능적으로 String과 다르다

 

StringBuffer 생성자
- 매개변수가 int capacity로 된 생상자가 있다, 버퍼라는 임시기억장소의 크기를 생성하는 거임
- 크기를 지정하면 지정된크기로 만들어줌, 크기 설정 따로 안해도 버퍼라는 임시기억소 만듬
- 설정안하면 기본적으로 16characther임 16글자 저장하기위한 힙메모리상의 공간을 만들어줌

 

StringBuffer 예제
- StringBufferTest.java

package p2022_07_01;

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

		StringBuffer sb1 = new StringBuffer("gemini");
		System.out.println("sb1.length() : " + sb1.length());	//6
		System.out.println("sb1.capacity() : " + sb1.capacity());	//22

		sb1.append("A string buffer implements" + "a mutable sequence of characters");
		System.out.println("sb1.length() : " + sb1.length());	//64
		System.out.println("sb1.capacity() : " + sb1.capacity());	//64

		StringBuffer sb2 = new StringBuffer();
		System.out.println("sb2.length() : " + sb2.length());	//0
		System.out.println("sb2.capacity() : " + sb2.capacity());	//16
	}
}

 

위 예제 부분1(매개변수가 있는 생성자)

		StringBuffer sb1 = new StringBuffer("gemini");

- 매개변수가 있는 생성자로 객체를 생성하고 있다
- "gemini"가 힙메모리 상에 저장되고, sb1이 이 주소를 갖고 있다.

 

- length()메소드 지원 : 문자열길이를 구해줌
- capacity() 메소드 : 힙메모리상의 할당된 바이트 크기 알려줌 //22바이트
- append() 메소드 : 문자열을 추가함

 

- 동적으로 공간을 늘려주는 기능도 있다 자동으로 늘려줌
- 만약 22보다 큰 크기의 문자열을 넣으면 동적으로 공간을 늘려줌
- 다시 length()를 구했을때 64가 나옴
- 처음에 22바이트였던 공간을 64만큼 늘려줌

 

위 예제 부분2(기본생성자)

		StringBuffer sb2 = new StringBuffer();

- 기본생성자로 객체를 생성하고 있다
- 길이 length 는 0임
- 자동으로 16바이트(16글자공간 만들어줌) 로 만들어줌
- 아무것도 안가리키기 때문에 length()는 0

 

StringBuffer와 값의 변화
- StringBuffer는 값의 변화가 일어나더라도 시작주소값이 바뀌지 않는다
- String과 다른 특징

 

StringBuffer와 값의 변화 예제
- AppendStringBuffer.java

package p2022_07_01;

public class AppendStringBuffer {
    public static void main( String[] args ) {
		
	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());
    }
}
sb1 = gemini
sb2 = gemini is beautiful
sb1 = gemini is beautiful
같은 주소
gemini is beautiful1004
sb1 = gemini is beautiful1004
sb2 = gemini is beautiful1004
GEMINI IS BEAUTIFUL1004

 

위 예제 부분1

	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

- 힙메모리상에 "gemini"라는 값이 저장되고 그걸 sb1이 시작주소를 가지고 있다

 

위 예제 부분2

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

- append() 함수 : 기존 문자열에 새로운 문자열을 이어 붙여줌 (String클래스엔 이 함수 지원안됨)
- 그리고 이걸 sb2가 주소를 가지게 함

 

위 예제 부분3

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

- 출력 : 같은 주소
- 문자열이 변경되었지만 새로운 힙공간에 저장하지 않음 그러니 sb1과 sb2가 가리키는건 같음!
- 둘다 같은 문자열이 출력됨
- 즉 같은 주소, 같은 값 같은걸 가리키고 있음

그림

 

String vs StringBuffer 차이 정리
- String : 값의 변화 일어나면 새로운 공간에 그 결과 저장. 원래 값의 주솟값 != 바뀐 값의 주솟값
- StringBuffer : 값의 변화 일어나도 기존 공간에 적용, 변경된 값의 시작주솟값이 바뀌지 않음

 

위 예제 부분4

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());

- sb1에 append(1004) 함 
- 그 후에 sb1출력하나 sb2 출력하나 같은 gemini is beautiful1004 가 출력됨
- 같은주소를 리턴받았었기때문에 그렇다

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기
- StringBuffer 클래스는 toUperCase() 메소드가 없어서 못쓴다 (langth()는 있음)
- String과 StringBuffer 사이는 상속관계 없으므로 String 클래스 안에 있는걸 StringBuffer가 상속받아 쓸수도 없음

 

-> String 클래스의 생성자를 활용해서 대문자로 바꿔주면 된다.
-> String 클래스 생성자를 찾아보면 매개변수가 StringBuffer인 생성자가 있다
- String(StringBuffer buffer) 생성자
- 이 생성자를 통해서 StringBuffer -> String 으로 변환 가능
- String 객체로 받아서 toUpperCase 해서 대문자 변환하기

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기 예제
- InsertStringBuffer.java
- StringBuffer 클래스의 append() 메소드 : 기존 문자열에 끝 추가
- StringBuffer 클래스의 insert() 메소드 : 지정된 특정 위치에 문자열을 삽입 시킴

package p2022_07_01;

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

		StringBuffer sb1 = new StringBuffer("gemini is beautiful");
		System.out.println(sb1);

		// 인덱스 10번 위치에 very 문자를 삽입
		sb1.insert(10, "very");
		System.out.println(sb1);

		// 인덱스 0번 위치에 1004 를 삽입하라(숫자로 써도 문자가됨)
		sb1.insert(0, 1004);
		System.out.println(sb1);
	}
}
gemini is beautiful
gemini is verybeautiful
1004gemini is verybeautiful

- 처음엔 인덱스 10번위치에 "very"란 문자열을 삽입시켜라는 의미
- is beautiful 사이의 공백이 인덱스 10이다. 그 10번 뒤에 삽입 됨-> is verybeautiful
- 이후 인덱스 0번위치에 1004를 삽입하라는 의미

 

StringBuffer 클래스의 사용
- 문자열 처리 보통은 String 클래스로 다 처리가능함
- 값을 계속 누적시키거나 하는 특별한 경우들에만 StringBuffer를 사용함

 

+ 문자열 분리 방법 2가지
- 구분기호를 가지고 문자를 추출하는, 잘라서 토큰으로 추출하는 역할
1. java.util.StringTokenizer이용
2. String의 split() 메소드 활용

 

StringTokenizer 클래스
- 앞의 두 클래스와 기능이 좀 다름
- 특정 문자를 구분기호를 가지고 토큰을 구해오는 역할을 함
- 문자를 파싱해서 처리해주는 역할을 한다
- java.util 안에 있다

 

StringTokenizer 클래스 생성자
- 매개변수 1,2,3개인 3개의 생성자 중 StringTokenizer(String str, String delim) 을 주로 사용한다
- 첫번째 매개변수에는 전체 문자열 또는 그 문자열을 담은 변수명이 온다
- 두번째 매개변수에는 구분기호가들어간다, 구분기호는 @ # / 등이 될 수 있다.

 

StringTokenizer 클래스 예제1
- StringTest04.java

package p2022_07_01;

import java.util.*;

class StringTest04 {

	public static void main(String[] args) {
		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken()); // 예외발생

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt);

//		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

	} // main() end

}

 

StringTokenizer 클래스 사용예시(위 예제 부분1)

StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

 

- 이렇게 쓰고 두번째 자리에는 구분기호가 들어감
- 이 #으로 전체문자열을 파싱 = 자른다
- 파싱을 하고 리턴되는 "이순신" "을지문덕" 등을 토큰이라고함
- nextTokens() 메소드 : 이 토큰들을 구해오는 메소드

		System.out.println(str.nextToken());

- 하면 첫번쨰 토큰인 이순신 이 출력됨

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());

- 이렇게 더 하면 이순신, 을지문덕  출력됨
- nextToken()메소드는 String형으로 리턴한다

		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
이순신
을지문덕
강감찬
광개토대왕

- 가져올토큰 없는데 한번 더 nextToken() 메소드를 쓰면? 
- 예외가 발생해서 프로그램이 비정상적으로 멈추게됨

Exception in thread "main" java.util.NoSuchElementException
                 at java.util.StringTokenizer.nextToken(Unknown Source)
          at p2022_07_01.StringTest04.main(StringTest04.java:14)

- NoSuchElementException 예외 발생
* 예외 : 예상하지못했던 프로그램상 오류
-> 가져올 토큰이 있는지 없는지 판별을 해야함

 

가져올 토큰이 있는지 판별(위 예제 부분2)
- 가져올 토큰이있는경우에만 출력하기

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt); //4출력

- 토큰들 : 잘려진 부분들
- countTokens() 메소드 : 토큰의 개수를 구해주는 메소드
- 토큰이있을때만 가져오기위해서 처리하기 아래에

		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}
이순신 을지문덕 강감찬 광개토대왕

- hasMoreTokens() 메소드 : 가져올 토큰이 있는지 없는지 판별하는 역할을 함
- 결과를 돌려주는 리턴자료형은 boolean, 가져올 토큰 있으면 true,없으면 false 리턴해서 while문 제어
-> 이러면 예외가 발생할 가능성이 없다

 

nextTokens()의 특징(위 예제 부분3)

		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

- 이순신을 위에서 부르고 while문 에서는 을지문덕 감감찬 광개토대왕 만 나옴
- 한번 nextToken()쓰면 그건 끝난것, 그 뒤부터 출력됨

 

+ String 클래스의 split() 메소드가 이와 비슷한 역할을 한다.

 

StringTokenizer 클래스 예제2
- StringTokenizerTest1.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest1 {

	public static void main(String[] args) {
	
		String source1="111-111|강원도|춘천시|퇴계동";
		StringTokenizer st1=new StringTokenizer(source1,"|");
		
		String zip=st1.nextToken();
		String dou=st1.nextToken();
		String si=st1.nextToken();
		String dong=st1.nextToken();

		System.out.println("우편번호:" +zip);
		System.out.println("도:" +dou);
		System.out.println("시:" +si);
		System.out.println("동:" +dong);
	}

}
우편번호:111-111
도:강원도
시:춘천시
동:퇴계동

- String 객체 source1에 문자열들이 있다
- - StringTokenzier 는 구분기호를 1개밖에 쓰지 못한다!
- "-" 같은거까지 더 구분 못함
- split()은 여러개 구분기호로 파싱 가능
- nextToken() 의 리턴형은 String
- nextToken() 으로 토큰 구해와서 String 객체에 저장했다.

 

StringTokenizer 클래스 예제3(매개변수가 3개)
- StringTokenizerTest2.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest2 {

	public static void main(String[] args) {

		String source1 = "한국 미국 태국 중국 이란";
		StringTokenizer st1 = new StringTokenizer(source1, " ");
		while (st1.hasMoreTokens()) {
			System.out.println("st1.token:" + st1.nextToken());
		}

		System.out.println();
		System.out.println();

		String source2 = "푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2 = new StringTokenizer(source2, ",");
		while (st2.hasMoreTokens()) {
			System.out.println("st2.token:" + st2.nextToken());
		}

		System.out.println();
		System.out.println();

		// true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3 = new StringTokenizer(source2, ",", true);
		while (st3.hasMoreTokens()) {
			System.out.println("st3.token:" + st3.nextToken());
		}

	}

}

 

위 예제 부분1

		String source1="한국 미국 태국 중국 이란";
		StringTokenizer st1=new StringTokenizer(source1," ");

- 국가명 사이에 공백이 들어가있으니 공백으로 파싱하자
- 첫번째 매개변수에는 문자열 또는 문자열이 저장된 변수가 들어간다
- 두번쨰 매개변수에는 구분기호가 들어가는데 여기선 " " 공백으로 파싱

 

위 예제 부분2

		while(st1.hasMoreTokens()){
			System.out.println("st1.token:"+st1.nextToken());
		}

- hasMoreTokens() : 가져올 토큰이 있는지 판별
- while문 안에 가져올 토큰이있을때만 true를 리턴해서 while문 돌려서 모두 출력함
- 가져올 토큰이 없으면 false리턴

 

위 예제 부분3

		String source2="푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2=new StringTokenizer(source2,",");
		while(st2.hasMoreTokens()){
			System.out.println("st2.token:"+st2.nextToken());
		}

 

매개변수 3개인 StringTokenizer(위 예제 부분4)

		//true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3=new StringTokenizer(source2,",",true);
		while(st3.hasMoreTokens()){
			System.out.println("st3.token:"+st3.nextToken());
		}
st3.token:푸들
st3.token:,
st3.token:삽살개
st3.token:,
st3.token:풍산개
st3.token:,
st3.token:진돗개

- 첫번째, 두번쨰 매개변수에 넣어야하는건 위와 같다 
- 하지만 3번째 매개변수가 boolean형이다 즉 true나 false값을 써야함
- 세번째 매개변수에 true가 오면, 그 구분기호도 파싱될 토큰으로 처리하라는 의미
- 그래서 여기는 , 도 토큰기호로 인식해서 nextToken()하면 푸들 다음의 토큰으로 , 라는 토큰이옴
- false넣으면 다른 위의 예제들과 같게 구분기호는 토큰으로 인식 안함. 

 

String클래스의 split() 메소드
- StringTokenzier과 비슷한 역할하는 "메소드"
- 기능적으로 보면 split()이 쓰기가 더 편하고 여러개의 구분기호 가지고 있어도 파싱 가능함

- String[] Split(String regex)
- 이 매개변수에 구분기호가 온다
- 이 파싱된 결과를 왼쪽의 String 1차열 배열로 리턴
- 첫번째 토큰은 0번방, 두번째 토큰은 1번방, 세번째 토큰은 2번방...

 

String클래스의 split() 메소드 예시1

- 주민번호앞자리-주민번호뒷자리 를 - 로 파싱하자

		String jumin = "900101-1234567";
		String[] j = jumin.split("-");

- 구분기호를가지고 잘라서 결과를 왼쪽의 j (String형 배열) 로 전달
- "900101"인 첫번째 토큰이 j[0], "1234567" 인 두번째 토큰은 j[1]로 들어감

 

String클래스의 split() 메소드 예제1
- SplitEx.java

package p2022_07_01;

public class SplitEx {

	public static void main(String[] args) {

// String[] split(String regex) 메소드
		
		String jumin = "900101-1234567";
		String[] j = jumin.split("-");
		
		System.out.println("주민번호 앞자리 : " + j[0]);
		System.out.println("주민번호 앞자리 : " + j[1]);
		
		for (int i = 0; i < j.length; i++) { //향상된for문
			System.out.println("주민번호 " + j[i]);
		}

	}

}
주민번호 앞자리 900101
주민번호 뒷자리 1234567
주민번호 900101
주민번호 1234567
900101
1234567

+ 나중에 배열의 크기를 잘 모르는 경우에 length속성을 꼭 써야한다

 

String클래스의 split() 메소드 예제2

		String tel = "010-1234-5678";
		String[] t = tel.split("-");
		
		for (int i = 0; i < t.length; i++) {
			System.out.println(t[i]);
		}
010
1234
5678

 

String클래스의 split() 메소드 예제3

		// @를 구분기호로 아이디명과 도메인명 파싱하기
		String email = "totoro@naver.com"; //정해진 형식이 있다.
		String[] e = email.split("@");
		
		System.out.println("아이디 : " + e[0]);
		System.out.println("도메인 : " + e[1]);
아이디 : totoro
도메인 : naver.com

 

구분기호 여러개로 파싱하기(split() 메소드 예제4)

- 구분기호 여러개 섞여있어도 파싱하는게 가능하다

		String[] names = text.split("$|,|-");

- 구분기호를 연결해서서 | (파이퍼) 로 연결하면 또는 이런 구분기호들을 이용해 파싱하겠다는 의미
- 이런건 StringTokenizer 가 지원하지 못하는 기능임

 

- SplitEx1.java

package p2022_07_01;

public class SplitEx1 {

	public static void main(String[] args) {
// p512
//		String[] split(String regex); 메소드
		
		String text = "홍길동&이수홍,박연수,김자바-최명호";
		
		String[] names = text.split("&|,|-");
		
//		for (int i = 0; i < names.length; i++) {
//			System.out.println(names[i]);
//		}
//		System.out.println();
		
		for(String name : names) {
			System.out.println(name);
		} //향상된for문
		
	}

}
홍길동
이수홍
박연수
김자바
최명호

+ | 는 구분기호로 쑬 수 없다

 

문자열 파싱하는 방법 정리
1. StringTokenizer 클래스
2. String의 split() 메소드

+ Recent posts