본문 바로가기

프로그래밍/JAVA

[JAVA 이론] java.lang package & util classes

java.lang패키지는 자바프로그래밍에 가장 기본이 되는 클래스들을 포함하고 있다. 그렇기 때문에 java.lang패키지의 클래스들은 import문 없이도 사용할 수 있게 되어 있다.

 

Object클래스

Object클래스는 모든 클래스의 최고 조상이기 때문에 Object클래스의 멤버들은 모든 클래스에서 바로 사용 가능하다. Object클래스는 맴버변수는 없고 오직 11개의 메서드만 가지고 있다. 이 메서드들은 모든 인스턴스가 가져야 할 기본적인 것들이다.

 

protected Object clone()

객체 자신의 복사본을 반환한다.

cloneable인터페이스를 구현 클래스의 인스턴스만 clone()을 통한 복제가 가능한데, 그 이유는 인스턴스의 데이터를 보호하기 위해서이다.

 

- 공변 반환타입

JDK1.5부터 '공변 반환타입'이라는 것이 추가되었는데, 이 기능은 오버라이딩할 때 조상 메서드의 반환타입을 자손 클래스의 타입으로 변경을 허용하는 것이다.

public Object clone() {
	Object obj = null;
	try {
		obj = super.clone();
	}catch(CloneNotSupportedException e) {}
	return (Point)obj;
}

java.util패키지의 Vector, ArrayList, LinkedList, HashSet, TreeSet, HashMap, TreeMap, Calender, Date와 같은 클래스 들은 Object클래스를 상속받으며, 동시에 Cloneable인터페이스와 Serializable인터페이스가 구현되어 있다.

따라서, 아래와 같이 복사가 가능하다.

int[] arr = {1, 2, 3, 4, 5}
int[] arrClone = arr.clone();

//int[] arrClone = new[arr.length];
//System.arraycopy(arr, 0, arrClone, arr.length);

 

- 앝은 복사와 깊은 복사

얕은에서는 원본을 변경하면 복사본도 영향을 받는다. 그 이유는 원본과 복제본이 같은 객체를 공유하기 때문이다. 반면에 깊은 복사는 원본이 참조하고 있는 객체까지 복제한다. 원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 변경이 복사본에 영향을 미치지 않는다.

 

public boolean equals(Object obj)

객체 자신과 객체 obj가 같은 객체인지 알려준다.(같으면 true)

public boolean equals(Object obj){
	return (this == obj);
}

cf) String클래스뿐만 아니라, Data, File, wrapper클래스(Integer, Double 등)의 equals메서드도 주소값이 아닌 내용을 비교하도록 오버라이딩 되어있다.

 

protected void finalize()

객체가 소멸될 때 가비지 컬렉터에 의해 자동적으로 호출된다. 이때 수행되어야하는 코드가 있을 때 오버라이딩한다.(거의 사용안함)

 

public Class getClass()

객체 자신의 클래스 정보를 담고 있는 Class인스턴스를 반환한다.

public final class Class implements ... { //Class클래스
	...
}

1. 자신이 속한 클래스의 Class객체를 반환하는 메서드인데, Class객체는 이름이 'Class'인 클래스의 객체이다. 

2. Class객체는 클래스의 모든 정보를 담고 있으며, 클래스 당 1개만 존재한다.

3. 클래스 파일이 클래스 로더에 의해서 메모리에 올라갈 때, 자동으로 생성된다. 

4. 클래스로더는 실행 시에 필요한 클래스를 동적으로 메모리에 로드하는 역할을 한다.

5. 먼저 기존에 생성된 클래스 객체가 메모리에 존재하는지 확인하고, 있으면 객체의 참조를 반환하고 없으면 클래스 패스에 지정된 경로를 따라서 클래스 파일을 찾는다. 못 찾으면 ClassNotFoundException이 발생하고, 찾으면 해당 클래스 파일을 읽어서 Class객체로 변환한다.

 

- Class객체를 얻는 방법

Class obj = new AAA().getClass(); //생성된 객체로 부터 얻는 방법
Class obj = AAA.class; //클래스 리터럴(*.class)로 부터 얻는 방법
Class obj = AAA.forName("Card"); //클래스 이름으로 부터 얻는 방법

AAA obj = new AAA(); //new 연산자를 이용해서 객체 생성
AAA obj = AAA.class.newInstance(); //Class객체를 이용해서 객체 생성

 

public int hashCode()

객체 자신의 해시코드를 반환한다.

cf) String클래스의 경우 문자열이 같으면 같은 hashCode를 반환하지만 System.identityHashCode(object x)의 호출결과는 달라질 수 있다.

 

public String toString()

객체 자신의 정보를 문자열로 반환한다.

public String toString(){
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

cf) toString()은 일반적으로 인스턴스나 클래스에 대한 정보 또는 인스턴스 변수들의 값을 문자열로 변환하여 반환하도록 오버라이딩되는 것이 보통이다.

 

public void notify()

객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨운다.

 

public void notifyAll()

객체 자신을 사용하려고 기다리는 모든 쓰레드를 깨운다.

 

public void wait() /public void wait(long timeout) / public void wait(long timeout, int nanos)

다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 현재 쓰레드를 무한히 또는 지정된 시간(timeout, nanos)동안 기다리게 한다.(timeout은 천 분의 1초, nanos는 1/10의9승 초)

 

String클래스

변경 불가능한(immutable) 클래스

String클래스에는 문자열을 저장하기 위해서 문자형 배열 참조변수(char[]) value를 인스턴스 변수로 정의하고 있다.

public final class String implements java.io.Serializable, Comparable{
	private char[] value;
    	...

한번 생성된 String인스턴스가 갖고 있는 문자열은 읽어 올 수만 있고, 변경 할 수 는 없다. +연산을 해도 문자열이 바뀌는 것이 아닌 새로 생성 되는 것이다.

 

문자열의 비교

String str = "abc"; //문자열 리터럴을 지정하는 방법 
String str1 = "abc";
str == str1 //true

String str2 = new String("abc"); //String클래스의 생성자를 사용해서 만드는 방법
str == str2 //false

문자열 리터럴은 이미 존재하는 것을 재사용하고, new연산자는 의해서 메모리 할당이 각 각 일어난다. 

 

- 문자열 리터럴

1. 컴파일 시에 클래스 파일에 저장

2. 같은 내용의 문자열 리터럴은 한번만 저장

3. 클래스 파일이 클래스 로더에 의해 메모리에 올라갈 때, 이 리터럴의 목록에 있는 리터럴들이 JVM내에 있는 상수 저장소에 저장 됨

 

- 빈 문자열

길이가 0인 char형 배열을 문자열은 저장이 가능하다.

 

String클래스의 생성자와 메서드

- java.lang.String 클래스 참고

https://docs.oracle.com/javase/8/docs/api/index.html

 

Java Platform SE 8

 

docs.oracle.com

 

- join()과 StringJoiner

String s = "a,b,c";
String[] arr = s.split(","); //a b c
String str = String.join("-", arr); //a-b-c

Stringjoiner sj = new StringJoiner(",", "[", "]");
for(String temp: arr)
	sj.add(temp);

System.out.println(sj.toString()); //[a,b,c]

 

- 문자 인코딩 변환

byte[] uft8_str = "가".getBytes("UTF-8"); //문자열을 UTF-8로 변환
String str = new String(uft8_str, "UTF-8"); //byte배열을 문자열로 변환

java.nio.charset.Charset.availableCharsets() //사용가능한 문자 인코딩 목록

 

- String <-> 기본형

//기본형 -> String
String str = String.valueOf(i); 

//String -> 기본형
int i = Integer.parseInt("100");
int i = Integer.valueOf("100");

 

StringBuffer클래스와 StringBuilder클래스

- String Buffer클래스

내부적으로 가지고 있는 버퍼에 문자열을 저장하며, 문자열의 추가, 삭제, 수정 등을 지원합니다. 이를 통해 문자열을 다루는 작업에서 메모리 할당과 해제를 반복하지 않아도 되므로 성능이 향상됩니다. 또한, StringBuffer 인스턴스를 생성할 때 버퍼의 크기를 지정할 수 있으며, 이를 통해 문자열의 크기를 미리 예측하여 메모리를 효율적으로 사용할 수 있습니다.

 

여기서 말하는 버퍼란, 문자열을 조작할 때 문자열을 바로바로 조작하는 것이 아니라, 조작할 문자열을 임시적으로 저장하는 메모리 공간을 의미합니다.

 

StringBuffer 클래스의 내부 구현에서 문자열 버퍼는 동적으로 할당되는 char 배열에 저장됩니다. 이 char 배열의 크기는 StringBuffer 인스턴스를 생성할 때 지정한 초기 버퍼 크기에 따라 결정됩니다. 만약 초기 버퍼 크기를 지정하지 않으면, 기본값인 16으로 설정됩니다.


문자열이 추가되면, StringBuffer 클래스는 내부 char 배열의 크기를 자동으로 늘리고 문자열을 추가합니다. 이 때, 문자열의 추가를 위해 할당된 메모리 영역이 부족해지면, 보다 큰 크기의 char 배열을 새로 할당하고, 기존의 문자열을 새로운 배열로 복사하게 됩니다. 이러한 동작을 자동으로 수행하기 때문에 문자열 추가 작업을 수행할 때마다 매번 새로운 문자열 객체를 생성하는 String 클래스에 비해 메모리 할당 및 복사에 대한 오버헤드가 줄어들게 됩니다.


StringBuffer 클래스는 멀티스레드 환경에서 동기화를 보장하기 위해 synchronized 키워드가 적용되어 있습니다. 이와는 달리, StringBuilder 클래스는 단일 스레드 환경에서 사용하기 위해 만들어진 클래스로, synchronized 키워드가 없습니다. 따라서 StringBuilder 클래스는 StringBuffer 클래스에 비해 좀 더 높은 성능을 가집니다.

 

java.lang.StringBuffer 클래스 참고

https://docs.oracle.com/javase/8/docs/api/index.html

 

Java Platform SE 8

 

docs.oracle.com

 

- String Builder클래스

String Builder 클래스는 StringBuffer 클래스와 거의 유사하지만, 멀티스레드 환경에서 안전하지 않은 StringBuffer의 단점을 보완한 클래스입니다. 따라서 단일 스레드 환경에서는 StringBuffer 대신에 String Builder를 사용하는 것이 성능상 이점이 있습니다. String Builder는 StringBuffer와 같이 동적인 문자열 변경을 지원하며, StringBuilder 인스턴스를 생성할 때도 버퍼의 크기를 지정할 수 있습니다.

 

StringBuilder는 StringBuffer와 기본적인 동작 방식은 동일하지만, StringBuilder는 동기화(synchronization)를 제공하지 않습니다. 이것은 멀티스레드 환경에서 여러 스레드가 동시에 접근해도 안전하다는 것을 의미합니다.

StringBuffer는 멀티스레드 환경에서 안전하도록 설계되어 있지만, 이러한 동기화를 위한 비용이 추가되어 성능 저하를 가져올 수 있습니다. 따라서 단일 스레드 환경에서는 StringBuilder를 사용하는 것이 더욱 효율적입니다.

StringBuilder는 문자열을 변경하는 작업에서 StringBuffer와 같은 API를 제공하며, 내부적으로도 StringBuffer와 유사한 방식으로 동작합니다. 따라서 StringBuffer의 단점을 보완하면서도 성능을 향상시킬 수 있는 장점을 갖고 있습니다.

 

 

java.lang.StringBuilder 클래스 참고

https://docs.oracle.com/javase/8/docs/api/index.html

 

Java Platform SE 8

 

docs.oracle.com

 

Math클래스

Math클래스는 기본적인 수학계산에 유용한 메서드로 구성되어 있다.

 

Math클래스의 특징

1. Math클래스의 생성자는 접근 제어자가 private이기 때문에 다른 클래스에서 Math인스턴스를 생성할 수 없다.

2. 클래스 내에 인스턴스변수가 하나도 없어서 인스턴스를 생성할 필요가 없다.

3. Math클래스의 메서드는 모두 static이며, 자연로그와 원주율 만을 상수로 정의하고 있다.

 

예외를 발생시키는 메서드

변수의 최대값을 ~a+1 하면 예외 발생

int addExact(int x, int y); //x + y
int subtractExact(int x, int y); //x - y
int mutiplyExact(int x, int y); //x * y
int incrementExact(int x, int y); //x++
int decrementExact(int x, int y); //x--
int negateExact(int x, int y); //-x
int toIntExact(int x, int y); //(int)value - int로의 형변환

 

java.lang.Math 클래스 참고

https://docs.oracle.com/javase/8/docs/api/index.html

 

Java Platform SE 8

 

docs.oracle.com