Java.lang
패키지는 자바 프로그래밍 언어 디자인에서 가장 기본적인 클래스들을 제공한다. 그렇기 때문에 보통은 import를 통해 패키지를 가져오나 이 패키지는 안해도 그냥 사용할 수 있다. 내 추측인데 lang은 language가 아닐까,, 가장 중요한 클래스인 Object(클래스 계급의 가장 최상위)를 비롯해 다양한 클래스들이 존재한다.
내가 생각하는 패키지의 개념은 클래스들의 모음이며, 비슷한 기능을 하는 클래스들을 모아주는 장점을 가진다고 가볍게 생각했다.
(근데 사실 비슷한 기능을 하는걸 묶어주는게 왜 좋아? 라고 하면 대답못함..)
w3schools에 따르면 더 좋은 maintainable code를 작성할 수 있다고 하는데 나는 잘 와닿지 않는다!
또 !! 다른 사람이 작성한 자바 클래스나 라이브러리도 사용할 경우에, 클래스명이 겹친다면 패키지를 통해 구분할 수 있다!
(만약 우리가 import해올 때 sk폴더에서도 Example클래스를, yw폴더에서도 Example클래스를 가져올 때 패키지가 없다면 어떻게 구분해줄 것인가?)
= 클래스 계급의 뿌리
= 모든 클래스는 superclass로 Object 클래스를 가짐
= 배열을 포함한 모든 object는 이 클래스의 메서드를 포함하고 있움
원시 타입의 값을 대표하는 데 필수적이다.
ex. Double
타입의 Object는, 타입이 double인 필드(참조형의 변수에 저장될 수 있는 방식으로 값을 나타내는)를 포함한다.
오직 11개의 메서드만을 가진다.
clone()
자기 자신을 복제해서 새로운 객체를 생성하는 메서드 (shallow copy)
멤버변수의 값 만을 복제
(배열
이라면, 오버라이딩 하여 내용도 복제해야 함)
Cloneable 인터페이스를 구현한 클래스의 인스턴스만 복제 가능
(만약 그렇지 않다면 CloneNotSupportedException
이 던져짐
-> Object
클래스는 Cloneable
인터페이스를 포함하지 않으므로 Object 클래스가 클래스일 때 clone 메서드를 호출하며 런타임 시 예외가 발생한다)
알아두면 좋을 속성
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
위에서 설명했던 것처럼 값
만을 복제하므로 값이 같기 때문에 리터럴리 값을 비교하는 equals 메서드에서도 true, 당연히 같은 값을 복제했으므로 class도 같을 것이므로 true, 하지만 주소값이 같은지 ==으로 묻는다면 새로운
객체를 생성한다는 의미를 가지므로 주솟값은 무조건 다르니까 false!!
equals(Object obj)
hashCode()
메서드의 일반적인 contract(계약?)을 위해, 이 메서드를 재정의 할 때마다 hashCode()
메서드를 재정의할 필요가 있다.++Void
클래스는 void 타입을 나타내는 Class Object는 참조하기 때문에 인스턴스화가 불가능하다.
finalize()
[다시 읽어보자]public class getClass()
= 객체 자신의 정보를 담은 Class 인스턴스를 반환
public int hashCode()
= 객체의 해시 코드 값을 반환하는 메서드
= HashMap에서 제공하는 것과 같은 해시 테이블의 이점을 위해 사용됨
hashCode()
는 객체의 equals 비교에 사용되는 정보가 수정되지 않는 한 일관되게 동일한 정수를 반환해야 한다(must!!).equals(obj)
메서드에 따라 두 객체가 동일하지 않을 경우, 두 객체는 고유한 hashCode 값을 생성해야 한다(must!!). 이때 같지 않은 객체에 대해 고유한 정수 결과를 생성하면 hash table의 성능이 향상된다는 점을 조심해야 한다!hashCode()
는 객체의 주솟값으로 해시코드를 생성하므로 두 인스턴스의 해시 코드는 같을 수 없다. //혼자 궁금해서 끄적여본 예시
int[] arr = new int[5];
System.out.println(arr.hashCode());
//그야말로 arr과 동일한 배열 객체를 생성
int[] arr2 = arr;
System.out.println(arr2.hashCode());
//얕은 복사를 통해 새로운 배열 객체를 생성
int[] arr3 = arr.clone();
System.out.println(arr3.hashCode());
//출력결과
2055281021
2055281021
1554547125
public String toString()
= 객체의 정보를 문자열로 제공할 목적으로 정의한 메서드
public void notify()
= 객체 자신을 사용하려고 기다리는 스레드 하나만 깨우는 메서드
wait()
메서드를 호출함으로써 객체의 감시를 기다린다. synchronized
문장의 body(구현부?)를 실행(객체에서 동기화되는)notifyAll()
notify()
와 비슷하다.wait()
(throws InterruptedException)notify()
나 notifyAll()
을 호출할 때까지 기다리도록 한다. 다른 말로, 이 메서드는 마치 wait()
를 수행하는 것처럼 정확히 행동한다.notify()
나 notifyAll()
호출을 통해 깨우도록 알릴 때까지 기다린다. 그리고 소유권을 다시 얻을 때까지 기다린다.synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
wait(long timeout)
[정해진 대기 시간 존재]notify()
를 호출하고 현재 스레드는 깨울 스레드로 임의로 선택된다.notifyAll()
를 호출한다.wait()
가 호출된 시점의 상황으로 복원된다. 다음 스레드는 wait()
호출에서 반환된다.spurious wakeup
으로 깨울 수 있다. 이런 현상이 흔치 않게 발생하는 동안, applications은 스레드를 깨워야 하는 조건을 테스트하고 조건이 충족되지 않으면 계속 대기하여 방지해야 한다. //대기는 아래의 예시처럼 루프에서 발생해야 한다.
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
InterruptedException
이 던져진다.( spurious wakeup: wait()
호출 중에 스레드가 깨어나는 현상)
( 스레드 스케쥴링: 스레드의 개수가 코어의 수보다 많을 경우, 스레드를 어떤 순서에 의해 동시성을 실행할 것인지 결정하는 것 => 스케쥴러에 의해 여러 개의 스레드가 짧은 시간 동안 번갈아가며 스레드의 run()
을 실행)
wait(long timeout, int nanos)
[정밀한 추가 시간 존재]1000000*timeout+nanos(ns)
로 측정된다.notify()
나 notifyAll()
를 호출하여 깨우도록 알릴 때이 메서드는 이 객체 모니터의 주인인 스레드에 의해서만 불려진다.
※ wait 메서드를 호출하기 전에 해당 객체의 모니터 락을 획득해야 함!
(아니라면 IllegalMonitorStateException
을 발생시킴!)
wait과 notify에 대한 예시가 궁금하여 ChatGPT를 활용해보았다. 녀석 나보다 똑똑하다...
class Message {
private String content;
private boolean isDelivered = false;
public synchronized void send(String message) {
while (isDelivered) {
try {
wait(); // 다른 스레드에 의해 notify() 호출 시까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.content = message;
isDelivered = true;
notifyAll(); // 대기 중인 다른 스레드들을 깨움
}
public synchronized String receive() {
while (!isDelivered) {
try {
wait(); // 다른 스레드에 의해 notify() 호출 시까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String receivedMessage = content;
isDelivered = false;
notifyAll(); // 대기 중인 다른 스레드들을 깨움
return receivedMessage;
}
}
Message 클래스 안에는 send와 receiver 메서드가 있고, 이는 메시지를 보내고 받는 기능을 담당한다. 두 과정은 동기화 되어야 한다. 이를 synchronized
키워드를 사용하여 보장해준다. isDelivered
변수로 메시지 전달 여부를 확인하고, 메시지가 전달되지 않았을 때만 스레드를 대기 상태로 보낸다. 여기서는 wait
메서드를 활용하여 스레드 간의 메시지 전달을 조절한다.
String
클래스는 문자 string을 대표한다. 모든 문자열 리터럴(ex. "abc")은 이 클래스의 인스턴스로서 구현된다.
** 여기서 문자열
은 문자의 배열
로, 예를 들어 "hello"가 있다면 각각의 다섯개 글자를 나열한 것이다.
할당하는 방법은 1. 문자열 리터럴 생성 2. new 연산자 이용 이렇게 두가지가 있다.
그러나 두 가지는 리터럴을 사용하면 String Constant Pool
영역(Java 7부터 heap 영역으로 옮겨졌다고 함)에, new 연산자는 메모리의 heap
영역에 할당된다는 차이점을 지닌다.
String
은 상수이다(불변-thread safe).StringBuffer
가 변할 수 있는 문자열을 지원한다.StringBuilder
를 주로 사용한다.//아래의 두 코드는 동일
String str = "abc";
char data[] = {'a', 'b', 'c'};
String str2 = new String(data);
//예시
String cde = "cde";
String c = "abc".substring(2, 3);
String d = cde.substring(1, 2);
연결 연산자(+)
를 지원하고, 다른 객체에서 문자열로의 변환
을 지원한다.String concatenation(연결)
은 StringBuilder or StringBuffer
클래스와 append
메서드를 통해 구현된다.toString()
을 통해 구현된다. null
인자를 주면 NullPointerException
이 발생한다.|u0000
이나 공백으로 초기화 해줘야 한다.)String(String s)
주어진 문자열 s를 값는 String 인스턴스를 생성
String s = new String("Hello");
String(char[] value)
주어진 문자열을 갖는 String 인스턴스를 생성
String(StringBuffer buf)
StringBuffer 인스턴스가 갖는 문자열과 같은 내용의 String 인스턴스 생성
이거 외에도 생성자 굉장히 많다.. 여기 참조
메서드는 코테를 풀며 익히 알고있는 메서드가 많이 때문에 내가 모르는 거 위주로 작성하겠따.
아래의 메서드 외에도 정~~말 많은 메서드가 있으니 궁금하다면 더 찾아보면 좋겠다.
static String copyValueOf(char[] data)
valueOf(char[])
과 동일
static String valueOf(char[] data, int offset, int count)
valueOf(char[], int, int)
와 동일함
=> char 배열의 offset 인덱스부터 count개까지의 sub 배열을 반환
int codePointAt(int index)
특정한 위치의 문자(Unicode code point)를 반환
** code point
= 숫자(문자를 대표하는 시스템에서 추상적인 문자를 대표하는데 사용되는)
int codePointBefore(int index)
특정 인덱스 전의 문자를 반환
int compareToIgnoreCase(String str)
두 문자열을 대문자, 소문자에 상관없이 글자만 놓고 비교
String concat(String str)
특정 문자열을 이 문자열의 끝까지 붙이는 것
boolean contentEquals(CharSequence cs)
이 문자열을 특정한 CharSequence와 비교
boolean endsWith(String suffix)
이 문자열이 특정한 문자로 끝나는지 확인
byte[] getBytes()
플랫폼의 기본 문자 집합을 사용하여 이 문자열을 일련의 byte로 인코딩하고 결과를 새 바이트 배열에 저장
String str = "Hello World";
Byte[] encode = Str.getBytes();
//문자열을 인코딩된 Byte 형태로 넘겨줌
intern()
constant pool
에 등록하는데 이때 같은 내용의 문자열이 있다면 그 문자열의 주소값을 반환String s1 = new String("abc");
String s2 = new String("abc");
boolean y1 = s1.intern() == s2.intern() //true!!!!
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
두 문자열의 특정 지역이 동일한지 비교
String trim()
앞뒤로 공백을 없앤 결과를 반환(중간의 공백은 제거되지 않음)
join(CharSequence delimiter, CharSequence... elements)
String[] arr = {"딸기", "당근"};
String s = String.join("", arr);
System.out.println(s);
// 딸기당근
가장 큰 이점은 caching, security, synchronization, performance(결론적으로 성능 향상에 도움이 된단 소리임)이다. 읽어보면 당연한 소리이지만, 키워드에 대해 한번 고민해보지 않으면 바로 떠오르는 이점은 아니기 때문에 정리해본다.
caching
문자열 리터럴을 캐싱하고 재사용하는 것은 heap 영역에서의 엄청난 공간 효율성을 제공한다. 왜냐면 다른 문자열 변수는 String pool에서 같은 객체를 참조하기 때문! Java String Pool
은 String이 JVM에 저장된 특별한 메모리 영역이다.
=> intern()
메서드를 통해 이뤄짐
Security
String은 자바 어플리케이션에서 민감한 정보(비밀번호, 네트워크 연결, ..)를 저장하기 위해 사용된다. 그러므로 String은 전체 응용 프로그램의 보안과 관련해 String class를 보호하는 것이 중요하다. 이때 만약 문자열이 변경 가능하다면, 업데이트를 실행할 때까지 보안 검사를 한 후에도 받은 문자열이 안전할 지 확신할 수 없다!!
void criticalMethod(String userName) {
// perform security checks
if (!isAlphaNumeric(userName)) {
throw new SecurityException();
}
// do some secondary tasks
initializeDatabase();
// critical task
connection.executeUpdate("UPDATE Customers SET Status = 'Active' " +
" WHERE UserName = '" + userName + "'");
}
Synchronization
자동적으로 불변한 것은 다양한 스레드들이 접근했을 때 변하지 않기 때문에 String을 thread-safe하게 만든다.
Hashcode Caching
String 객체는 충부하게 데이터 구조로서 사용된다. 그들은 HashMap, HashTable, .. 과 같은 hash 구현체들에서 넓게 사용된다. 이 구현체들로부터 작동되면, hashCode
메서드가 빈번하게 bucketing
을 위해 호출된다.
=> hashCode
메서드는 캐싱을 용이하게 하기 위해 String 클래스에서 재정의되어 첫번째 메서드 호출 중에 hash가 계산 및 캐싱되고 그 이후로 동일한 값이 반환된다.
** 반면 문자열은 작업 후 내용이 수정됐을 경우 삽입 및 검색 시 두 개의 다른 해시 코드를 생성하여 map에서 값 객체를 잃을 가능성이 있다,,,
String이 불변하기 때문에 문자열의 변환이 많이 일어나는 경우에는 새로운 문자열 객체가 생겨나고 GC가 활발히 작동하여(변경되기 전의 문자열은 참조 대상이 사라졌으므로 GC의 대상이 됨) 효율이 매우 낮아진다. 우리는 이때 String 데이터 변경을 위해 자바에서 제공하는 StringBuffer
클래스를 사용한다 (++StringBuilder
클래스/기본적으로 두 객체가 제공하는 기능은 동일)
String
처럼 문자열 배열(char[]
, buffer라 불림)을 내부적으로 가지고 있다.public final class StringBuffer implements java.io.serializable {
private char[] value;
}
그렇지만 String
보다 char[]
를 좀 더 유연하게 사용할 수 있다. 기본적인 크기(16)이 존재하고 조절할 수 있다.
StringBuffer sb = new StringBuffer("abc");
sb.append("def");
String
클래스와 달리 equals()
를 오버라이딩 하지 않는다.
그래서 toString()
메서드를 활용해 String
으로 바꿔준 뒤 비교한다.
인스턴스 생성 시 버퍼의 크기를 충분히 지정해주는 것이 좋다.
(버퍼가 작으면 성능이 저하됨)
public StringBuffer(String str) {
this(str.length()+16);
append(str);
}
StringBuffer()
StringBuffer(int length)
StringBuffer(String str)
int capacity()
StringBuffer 인스턴스의 버퍼 크기를 알려줌
StringBuffer delete(int start, int end)
start부터 end 사이의 문자를 제거(마지막 위치의 문자는 제외)
StringBuffer insert(int pos, 자료형~)
두 번째 매개변수의 값을 문자열로 변환해 pos 위치에 추가
StringBuffer reverse()
저장돼 있는 문자열의 순서를 거꾸로 바꿈
void setLength(int newLength)
지정된 크기로 문자열의 길이를 변경
** 크기를 늘린다면 나머지 공간을 null 문자로 채움
Math
클래스는 흔히 사용되는 수학적인 함수들(ex. sine, cosine, square root)을 제공한다. 또한 모두 static 메서드로 구성된다. 기본적으로 많은 java.lang.Math
의 메서드는 StrictMath
클래스의 메서드를 호출한다. 다만 두 클래스의 차이는 StrictMath
는 어떤 시스템에서 수행되던 간에 동일한 값을 리턴한다는 점(native method)이다.
자료형 abs(자료형)
절댓값 반환
static double cell(double a)
주어진 값을 올림하여 반환
ex. double d = Math.ceil(10.1) => 11.0
static double floor(double a)
주어진 값을 버림하여 반환
ex. double d = Math.floor(10.1) => 10.0
static 자료형 min/max
주어진 두 값을 비교해 더 크고 작은 쪽을 반환
static double random()
0.0(이상)~1.0(미만) 범위의 임의의 double 값을 반환
statuc double rint(double a)
주어진 dobule 값과 가장 가까운 정수값을 double 형으로 반환
static long round(double/float a)
소수점 첫째 자리에서 반올림한 double형 정수 값을 반환
기본형을 클래스로 정의한 클래스이다. (어감이 이상하다)
이쯤에서 읽어보면 좋을 기본형과 wrapper 클래스의 차이 및 각각의 특징
기본적인 내용은 위에서 확인하면 된다! (나름 자세해용b)
equals()
를 오버라이딩 한다.ClassLoader, Process, ProcessBuilder, Runtime, SecurityManager, System 클래스
는 클래스의 다이나믹 로딩, 외부 프로세스의 생성, 시간과 같은 host 환경 문의(??), 보안 정책 강제 작동과 같은 "시스템 작동"을 제공한다.
Throwable
클래스는 throw될 object를 포함한다. 대표적인 서브 클래스의 예시가 앞선 단원의 에러와 예외이다..
자바의 정석, 2nd Edition.
https://docs.oracle.com/javase/8/docs/api/java/lang/package-summary.html
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
https://codedragon.tistory.com/5346
https://www.baeldung.com/java-string-immutable
https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html