수업/정리

220104 문자열, 날짜/시간, 형식

jumphare 2022. 1. 4. 18:07

*과제 확인
1.
나: 필드에 2차원 배열을 선언함 String [][] input=new String[5][4];
답: 메인 메소드에 객체 배열을 변수로 클래스에 접근함 MemberInfo[] m=new MemberInfo[5];

-> 메인 메소드에 객체 배열을 변수로 선언, new 연산자로 각 배열마다 영역을 할당하고, 입력받은 값을 생성자로 필드에 넘겨 초기화시켜 저장하게 됨 
각 배열마다 새 영역을 할당해 필드의 값을 각자 집어넣을 수 있음
+ 메소드로 값을 받을 필요 없고 생성자만 이용하면 됨
+ 서로 다른 자료형의 값을 집어넣을 수 있음 (필드의 자료형은 변하지 않으니까)
이렇게 메모리 값을 일시적으로 저장해주는 클래스 -> DTO(Data Transfer Object)데이터 접근 객체

내 값이 가장 마지막에 선언한 값만 들어갔던 이유... new 연산자로 할당한 영역은 하나뿐이었고 그 영역의 초기값은 생성자로 넣어주는 값이기 때문에. 객체 배열로 n개 선언해주면 new로 할당하는 영역도 n개이고 각 영역마다 생성자가 값을 초기화시켜줌 -> 정보 여러개 입력 가능!


2.
나: MemberInfo 클래스에 print() 메소드 만들어 사용
답: 출력을 main에서 하고 getter 메소드를 사용

-> 객체 배열을 사용하는 경우 2차 배열 대신
m[i].getName()
m[i].getAge()
..... 이걸 for문 돌려서 출력하는게 좀더 효율적임! setter와 getter를 언제, 어디서, 왜 사용하는지 계속 확인하고 필요 시 응용할 수 있도록 해야함

3.
나: String 문자열 입력받을 때 .next() 사용
답: .nextLine() 사용

-> 띄어쓰기 포함된 모든 문자열을 저장하려면 nextLine()을 사용해야함. next()는 주소를 입력할 때 서울시 강서구... 에서 서울시만 값을 저장하게 됨
+ int형 nextInt() 사용 뒤 nexLine() 추가해주면 -> 숫자 입력 후 enter키 누르면 null값 리턴 (오류 없애기)

4. 정해지지 않은 n명의 정보를 입력하고 싶다면 for보다 while을 이용하는 걸 추천함



어제에 이어서

*문자열- String 클래스
.toUpperCase() : 문자열을 대문자로 변환

.toLowerCase() : 문자열을 소문자로 변환

.length() : 문자열의 길이(공백 포함 글자수) 구해줌

.charAt() : 특정 위치의 문자를 반환
ex) String a= "Java program";
char c= a.charAt(4)
-> c='a'가 들어가게 됨 

.indexOf() : 특정 문자의 인덱스 번호를 구해줌
ex) String m="Java program";
index1=m.indexOf('a'); -> 1 출력 (0부터 시작해서 번호 매겨 가장 처음 나오는 a의 번호,)
index2=m.indexOf('a',5); -> 10 출력 (5 이후에 a를 검색)
index3=m.indexOf("av"); -> 1 출력 (a부분의 번호)
index4=m.indexOf("java"); -> -1 출력 (java 단어가 없을 경우 -1을 리턴)

.trim() : 문자열 좌, 우 공백을 없애줌
boolean equals() : 값을 비교

.substring(): 전체 문자열에서 특정 범위 문자를 추출
ex) String s="Java program";
s.substring(5); -> program 출력 (index번호 5번부터 끝까지 추출)
s.substring(5,10); ->progr 출력 (index번호 5번부터 (10-1)번까지 추출)

.replace() : 문자열 대체
String oldStr= "자바 프로그래밍";
String newStr= oldStr.replace("자바","JAVA"); -> "자바"를 찾아서 "JAVA"로 바꾸고 바꾼 문자열을 newStr로~

참고)
문자열 결합 연산자 + : String은 내부의 문자열을 수정할 수 없음 -> 대치된 새로운 문자열을 리턴함

String data="ABC";
data+="DEF";  // ABC 아닌 ABCDEF가 리턴되게 됨

-> ABC라는 값이 저장된 heap영역이 아니라 DEF 붙은 ABCDEF라는 새로운 문자열이 할당된 heap영역을 리턴하는 것


.valueOf() : 기본타입 자료형을 문자열로 변환
ex int형 20 -> String형 "20"
   double형 3.14 -> String형 "3.14"
 boolean형 true -> String형 "true"

(++++참고참고)
문자를 숫자로 변환하고 싶다면 >>>Wrapper 클래스<<< 쓰세요
20 문자를 int형 20으로 바꾸고자 하면
int num = Integer.parseInt("20");  // 이렇게.. int형 변환하는 클래스가 Integer임 얘 많이 씀


문자열- StringBuffer
.length() : 길이
.capacity() : 버퍼 크기, 기본(공백) 16Byte에 문자열 크기만큼 +되는듯
.append() : 새로 문자열을 추가
.insert(n,"abc") : n번 위치 index에 abc라는 문자열을 추가
ex. gemini is cute 에서 sb1.insert(10,"very "); -> gemini is very cute가 되는 것
StringBuffer는 String과 달리 새로 영역을 할당시키지 않고 기존 영역의 메모리를 늘렸다 줄였다 하면서 값을 저장함 --> 문자열에 따라 capacity()값 달라지는 것으로 확인 가능. 차이점 알아두자
ex.
StringBuffer sb1=new StringBuffer("gemini");
StringBuffer sb2=sb1.append(" is cute");
이때 sb1와 sb2의 값이 같고, 주소값도 같음. 어쩌면 당연함 sb2는 새 영역 할당 안하고 sb1에 문장 더한걸 받았고 sb1은 append로 늘어난 값이 그대로 저장되어버림 이게 StringBuffer의 특징인
여기에 sb1.append(1004)를 추가한다고 하면, sb1와 sb2에서 둘 다 1004 추가된 값을 가지게 됨!

+) StringBuffer 값을 String으로 변환시키고 싶으면 String str=new String(sb1);로 사용하면 됨.

둘은 상속관계가 아니므로! toUpperCase()같은 메소드를 사용해야 한다면 String 형태로 변환시켜 사용해야~


* 문자열- StringTokenizer
문자열을 분리
1. StringTokenizer -> import하고 사용해야함
StringTokenizer("A/B/C/D/E","/"); -> /을 기준으로 문자열을 분리(=파싱parsing)
+)
countTokens() ->  분리된 문자열(=토큰)이 몇 개인지 알려줌
hasMoreTokens() -> 토큰의 존재여부 있으면 True 없으면 False (boolean형)
nextToken() -> 차례대로 토큰을 가져옴
system.out.println(str.nextToken()); // A 출력
system.out.println(str.nextToken()); // B 출력
system.out.println(str.nextToken()); // C 출력 이렇게 차례대로 출력
~~~ 가져올 토큰이 없는데 실행시키면 오류 발생!

/까지 살려서 분리하고 싶다면 StringTokenizer("A/B/C/D",",",true) -> 뒤에 true붙이면 구분기호까지 토큰으로 싹 분리해줌

2. split() -> 정규표현식(& , - 등)을 구분자로 부분 문자열 분리, string 메소드임 -------- 얘를 좀더 자주 쓰는듯
text= A&B&C&D&E 일때
String[] names= text.split("&|,|-"); -> or(|)로 구분자 여럿 지정 가능! 구분자로 문자열 분리 후 객체 배열에 A B C D E 저장 후 리턴

문자열을 뭣하러 분리하는지? -> 파일명.확장자 형태에서 특정확장자만 업로드할 수 있게 하거나 하는 등...


* 날짜/시간 클래스
1. Calendar 클래스(import java.util.Calendar)
  - new 연산자로 객체 생성하면 오류 남 (생성자 사용 시)
   방법    1 자식클래스 이용해 객체 생성 후 형변환
ex.
Calendar c1=new GregorianCalendar();
//클래스명과 생성자명이 다름 -> 왼쪽이 부모 클래스, 오른쪽 자식 클래스 -> 레퍼런스 형변환 : 업캐스팅
getInstance() 이용해 캘린더 객체 생성 (이게 좀더 많이 쓰임)
ex.
Calendar c2=Calendar.getInstance();
//static method->클래스명.메소드로 바로 접근 가능 -> getInstance()로 접근해 Calendar 클래스 객체를 생성

+)날짜 구하기
int y=c2.get(Calendar.YEAR);
//그냥 바로 YEAR 빼오지 말고, Calendar 클래스의 get 메소드의 매개변수로 집어넣어야 현재 연도 구할 수 있음
int m=c2.get(Calendar.MONTH);
//MONTH의 범위가 0~11로 잡히므로 출력 시 +1을 해줘야함


2. Date 클래스 (import java.util.Date) 객체 선언하고 참고)))) ctrl+shift+O 누르면 import 선택하는 창 뜸! 

  -> new 연산자로 선언해서 쓰면 됨
3. Timestamp (import java.sql.Timestamp)
   : Date 확장형(더 자세해서 유용함)
   -> 얘는 기본생성자가 없고 Timestamp(long time) 생성자를 이용하는 게 보통인데, 괄호 안에
       system 클래스의 currentTimeMillis() 메소드를 호출시켜줌 그럼 현재 시간을 1/1000초 단위로 구해준다
       ex. Timestamp ts=new Timestamp(system.currentTimeMillis());
+)
시간 출력되는 형식이 둘이 다르고 Timestamp가 0.001초 단위로 보여줌
자체 클래스로는 이 형식을 변경해줄 수 없기 때문에, 원하는 형식으로 변환하려면 형식Format 클래스를 사용해야 한다

*형식(Format) 클래스 (java.text.*)
: 숫자와 날짜를 원하는 형식의 문자열로 변환
- 숫자 형식: DecimalFormat
- 날짜 형식: SimpleDateFormat
- 매개변수화된 문자열 형식: MessageFormat

+) 참고!!!
형식 클래스를 먼저 써서 형식을 바꿔주고 시간 클래스를 사용해 값을 넣어줘야 함
SimpleDateFormat을 이용해 날짜 클래스 형식을 바꿔준 것