ㅁ API란 자바 측에서 제공하는 기본 라이브러리이다.
- 라이브러리란 재사용 가능한 코드와 기능 모음입니다.
- 라이브러리는 클래스, 인터페이스, 메서드, 필드, 상수, 예외 등 다양한 요소들을 포함합니다.
ㅁ java.lang.Math
- 수학과 관련된 기능을 제공하는 클래스
- 모든 필드가 상수 필드로 되어 있고(상수도 static이니까 프로그램 실행시 바로 메모리에 올라가서 객체 생성을 안하고 사용 가능), 모든 메소드가 static 메소드로 되어 있음.
워낙 자주 사용하는 클래스라. (다 public이라 직접적으로 접근 가능)
- 프로그램 실행과 동시에 메모리상에 올라가 있음
- 클래스명. 으로 해당 필드 및 메소드 접근해서 이용
- 객체 생성이 필요없으니까 불가능하게끔 (기본) 생성자가 private으로 되어 있음.
그럼 생성자를 왜 만들었냐. 안만들면 JVM이 public으로 기본생성자를 만들어버리기 때문.
// PI : 파이값을 가지고 있는 상수필드
System.out.println(Math.PI); // 3.141592653589793
// abs : 절대값을 반환
int num1 = -10;
System.out.println(Math.abs(num1)); // 10
// ceil : 올림값을 반환 (실수 형태로 반환함)
double num2 = 4.349;
System.out.println(Math.ceil(num2)); // 5.0
System.out.println((int)Math.ceil(num2)); // 5
// round : 반올림값을 반환 (정수 형태로 반환함) <- 근데 long형으로 반환함!
System.out.println(Math.round(num2)); // 4
// floor : 버림값을 반환 (실수 형태로 반환함)
System.out.println(Math.floor(num2)); // 4.0
// rint : 가장 가까운 정수값을 반환 (실수 형태로 반환함)
System.out.println(Math.rint(num2)); // 4.0
// sqrt : 제곱근(루트) 값을 반환 (실수 형태로 반환함)
System.out.println(Math.sqrt(4)); // 2.0
// pow : 제곱 값을 반환 (실수 형태로 반환함)
System.out.println(Math.pow(2, 10)); // 1024.0 (2의 10승 = 2의 10제곱)
// 이 외에도 메소드들이 많이 있지만 다 외울 필요는 없다.
// 개발자는 항상 문서를 보는 습관이 되어있어야 한다.
ㅁ 구글에 openjdk17 doc 검색 (공식 문서) 해서 북마크 항상 해놔야 한다 개발자는.
ㅁ java.lang.String
- 문자열을 생성하는 두 가지 방법
// 문자열을 생성하는 두 가지 방법
//(1) 문자열 객체로 생성
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1); // String은 Object의 toString 메소드를 재정의했음.
System.out.println(str2);
System.out.println();
System.out.println(str1 == str2); // false 주소값 비교
System.out.println(str1.equals(str2)); // true. String은 Object의 equals 메소드를 재정의했음.
System.out.println();
System.out.println(str1.hashCode()); // 99162322
System.out.println(str2.hashCode()); // 99162322 String은 Object의 hashCode 메소드를 재정의했음.
System.out.println(System.identityHashCode(str1)); // 918221580
System.out.println(System.identityHashCode(str2)); // 2055281021
//(2) 문자열 리터럴로 생성
String str3 = "hello";
String str4 = "hello";
System.out.println(str3);
System.out.println(str4);
System.out.println();
System.out.println(str3 == str4); // true
System.out.println(str3.equals(str4)); // true
System.out.println();
System.out.println(str3.hashCode()); // 99162322 (위랑 똑같음)
System.out.println(str4.hashCode()); // 99162322
System.out.println(System.identityHashCode(str3)); // 1554547125
System.out.println(System.identityHashCode(str4)); // 1554547125
(1) 문자열 객체
(2) 문자열 리터럴로 생성
- object toString '객체의클래스이름@객체의해시코드(객체의 고유한 식별자)를 16진수로 변환' 한 것을 반환
- String toString 문자열 반환하게끔 오버라이딩
- new를 만나는 순간 무조건 힙영역에 올라감.
- 리터럴로 생성하면 동일 문자풀을 참조.
- object equals 주소값 비교해서 반환
- String equals실제 데이터값 비교해서 반환하겎므 오버라이딩
- object hashCode 주소값기반의 10진수 반환
- String hashCode 실제데이터값 기반의 10진수 반환
그래서 str1과 str2의 해시코드가 new로 객체를 생성했음에도 불구하고 같다. 주소값 기반이 아니라ㅓㅅ.
- 찐 주소값이 다른지를 직접 눈으로 보고싶다면 -> System.identityHashCode(레퍼런스)
- 리터럴 제시시 String Pool(상수풀, constant 풀) 영역에 데이터가 올라감.
String Pool 의 특징 : 동일한 문자열을 가질 수 없음.
ㅁ 자바에서 문자열을 관리하는 클래스는 String 말고도 더 있다. (거진 String을 쓰긴 할겁니다.)
(1) String
- 클래스지만 기본자료형처럼 쓸 수 있음. ---> "" (리터럴)로 제시 가능.
- 불변클래스라고 한다.(수정이 불가능함)
- 그 자리에서 변경이 불가능함. => 매번 새로운 주소값을 참조.
- 변경이 적고, 한번
(2) StringBuffer 클래스와 StringBuilder 클래스
- 객체 생성을 통해서 사용해야 함. new로 생성 후 사용.
- 가변클래스라고 한다.(수정이 가능함)
- 그 자리에서 변경이 진행됨. => 매번 동일한 주소값.
- 변경이 빈번할 경우
※
- StringBuffer 클래스와 StringBuilder 클래스는 기능적으로 매우 유사하지만, 멀티 쓰레드 환경에서의 동기화 여부에 있어서 차이가 있습니다. (생성자와 메소드가 다 똑같음)
- StringBuffer 클래스와 StringBuilder 클래스는 생성자, 메소드 모두 다 동일.
다만 차이점 속도 차이가 있다.
전자는 동기화 제공o. 속도가 느림. 데이터 안정성 확보.
후자는 동기화 제공x. 속도가 빠름. 데이터 안정성 확보.
ㅁ String이 불변클래스인 이유
String str = "반가워!";
System.out.println(str);
System.out.println(System.identityHashCode(str)); // 918221580
str += " 난 String이야"; // str = str + "새문자열";
System.out.println(str);
System.out.println(System.identityHashCode(str)); // 603742814
// 기존의 공간에서 문자열이 수정(변경)되는게 아님. <-> 가변클래스는 그자리에서 변경이 일어남.
// str이 100번지를 참조하고 있다가, 200번지를 참조하는 형태가 됨. (주소값 자체가 바뀜)
// 그럼 기존의 힙영역의 "반가워!"라는 값은? 아무도 참조 안하면 나중에 가비지컬렉터가 지움.
- 변경이 안되는 건 아닌데 매번 새로운 주소값을 참조하고 매번 가비지 컬렉터가 지움.
- 변경할 때마다 새로운 주소값이 대입 그말은 곧 매번 새로운 곳을 참조한다는 뜻.
- 기존에 참조하던 객체를 매번 GC가 지워줘야하는 번거로움.
문자열 변경이 빈번할 것 같다면 String은 적합하지 않음. GC가 계속 그걸 치워줘야 해서.
StringBuilder나 StringBuffer가 적합.
(알고리즘 문제풀 때. 빨리, 메모리를 덜 써야 하는데 저걸 씀.)
(근데 웹개발할 때는 다 String 쓰기도 함. 속도차이가 크진 않아서) - 그래도 속도차이는 남. 스트링보다 저 두개가 빠름 변경시.
ㅁ StringBuilder 클래스와 StringBuffer 클래스가 가변 클래스인 이유
- StringBuilder 클래스와 StringBuffer 클래스를 생성하면 내부적으로 16개의 문자를 담을 수 있는 버퍼 공간이 생성이 됨.
- 만약 초기값을 세팅한다면 16+글자수만큼 생성됨. 값을 꼐속 더하다보면 이 공간을 넘을 수 있는데 ㄱㅊ 알아서 늘어남.
( capacity() 메소드 - 총 몇개의 문자를 저장할 수 있는 공간이 있는지 )
( length() 메소드 - 현재까지 실제로 저장된 문자열의 길이를 반환 )
StringBuilder sb = new StringBuilder();
System.out.println(sb.capacity()); // 16
System.out.println(sb.length()); // 0
System.out.println(System.identityHashCode(sb)); // 918221580
StringBuilder sb = new StringBuilder("가나다");
System.out.println(sb.capacity()); // 19 (16 + 글자수만큼 더해진 버퍼공간)
System.out.println(sb.length()); // 3
System.out.println(System.identityHashCode(sb)); // 918221580 (같다)
( append(추가할 문자열) : 기존의 문자열에 전달된 문자열을 추가시켜주는 메소드 )
sb.append("abc");
System.out.println(sb);
System.out.println(sb.capacity()); // 19
System.out.println(sb.length()); // 6
System.out.println(System.identityHashCode(sb)); // 918221580
// delete(시작인데스, 끝인덱스) : 기존의 문자열 시작인덱스 이상, 끝문자열 미만 범위의 문자열 삭제
// 범위를 지정할 때 보통 자바에서는 시작인데스는 포함하고 끝인덱스는 포함 않는 경우가 많다.
sb.delete(2, 4); // 가 나 다 a b c -> 가 나 b c (가비지컬렉터 x)
System.out.println(sb); // 가나bc
System.out.println(sb.capacity()); // 19
System.out.println(sb.length()); // 4
System.out.println(System.identityHashCode(sb)); // 918221580
// insert(위치, 추가시킬 문자열) : 해당 위치에 전달된 문자열을 추가
sb.insert(2, "AA");
System.out.println(sb); // 가나AAbc
System.out.println(sb.capacity()); // 19
System.out.println(sb.length()); // 6
System.out.println(System.identityHashCode(sb)); // 918221580
- 이걸 String으로 했으면 반복문으로 복잡한 로직을 짜야했을 것.
// reverse() : 기존 문자열을 역으로 변경
sb.reverse();
System.out.println(sb); // cbAA나가
System.out.println(sb.capacity()); // 19
System.out.println(sb.length()); // 6
System.out.println(System.identityHashCode(sb)); // 918221580
- 이것도 String으로 했으면 복잡한 로직을 짜야했을 것.
- 변경할 때마다 주소값은 그래도 유지됨을 볼 수 있다.
※ reverse, insert, delete, append를 갖다대보면 사실 return값이 존재한다.
- StringBuilder 객체를 다시 반환함.
그래서 거기에 연이어서 메소드를 또 호출할 수가 있음.
sb.append("ㅋㅋㅋ").delete(0, 4).reverse().insert(0, "!!!");
이게 가능함. 이러한 개념을 메서드 체이닝(Method Chaining) 이라고 함.
- 변경용 메소드 실행시 해당 StringBuilder 객체를 다시 반환해주기 때문에 또다른 메소드를 연이어 호출할 수 있음.
- 가독성을 위해 이렇게 표현하기도 함.
sb.append("ㅋㅋㅋ")
.delete(0, 4)
.reverse()
.insert(0, "!!!");
- 최종적으로 스트링에 넣고싶으면 String asdf = syso(sb); (맞나 확실친않음)
ㅁ String과 관련된 메소드들
String str1 = "Hello World";
// 문자열.charAt(인덱스) : 문자열에서 해당 인엑스의 문자를 반환
char ch = str1.charAt(3);
System.out.println(ch); // l
// 문자열.concat(문자열) " 기존 문자열에 전달된 문자열을 덧붙여서 새로운 문자열로 반환
String str2 = str1.concat("!!!");
System.out.println(str2); // Hello World!!!
// 문자열.equals(문자열) : 두 문자열이 일치하는지 비교 결과값 반환
// 문자열.equalsIgnoreCase(문자열) : 두 문자열이 일치하는지 비교 결과값 반환
// (단, 대소문자는 무시)
String str3 = "hello world";
System.out.println(str1.equals(str3)); // false
System.out.println(str1.equalsIgnoreCase(str3)); // true
// 문자열.length() : 문자열의 글자수 반환
System.out.println(str1.length()); // 11
// 문자열.contains(문자열) : 기준이 되는 문자열에 전달된 문자열이 포함되어 있을 경우 true 반환
System.out.println(str1.contains("llo")); // true
// 문자열.substring(시작인덱스) : 문자열로부터 시작인덱스부터 끝까지 추출해서 반환
// 문자열.substring(시작인덱스, 끝인덱스) : 문자열로부터 시작인덱스부터 끝인덱스 -1까지 반환
System.out.println(str1.substring(3) ); // lo World
System.out.println(str1.substring(3, 7) ); // lo W
// 문자열.indexOf(탐색할 문자열) : 문자열로부터 전달된 문자열의 첫 번째 등장 위치의 인덱스를 반환.
// 문자열.lastIndexOf(탐색할 문자열) : 위와 동일하나 뒤에서 부터 탐색
System.out.println(str1.indexOf("l") ); // 2 (앞에서 부터 탐색)
System.out.println(str1.lastIndexOf("l") ); // 9 (뒤에서 부터 탐색)
System.out.println(str1.indexOf("a") ); // -1 (찾지 못한 경우 -1을 반환)
// 문자열.replace(old, new) : 문자열로부터 old 문자열을 찾아서 new 문자열로 치환한 결과값을 반환.
System.out.println(str1.replace("o", "가") ); // Hell가 W가rld (원본 데이터 str1은 그대로)
// 문자열.toUpperCase() : 문자열을 다 대문자로 변경해서 반환
// 문자열.toLowerCase() : 문자열을 다 소문자로 변경해서 반환
System.out.println(str1.toUpperCase()); // HELLO WORLD
System.out.println(str1.toLowerCase()); // hello world
// 문자열.trim() : 문자열의 앞 뒤 공백을 제거시킨 값 반환
String str4 = " JA VA ";
System.out.println(str4); // JA VA
System.out.println(str4.trim()); //JA VA (중간 공백은 그대로)
// 웹개발할 때 사용자가 아이디나 pw의 앞뒤로 공백을 주면 뺄 때 사용.
// 문자열.toCharArray() : 문자열의 각 문자들을 char[] 배열에 담아 반환
char[] c = str1.toCharArray();
System.out.println(Arrays.toString(c)); // [H, e, l, l, o, , W, o, r, l, d]
// 문자열.isBlank() 자바 11 버전부터 : 빈 문자열이든 공백 문자열이든 true 반환
// 문자열.isEmpty() 자바 6 버전부터 : 빈 문자열이면 true 반환
// 둘 다 문자열이 존재하는지 비교함.
System.out.println("".isBlank()); // true
System.out.println(" ".isBlank()); // true
System.out.println("".isEmpty()); // true
System.out.println(" ".isEmpty()); // false
// 문자열.split(구분자) : 문자열로부터 구분자들을 통해 분리시킨 후 String[] 배열에 담아서 반환
String str5 = "Java, Oracle, HTML, CSS, JavaScript";
String[] a = str5.split(",");
System.out.println(a[0]); //Java
System.out.println(a[1]); // Oracle
System.out.println(a[2]); // HTML
System.out.println(a[3]); // CSS
System.out.println(a[4]); // JavaScript
String str6 = "강보람\n홍길동\n김말똥";
System.out.println(str6); // 줄바꿈되서 3줄에 걸쳐 나옴
String[] names = str6.split("\n");
System.out.println(names[0]); // 강보람
System.out.println(names[1]); // 홍길동
System.out.println(names[2]); // 김말똥
ㅁ Homework
- 공공데이터 가져오면 csv파일로 되어 있는 경우가 있다. 이걸 자바단으로 가져올 수 있다.
- csv파일 : 데이터 형식이 ,로 나열되어 있음. / 여러줄로도 되어있음
// // 새로 만드는 Shop 배열의 크기를 10개로 하기보단 분리된 문자열대로 하는게 좋음. 10대신 [a.length]
ㅁ split의 다른 방법도 있다. 자바가 제공하는 다른 클래스( StringTokenizer )를 통해서 split할 수도 있음.
-
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
String text = "apple,banana,grape,kiwi"; // 콤마를 구분자로 StringTokenizer 객체 생성
StringTokenizer tokenizer = new StringTokenizer(text, ","); // 토큰들을 출력
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
System.out.println(token);
}
}
}
[실행 결과]
apple
banana
grape
kiwi
- 스트링 토크나이저(StringTokenizer)는 자바에서 문자열을 특정 구분자(delimiter)를 기준으로 토큰(token)으로 분리하는 클래스입니다.
-
주요 특징:
- 구분자 지정: StringTokenizer는 생성할 때 어떤 구분자를 기준으로 문자열을 분리할지 지정합니다. 기본적으로 공백(space), 탭(tab), 개행(newline)을 구분자로 인식합니다.
- 토큰 추출: 분리된 각 부분을 토큰(token)이라고 부릅니다. nextToken() 메소드를 사용하여 하나씩 토큰을 추출할 수 있습니다.
- 토큰 개수: countTokens() 메소드를 통해 남아 있는 토큰의 개수를 확인할 수 있습니다.
- 반복적 사용: 다음 토큰을 얻기 위해 hasMoreTokens() 메소드를 사용하여 루프를 반복하면서 토큰을 처리할 수 있습니다.
- 문자열을 배열로 변환: StringTokenizer를 사용하여 문자열을 분리한 후, 필요에 따라 배열이나 리스트로 변환하여 사용할 수 있습니다.
ㅁ Wrapper 클래스
- 진짜 Wrapper라는 클래스가 있는것은 아니고, 이런 클래스들을 묶어서 Wrapper 클래스라고 함.
- <Wrapper 클래스>
기본자료형을 객체로 포장시킬 수 있는 클래스
기본자료형은 리터럴을 곧바로 담을 수 있는 변수들이고 객체가 아님.
주소값을 가지고 있는 것들이 아님.
- 기본자료형은 Object 상속받고 그런거 없음.
즉, 기본자료형을 Wrapper클래스를 통해 객체화 시킬 수 있음.
- 기본자료형을 객체로 취급해야될 경우
1) 기본자료형 데이터를 통해서 메소드를 호출하고자 할 경우
2) 메소드의 매개변수로 기본자료형이 아닌 객체 타입만이 요구될 경우
3) 다형성을 적용시키고 싶을 때
※ 3번
public void method(Object o){ }
method(1);
method(1.3);
이런 경우나
Object[] arr = new Object[5];
arr[0] = 10;
arr[1] = 1.34;
이런경우요!
근데 어짜피 여기서도 AutoBoxing이 되기때문에
바로 값을 전달 또는 대입하면되용
내부적으로 Wrapper객체화 되서 담긴다고 생각하면됩니다!
다형성을 적용시키고 싶을 때, 특히 자바에서 객체 지향 프로그래밍에서 다형성은 중요한 개념입니다. 다형성은 같은 이름의 메소드 호출이 객체의 타입에 따라 다르게 실행될 수 있도록 하는 것을 말합니다. 이를 구현하기 위해 상속과 인터페이스를 사용합니다.
기본적으로 기본자료형(primitive type)은 객체가 아니므로, 다형성을 적용할 수 없습니다. 다형성은 클래스와 그 클래스의 서브클래스, 인터페이스와 그 인터페이스를 구현한 클래스 사이에서 작동합니다.
ㅁ Boxing : 기본자료형을 Wrapper 클래스 자료형으로 바꾸는 과정. (객체화)
- int num1 = 10;
- int num2 = 15;
(1) 방법1. 객체 생성 구문을 통한 방법
Integer i1 = new Integer(num1);
Integer i2 = new Integer(num2);
취소선 그어져있는건 오류나는건 아닌데 권장하지 않는 문법인거.
deprecated는 언젠가는 이 문법이 사라질거니까 쓰지 말라고 알려주는거.
System.out.println(i1); // 10
System.out.println(i2); // 15
Integer라는 클래스에도 toString이라는 메소드가 오버라이딩 되어있음.
주소값을 보여주는게 아니라 실제값을 보여주도록.
(equals 메소드도 주소값 비교가 아닌 데이터값 비교로 오버라이딩 되어있음.)
이제 i1과 i2를 가지고 .equals나 .compareTo 등 참조타입 즉 객체들이 쓰는 메소드 사용 가능.
System.out.println(i1.equals(i2)); // flase
System.out.println(i1.compareTo(i2)); // -1 // 두 값을 비교해서 앞쪽이 크면 1 반환, 뒤쪽이 크면 -1반환, 같으면 0반환
(2) 방법2. 리터럴값 대입하듯이 단순 대입을 통한 방법 (AutoBoxing)
Integer i3 = num1;
Integer i4 = 30;
※ 번외. 문자열 데이터를 Wrapper 클래스로 객체화
Integer i5 = "123"; // 숫자만 담겨있는 문자열이라도 문자열 타입이어서 불가능.
Integer i5 = new Integer("123"); // 이렇게 생성시에는 가능. 문자열로 줘도 int형으로 받아들임. 권장 x
Integer i5 = Integer.valueOf("123"); // Integer 클래스가 제공하는 static 메소드 사용.
// 얘는 deprecated 되어있지 않음. 권장 o
ㅁ UnBoxing: Wrapper 클래스 자료형을 기본자료형으로 바꾸는 과정.
(1) 방법1. Wrapper 클래스의 xxxValue 메소드 이용 방법
int num3 = i3.intValue(); // i3 => num3
int num4 = i4.intValue(); // i4 => num4
(2) 방법2. 단순 대입을 통한 방법 (AutoUnBoxing)
int num5 = i5;
System.out.println(num5);
- 래퍼 클래스를 배우는 가장 큰 목적은 기본 자료형과 스트링 자료형을 쌍방으로 변환시켜야 하는 경우가 있다.
기본자료형을 문자열로, 문자열을 기본자료형으로 취급해야하는 경우가 있기 때문.
이걸 위해서 래퍼 클래스의 종류를 알아야 한다.
= 이게 중요. 파싱하는 과정. 박싱과 언박싱은 어차피 오토로 되고.
String str1 = "10";
String str2 = "15.3";
System.out.println(str1 + str2); // 1015.3
(1) String -> 기본자료형 // 이걸 파싱한다고 함.
웹개발할 때 사용자가 입력한 값을 자바에서 받으면 무조건 문자열 데이터로 옴.
파싱이라는 과정을 통해서 변환처리해서 담아야 한다.
- 웹에서는 화면으로부터 입력된 값을 자바측으로 넘어올 때 무조건 문자열로 넘어옴.
이걸 기본자료형 변수에 담고자한다면 파싱해야 함.
int i = Integer.parseInt(str1);
double d = Double.parseDouble(str2);
※ Integer.valueOf() 메소드와 Integer.parseInt() 메소드는 모두 문자열을 정수로 변환하는 목적을 가지고 있지만, 몇 가지 중요한 차이점이 있습니다.
- Integer.valueOf(String str) 반환 타입: Integer 객체를 반환합니다.
- Integer.parseInt(String str) 반환 타입: int (기본 자료형)을 반환합니다.
- String 클래스에는 valueOf 메서드가 있지만, parseString 메서드는 존재하지 않습니다
(2) 기본자료형 -> 문자열 // 이건 딱히 용어가 있진 않음
- String.valueOf(변환시키고자하는값)
10 -> "10"
- String strI = String.valueOf(i);
String strD = String.valueOf(d);
System.out.println(strI); // 10
System.out.println(strD); // 15.3
ㅁ Scanner로 입력받을 때는 자료형에 맞게 nextInt등을 썼지만,
웹개발 들어가면 Scanner로 값을 넘겨받지 않음. 화면에서 넘겨 받을 거. 그때는 문자열로 옴. 그때는 파싱해야함.
- int age = Integer.parseInt(sc.nextLine() ); // "10" -> 10
ㅁ 날짜와 시간 관련 데이터를 담을 수 있는 클래스
- 자바에서 제공하는 Date 클래스.
- Date 클래스가 java.sql 패키지에도 Date 클래스가 있고,
java.util 패키지에도 Date 클래스가 있다. 지금은 후자를 쓴다.
ㅁ <java.util.Date >
- 날짜 및 시간에 대한 값을 담을 수 있는 객체
- 많이 쓰진 않을 거임. 자바 1때부터 만들어진 클래스라 급하게 만들어짐.
너무 급하게 만들어져서 다국적으로 쓰기에는 적합하지 않다고 판별이 됐음.
그래도 아직도 Date 클래스를 쓰는 회사도 있을거라 볼 줄은 알아야 함.
- 대부분의 구문들이 deprecated 되어 있음.
(1) 기본 생성자로 생성 <- 현재 시스템 날짜 및 시간에 대한 정보를 가짐.
Date date1 = new Date();
System.out.println(date1); // Mon Jul 08 11:28:29 KST 2024
- 얘도 참조자료형인데 toString 메소드가 오버라이딩 되어 있음.
(2) 매개변수 생성자로 생성 <- 내가 원하는 날짜 및 시간 설정 가능
Date dat2 = new Date(2024, 6, 17, 13, 30, 15); // 연 월 일 시 분 초
System.out.println(date2); // Thu Jul 17 13:30:15 KST 3924
- '시분초 + 일'은 세팅이 잘 됐는데, 년월이 이상함.
연도가 내가 전달한 연도에 1900이 더해졌음.
생성자를 보면 전달된 연도를 가지고 1900을 더함. 그때 당시에 이렇게 개발했음.
월도 6월이라고 숫자6으로 치지 않고 0에서부터 11로 침.
- 그래서 이걸 쓰려면 연도는 -1900해야 하고 월도 -1해야 함.
그래서 다국적으로 쓰기에 적합하지 않다. 그래서 쓰진 않아요 많이.
- 추출하고서도 연도에 +1900, 월에 +1 해야 함.
Date date2 = new Date(2024 - 1900 , 6 - 1, 17, 13, 30, 15); // Mon Jun 17 13:30:15 KST 2024 원하는 대로 나옴.
ㅁ API 문서 내에서 Date 클래스 말고 Calendar 클래스 쓰라고 되어 있음.
ㅁ <java.util.Calendar>
- 날짜 및 시간에 대한 정보를 가질 수 있는 클래스
- 단 추상클래스이므로 객체 생성은 불가능함.
추상클래스라느 ㄴ것은 이를 완성시키는 자식 클래스가 있다는 뜻.
국가별 시간대별로 구체화시켜둔 자식 클래스가 존재함.
그래서 다형성이라는 개념을 적용시켜서 다형성이라는 개념을 적용시켜서 자식객엧를 생성해서 사용하면 됨.
- 캘린더로는 객체 생성이 불가능하고 자식객체로 생성 가능.
Calendar today = new Calender(); // 불가능
Calendar today;
대신 타입으로는 사용 가능
(1) 방법1. 우리나라에 맞는 GregorianCalendar 객체를 생성.
캘린더 추상클래스를 구현하고 있는 자식 클래스로 그레고리안 캘린더라는 클래스가 있음.
Calendar today = new GregorianCalendar();
System.out.println(today);
[실행 결과] // 24년 7월 8일 11시 41분 35초 실행
java.util.GregorianCalendar[time=1720406495749,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Seoul",offset=32400000,dstSavings=0,useDaylight=false,transitions=30,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2024,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=2,DAY_OF_MONTH=8,DAY_OF_YEAR=190,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=11,HOUR_OF_DAY=11,MINUTE=41,SECOND=35,MILLISECOND=749,ZONE_OFFSET=32400000,DST_OFFSET=0]
- 얘도 참조형. toString 오버라이딩 되어 있음.
- 7월이지만 내부적으로는 6으로 인식됨.
- AM은 0을, PM은 1을 나타냄.
- get 메소드로 현재 날짜 및 시간 정보 따라 알아보기
// 현재 시스템 날짜 및 시간 정보로 설정
Calendar today = new GregorianCalendar();
System.out.println(today.get(1)); // get(1) 연도 //2024
System.out.println(today.get(2)); // get(2) 월 // 6 // 1월(0)~12월(11)
System.out.println(today.get(2) +1 ); // 7 (+1해줘야 지금 달이 나옴.)
System.out.println(today.get(5)); // get(3) 일 // 8
System.out.println();
// 이 필드에 대한 숫자값을 다 상수로 해놨음.
// 연도가 1이라는 것을 까먹었다. 그러면
// Calendar.YEAR하면 이게 1이다.
// [2024.07.08 11시 50분 34초]
System.out.println(today.get(Calendar.YEAR) ); // 2024
System.out.println(today.get(Calendar.MONTH) ); // 6
System.out.println(today.get(Calendar.MONTH +1) ); // 28 <- 이러면 이상한 값.
System.out.println(today.get(Calendar.MONTH) +1 ); // 7 <- 이렇개 해야함.
System.out.println(today.get(Calendar.DATE) ); // 8
System.out.println(today.get(Calendar.AM_PM) ); // 0 (AM은 0 PM은 1)
System.out.println(today.get(Calendar.HOUR) ); // 11
System.out.println(today.get(Calendar.HOUR_OF_DAY) ); // 11 (24시로보여줌)
System.out.println(today.get(Calendar.MINUTE) ); // 50 (50분)
System.out.println(today.get(Calendar.SECOND) ); // 34 (34초)
(2) 방법2. Calendar에서 제공하는 getInstance static 메소드를 이용
이러면 알아서 우리나라 locale에 맞춰서 그 국가별 시간대별에 맞게 반환해줌.
Calendar today = Calendar.getInstance(); // 그레고리안 객체가 반환됨.
System.out.println(today instanceof GregorianCalendar); // true
- today로 위와 동일하게 사용 가능.
Calendar today = Calendar.getInstance();
System.out.println(today instanceof GregorianCalendar);
System.out.printf("%d년 %d월 %d일 %d %d(%d)시 %d분 %d초 \n",
today.get(Calendar.YEAR), today.get(Calendar.MONTH) + 1,
today.get(Calendar.DATE), today.get(Calendar.AM_PM),
today.get(Calendar.HOUR), today.get(Calendar.HOUR_OF_DAY),
today.get(Calendar.MINUTE), today.get(Calendar.SECOND) );
[실행 결과]
true
2024년 7월 8일 1 0(12)시 8분 31초 // 12시가 넘었음.
ㅁ 내가 원하는 특정 날짜 및 시간으로 설정
(1) 방법1. 우선 생성 후 set으로 수정하기
Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.YEAR, 2100);
cal1.set(Calendar.MONTH, 11); // 12월로 설정하고 싶다면
cal1.set(Calendar.DATE, 31);
// 이런식으로 시분초도 할 수 있는데 생략.
// 한번에 설정하는 법(년 월 일 순으로 전달)
cal1.set(2100, 11, 31);
System.out.println(cal1); // 보기 어렵게 나옴. 근데 왜 MONTH=11로 나오지 <- 숫자로 11로 표시되지만 12월로 된거 맞음.
(2) 방법2. 객체 생성시 바로 값 전달하기
Calendar cal2 = new GregorianCalendar(2100, 11, 31, 3, 33, 33);
// 연 월 일 시 분 초
// 시분초 전달 안하면 00시 00분 00초
- 11 대신 Calendar.DECEMBER 도 가능.
ㅁ 일일이 값을 가져와서 printf로 힘들게 할 필요 없이, 쉽게 출력할 수 있는 클래스가 있음.
ㅁ < java.text.SimpleDateFormat >
- 날짜 및 시간정보를 내가 원하는 형식의 문자열로 변환시켜주는 객체
- 작성가능한 포맷에 대한 키워드
y(년도), M(월), d(일), h/H(시간 12시간제, 시간 24시간제), m(분), s(초) + E(요일)
- SimpleDateFormat sdf = new SimpleDateFormat("반영시키고자하는형식(포맷)");
sdf.format(날짜 및 시간정보의 객체) : String으로 반환함
sdf.format(날짜 및 시간 정보의 객체)는 주어진 날짜 및 시간 정보를 문자열로 변환하여 반환합니다.
//java.util.Date 객체
SimpleDateFormat sdf = new SimpleDateFormat("yyyy년 MM월 dd일 hh(HH):mm:ss");
sdf.format(new Date()); // format 메소드 호출시 Date형 객체를 전달 가능.
String a= sdf.format(new Date());
System.out.println(a); // 2024년 07월 08일 12(12):25:03 <- 현재시간
// 그런데 우리가 Date 객체를 쓰는건 지양한다고 했죠.
// 다국적으로 적합핮 ㅣ않기 때문에 Date보단 Calendar 객체를 사용하기로 했죠.\
// 우리가 가진 Calendar 객체를 저런 형식에 반영시키고자 한다면?
//java.util.Calendar 객체
String b = sdf.format(new GregorianCalendar());
// 혹은
String c = sdf.format(Calendar.getInstance());
// 근데 오류남. 캘린더 객체를 전달할 때는 곧바로 저기에 넣으면 안됨.
// 빨간줄 안떠서 실행될거같지만 안 됨.
// java.util.Calendar 객체 <- 날짜 및 시간 정보를 밀리초로 환산해서 전달해야 함.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy년 MM월 dd일 hh(HH):mm:ss");
String b = sdf.format(new GregorianCalendar().getTimeInMillis());
// 혹은
String c = sdf.format(Calendar.getInstance().getTimeInMillis());
System.out.println(b); // 2024년 07월 08일 12(12):30:32
System.out.println(c); // 2024년 07월 08일 12(12):30:32
// System.out.println(Calendar.getInstance().getTimeInMillis()); 이거는 long형이다 // 1720409516962
ㅁ java.time 패키지에 LocalDate, LocalTime, LocalDateTime이라는 클래스가 있다.
- 자바 8 이상부터만 사용 가능하다.
ㅁ < java.time.LocalDate | LocalTime | LocalDateTime >
- 자바 8 이상부터 사용 가능한 클래스
- 날짜만 | 시간만 | 둘 다의 정보를 가지는 클래스
- 얘네는 추상클래스가 아니지만 직접적으로 new로 생성이 불가능함.
- static 메소드인 now() 메소드를 이용하면 현재 날짜 및 시간 정보를 가져올 수 있다.
3개 다공통적으로 그렇다.
- 특정 세팅을 하고 싶다면 3개 다 공통적으로
static 메소드인 of() 메소드를 이용하면 특정 날짜 및 시간 정보를 설정할 수 있음.
(1)
// LocalDate
// LocalDate date1 = new LocalDate();
// 이렇게 객체 생성 불가능
// 추상클래스여서가 아니라 생성자가 정의되어 있지 않아서 그럼. 불변클래스라고 함.
LocalDate date1 = LocalDate.now(); // 이러면 됨.
System.out.println(date1); // 2024-07-08 (toString 메소드 오버라이딩 되어있따)
// 연 월 일 따로 알고 싶다면 getXxx 메소드 사용
System.out.println(date1.getYear()); // 2024
System.out.println(date1.getMonth()); // JULY 영문으로 반환시켜줌
System.out.println(date1.getMonthValue()); // 7 // +1처리 안해도 되서 캘린더 객체보다 더 쉽다.
System.out.println(date1.getDayOfMonth()); // 8
LocalDate date2 = LocalDate.of(2100, 12, 12); // 특정날짜 세팅. 연 월 일. // 월 -1할 필요가 없음.
System.out.println(date2); // 2100-12-12 // 날짜에 대한 정보만. 시간은 x
(2)
// LocalTime - 날짜에 대한 정보는 필요 없고 시간에 대한 정보만
// LocalDate date1 = new LocalDate(); // 이것도 생성자 불가능
LocalTime time1 = LocalTime.now();
System.out.println(time1); // 12:42:52.122494300 뒤는 나노초다.
// toString이 24시 분 초 나노초까지 하나의 문자열로 만들어서 반환 되게끔 해놨음.
// 나노초는 빼고 싶다면, substring같은거 쓰면됨.
//System.out.println(time1.substring// 이건 안됨. time1은 문자열 데이터가 아니고 LocalTime형 객체임.
System.out.println(time1.toString().substring(0, 8)); // 12:45:10 0번 인덱스부터 8-1번 인덱스까지..
// 특정 시간에 대한 정보를 세팅하고 싶다면 이때도 of 메소드
LocalTime time2 = LocalTime.of(18, 18, 18); // 이것 말고 시 분, 시분초나노초 생성자 매개변수 2개, 4개짜리도 있따.
System.out.println(time2); // 18:18:18 // 나노초는 세팅하지 않아서 시분초까지만 나옴.
// getHour() getMinute() getSecond() getNano() 등으로 이것만 빼올 수도 있음.
(3)
// LocalDateTime
LocalDateTime dateTime1 = LocalDateTime.now();
System.out.println(dateTime1); // 2024-07-08T14:05:31.338981900 toString 오버라이딩되어있음
/*
* @Override
public String toString() {
return date.toString() + 'T' + time.toString();
}
이렇게 되어있음.
*/
// substirng, indexOf 이런걸로 t와 나노초 없앨 수 있음.
// 이 객체 가지고도 겟먼스 겟미닛 이런거 다 됨.
LocalDateTime dateTime2 = LocalDateTime.of(2024, 12, 11, 13, 0); // 이러면 알아서 년월일시분으로 설정됨.
System.out.println(dateTime2); // 2024-12-11T13:00
// 6개 주면 초까지 나오고. of라는 메소드가 오버로딩되어있어서 3개만 전달할 수도 있고 더 전달할 수도 있고.
/*
LocalDateTime dateTime3 = LocalDateTime.of(LocalDate date, LocalTime time) // 숫자 주지 않고 LocalDate 객체, LocalTime 객체를 받을 수도있음.
System.out.println(dateTime3);
*/
// 얘도 포맷을 변형시킬 수 있음.
// LocalDateTime 객체를 원하는 형식으로 반영시켜서 출력하기
// 아까 배운 SimpleDateFormat 객체를 써도 되는데, 로컬데이트타임이랑 같이 쓰라고 ㄷ ㅓ편하게 만들어진게 있음.
// -> java.time.format.DateTimeFormatter
LocalDateTime dateTime22 = LocalDateTime.of(2024, 12, 11, 13, 30, 5);
System.out.println(dateTime22); // 2024-12-11T13:30:05
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일 E요일 hh(HH):mm:ss"); // 심플데이트포맷과 다른점. new로 생성하지 않고 정적ㅈ메소드로.
System.out.println(dtf.format(dateTime22)); // 2024년 12월 11일 수요일 01(13):30:05
ㅁ < java.util.UUID >
- Universal Unique Identifier
- 전역 고유 식별자 (한 프로그램 내에서 절대적으로 고유한 값)
절대 겹쳐서는 안되는 문자열을 만들어야할 때가 있을 거에요. 여기서 랜덤으로 만들 수 있는 메소드가 있음.
- 형식
16진수 32개와 하이픈(-) 4개로 구성되어 있음. 엄청 긴 문자열.
( 8자리 - 4자리 - 4자리 - 4자리 - 12자리 )
ex) 사용자가 업로드한 첨부파일명을 우리가 그대로 서버에 업로드 하면 안됨.
회원1이 a.text 파일 업로드, 회원2가 a.text 파일 업로드. 동일한 파일명으로 업로드할 수 있음. 또 공백 등 특수문자도.
(서버에 저장할때 파일명에 공백이나 특수문자, 중복파일 절대 있으면 안됨. 확장자는 당연히 있어야하고)
우리는 수정작업을 거쳐서 절대 겹치지 않게끔 수정작업해서 저장해야 한다.
이때 보통 UUID.radnomUUID();가 사용됨.
UUID uuid = UUID.randomUUID(); // 랜덤한 문자열이 UUID 타입으로 반환됨.
System.out.println(uuid); // 484f97a9-4a43-4ade-9067-43f5bcb40a0a(계속 달라짐) // toString 오버라이딩되어잇음.
// String result = uuid; // 불가능.
String result = uuid.toString();
System.out.println(result); // 484f97a9-4a43-4ade-9067-43f5bcb40a0a (위랑 같음. 실행할때마다 달라지지만)
- 하이픈 없애려면 replace 사용.
// 내가 test.txt 파일을 받았다고 가정
String originalFilename1 = "test.txt"; // 회원1이 업로드 요청한 파일의 원본명
String originalFilename2 = "test.txt"; // 회원2가 업로드 요청한 파일의 원본명
// 파일명 수정 작업 : 고유한문자열(UUDI로 만들예정) + 기존의확장자(.txt)
int a = originalFilename1.indexOf(".txt");
System.out.println(a); // 4
String aa = originalFilename1.substring(a);
System.out.println(aa); // .txt
// 그런데 확장자 이전에 파일 이름에 .이 중간에 찍혀있을 수도 있음. 그러면?
- 지정된 문자열 str이 문자열에서 처음 등장하는 위치(인덱스)를 반환합니다. 문자열에서 해당 문자열이 없으면 -1을 반환합니다.
- indexOf는 없으면 -1을 반환함.
// 제일 뒤에서부터 있는 .을 찾으면 됨. lastIndexOf 쓰기.
int b = originalFilename1.lastIndexOf(".txt");
System.out.println(b); // 4
String bb = originalFilename1.substring(b);
System.out.println(bb); // .txt
// 좀더 간결하게 하면
String cc = originalFilename1.substring(originalFilename1.lastIndexOf(".txt"));
System.out.println(cc); // .txt
// 새로운 파일명 만들기
String newFilename1 = UUID.randomUUID().toString().replace("-", "") + aa;
System.out.println(newFilename1); // 3df3ff8392d84fa19e64374e3d8acd60.txt (매번바뀜.)
'클라우드 활용 자바개발자 양성과정 > 01. JAVA 프로그래밍 언어 활용' 카테고리의 다른 글
13. 컬렉션 Collection (0) | 2024.07.10 |
---|---|
11. 예외처리 (0) | 2024.07.09 |
08. 상속 Inherit & 09. 다형성 Polymorphism (1) | 2024.07.03 |
07. 객체 배열 (0) | 2024.07.02 |
06. 객체 (0) | 2024.06.27 |