✅ 1. java.lang 패키지란?
import java.lang.*;
- Java에서 가장 기본적이고 자주 사용되는 클래스들을 모아놓은 패지키를 의미한다.
- java.lang 패키지는 모든 클래스의 자동으로 import가 되기 때문에 별도로 import를 이용해 사용을 하지 않아도 된다.
- 위의 코드처럼 컴파일 시 모든 코드에 해당 import 문이 상단에 붙게 된다.
- java.lang 패키지 내부에는 String, Object, Thread, System 등 자바에서 가장 기본이 되는 클래스들이 들어가 있음.
✅ 2. Object 클래스
// 컴파일 전
public class MyClass {
}
// 컴파일 후 -> .class
public class MyClass extends Object {
}
- 자동으로 모든 클래스의 조상이 되는 클래스이며, 클래스 계층 구조에서 루트가 되는 클래스이다.
- 해당 Object 클래스는 모든 클래스가 자동으로 상속을 받고 있기에 상속 구조에서 최상위 클래스가 된다.
- 이건 컴파일 시점에 컴파일러가 자동으로 상속이 없는 클래스에 extends Object를 자동으로 붙여주기 떄문이다.
(1) Object 클래스가 가지고 있는 주요 메서드
protected Object clone() // 객체를 복제하여 반환
public boolean equals(Object obj) // 같은 객체인지 참조값으로 비교
public int hashCode() // 객체를 식별하는 정수값을 반환
public String toString() // 객체를 문자열로 반환
(2) toString()
// Object.class
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 객체를 문자열로 표현한 결과를 반환하는 메서드이다.
- 클래스이름@16진수해시코드로 표현을 해서 String 즉, 문자열로 반환을 해준다.
(3) equals()
// Object.class
public boolean equals(Object obj) {
return (this == obj);
}
- 두 객체 변수를 비교해서, 변수가 가리키는 객체의 참조값이 같으면 true를 반환 ( 즉, 객체 검증을 할 때 사용 )
- 해당 메서드는 자바의 == (동등비교연산자) 를 사용해서 비교를 하고 있음. 즉, 그냥 동등비교연산자라고 생각하면됨.
(4) clone()
// Object.class
@IntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
// Cloneable interface
package java.lang;
public interface Cloneable {
}
- Java에서 객체를 복제하기 위해 사용하는 메서드이다.
- 모든 클래스는 Object를 상속 받고 있기 때문에 모든 클래스에서 사용이 가능하지만 조건이 붙는다.
- 해당 클래스가 Cloneable 인터페이스를 implements 해야하며, 해당 clone()를 직접 구현해야지만 사용이 가능하다.
- clone을 하면, 해당 객체 내부의 들어가있는 값 자체도 복사가 되며, 참조값이 다른 똑같이 생긴 객체를 만들어준다.
- 이러한 부분은 예외처리 할 때 try() 메서드문의 자동 인터페이스 -> close() 메서드와 같은 방식으로 동작을 한다.
(5) getClass()
// Object.class
@IntrinsicCandidate
public final native Class<?> getClass();
- 현재 객체의 실제 클래스 정보를 반환한다. 즉, 클래스 정보를 가진 Class 객체를 리턴하게 된다.
- 해당 메서드는 native 즉, JVM이 네이티브 코드(C/C++)로 구현했다는 의미이다.
- 즉, Java 소스 코드가 아닌 JVM 내부에서 다른 언어를 통해 처리가 되므로, 메서드 바디는 확인 할 수 없다.
- 반환 타입 Class<?>은 보통 Java의 리플렉션에서 사용이 된다.
- JVM은 Dog클래스가 있다치면, 클래스를 메모리에 로드하면서 Class<Dog> 객체도 내부에서 자동으로 생성을 해둔다.
- 이건 네이티브 영역에서 진행이 된다.
- JVM은 클래스를 처음 "로드(load)"할 때, Class<?> 객체를 내부에서 생성하며, 그 안에 해당 클래스의 모든 정보를 "내장된 구조"를 통해 채워 넣습니다.
- "JVM은 클래스를 하나의 데이터 객체로 다룰 수 있도록 Class<?>라는 구조를 미리 설계해놓고, 클래스를 로딩하면서 거기에 정보를 채워넣는 일종의 프레임워크처럼 작동한다."
✅ 3. String 클래스
- 문자열을 표현하고 처리하기 위한 클래스를 의미한다.
- String 클래스 생성 방식은 리터럴 방식과 객체 생성 방식 두 가지 방식이 존재한다.
- String은 불변클래스이며, 필드와 클래스에는 final로 값의 변경을 막고 있음.
(1) String 리터럴 생성 방식
String a = "Hello";
- 리터럴 방식은 해당 문자열 값이 String Constant Pool(문자열 상수 풀)에 저장이 된다.
- 상수풀에 존재하는 해당 문자열 값을 다른 변수로 이용을 하게 된다면 재사용을 하게 된다.
- 즉, Hello 라는 문자가 존재하면 해당 문자를 변수들이 참조해서 이용을 하게 된다는 의미이다.
- 문자열은 반복되는 문자가 많이 선언될 수 있기에, 객체로써 가지고 있게 되면 같은 문자 객체를 반복적으로 만들게됨.
- 즉, 메모리 측면에서 많은 비효율과 성능의 떨어짐이 존재할 수 있음.
- 그래서 상수풀을 활용하면, 메모리 효율이 높고 속도가 빠르다는 장점이 있음.
[1] String Constant Pool(문자열 상수 풀) 이란?
- 처음 String 리터럴 방식 또는 intern() 메서드가 호출이 되면 그때 해당 상수풀이 만들어진다.
- 즉, 클래스로더가 해당 클래스를 처음 로드 하는 시점에 상수풀이 만들어진다고 보면 된다.
- 해당 상수풀은 반복적으로 만들어지는 문자열을
[2] intern() 메서드란?
// String.class
public native String intern();
- new String("Hello")로 만들어진 객체 문자열을 intern() 메서드를 통해 상수풀에 넣을 수 있게 됨.
- String 클래스의 메서드로, native 코드 즉, 메서드 바디는 C랑 C++로 구현 되어있으며, 해당 코드를 실행하는 메서드임.
- JVM 에서 해당 C랑 C++로 구현 되고, 컴파일 된 코드를 호출하는 코드가 내장이 되어있음.
- 즉, 파일을 읽는 등의 코드는 내장이 되어있어서, 바로 메서드 호출로 해당 C++ 코드를 실행 할 수 있음.
- 왜냐하면, 이미 JVM이 해당 코드를 JVM 내부에서 가지고 있기 때문임.
(2) String 객체 생성 방식
String b = new String("hello"); // Heap 메모리 새 객체
- 해당 문자열을 새로운 Heap 메모리에 새로운 객체로 만드는 방식이다.
- 즉, 같은 문자열을 똑같은 방식으로 생성을 하게 되도 주소값이 다른 새로운 객체가 만들어진다.
String a = new String("hello"); // Heap 메모리 새 객체
String b = new String("hello"); // Heap 메모리 새 객체
System.out.println(a == b); // false
- String 객체 생성 방식은 동일한 문자열을 재사용 할 수 없는 부분이 매우 큰 단점이라 보통은 사용이 되지 않는 방식이다.
- 그렇기 때문에 이러한 문제를 해결하기 위해 객체로 생성한 문자열을 상수풀에 넣는 방법이 존재한다.
- 이 방법은 위에 설명에서 나온 intern() 메서드를 호출해서 상수풀에 넣는 방식이다.
String a = "hello"; // Constant Pool 활용 (리터럴)
String b = new String("hello"); // Heap 메모리 새 객체
System.out.println(a == b); // false
System.out.println(a == b.intern()); // true
(3) String - 문자열 비교 메서드
[1] compareTo 메서드 - 정수값 반환
String a = "Hello";
String b = new String("Hello");
System.out.println(a.compareTo(b)); // 결과: 0
- 두 문자열이 같으면 0을 리턴하고, 다르면 0이 아닌 정수값을 리턴함.
- 주소값이 아닌 내부의 값 자체를 비교함.
[2] equals 메서드 - 논리값 반환
String a = "Hello";
String b = new String("Hello");
System.out.println(a.equals(b)); // true
System.out.println(a == b); // false
- Object 클래스의 equals() 를 재정의 하고 있어, 주소값이 아닌 문자열 자체의 값을 비교함.
✅ 4. StringBuffer 클래스
(1) String 클래스의 문제점
- String의 문자열 상수풀은 문자열의 중복값 저장을 방지하기 위해서 사용을 한다.
- 하지만, 문자열이 늘어남에 따라 새로운 객체가 생성되는 문제점은 그대로 있다.
- 이러한 문제로인해, 잦은 변수값의 수정은 새로운 String 객체를 만들기 때문에 성능의 저하를 일으킬 수 있다.
(2) StringBuffer 클래스
StringBuffer sb = new StringBuffer(); // 초기 빈 문자열 버퍼
sb.append("안녕하세요");
sb.append(" ");
sb.append("XXX입니다.");
sb.insert(6, "[개발자] ");
sb.replace(0, 5, "Hello");
sb.delete(17, sb.length()); // 마지막 문장 일부 삭제
System.out.println(sb.toString()); // 출력 결과: Hello [개발자] XXX
- StringBuffer 클래스는 객체 생성 이후 문자열을 변경할 수 있는 클래스이다.
- 내부적으로 문자열을 저장하기 위해 크기가 조절되는 버퍼(배열이라고 보면됨)를 사용을 한다.
- 문자열을 자주 수정해야 하는 상황에서 많이 쓰이는 클래스라고 보면 된다.
- 메서드를 통해 문자를 추가하게 되면, 객체를 생성하지 않고 내부의 버퍼에 추가가 된다고 보면 된다.
(3) StringBuilder 클래스
- StringBuffer 클래스와 거의 똑같이 생긴 클래이며, 차이로는 동기화 여부에서의 차이가 있다.
- StringBuffer은 스레드 안전하지만, StringBuilder은 비동기로 스레드 안전하지 못하다는 특징이 있음.
- 대신에, 속도 측명에선 StringBuilder가 빠르다.
- 멀티스레드에선 StringBuffer를 사용하며, 단일 스레드에선 StringBuilder를 주로 사용함.
- 그래서 보통은 StringBuilder를 사용하지만, 스레드 안정성이 정말 필요한 경우 StringBuffer를 쓴다.
(4) String vs StringBuffer vs StringBuilder
public class Main {
public static void main(String[] args) {
final String tmp = "test";
long start, end;
String str = new String();
StringBuffer sb1 = new StringBuffer();
StringBuilder sb2 = new StringBuilder();
start = System.nanoTime();
for(int i = 0; i < 100; i++) str += tmp;
end = System.nanoTime();
System.out.println((end-start) / 1000000.0 + " msecs"); // 4.155299 msecs
start = System.nanoTime();
for(int i = 0; i < 100; i++) sb1.append(tmp);
end = System.nanoTime();
System.out.println((end-start) / 1000000.0 + " msecs"); // 0.054601 msecs
start = System.nanoTime();
for(int i = 0; i < 100; i++) sb2.append(tmp);
end = System.nanoTime();
System.out.println((end-start) / 1000000.0 + " msecs"); // 0.047 msecs
}
}
- String = 4.155299 msecs
- StringBuffer = 0.054601 msecs
- StringBuilder = 0.047 msecs
- StringBuilder가 가장 빠르고 다음으로 StringBuffer가 빠르고 다음으로 String이 나왔음.
✅ 5. 포장 클래스 ( 래퍼 클래스 )
Double double = new Double(2.59) // 생성자 방식, 권장 안됨
DOuble double = Double.valueOf(10.4); // ValueOf() 사용 방식 권장
Double double = 3.14; // 자동 boxing
- 기본자료형을 참조자료형으로 표현하기 위한 클래스이다. 기본자료형은 int, double, char, boolean 등을 의미함.
- 기본형과 상응하는 객체 사이의 형변환 기능을 제공함.
- 메서드의 인자로 참조형 즉, 객체 자체가 필요한 경우 해당 기본자료형을 참조형으로 박싱해서 보내줄 수 있음.
- 또한. 래퍼 클래스는 다양한 메서드를 제공을 해줌.
- Number 추상 클래스를 상속 받아서 구현 된 클래스들을 의미함.
(1) 박싱(Boxing)
Double d = Double.valueOf(10.4); // ValueOf() 사용 방식 권장
Double pi = 3.14; // 자동 boxing
// 내부적으로 Double.vlauleOf(3.14) 로 처리가 됨.
- 기본자료형의 값을 박싱해서 객체로 만드는 방법을 의미하며, 자동과 valueOf() 방식이 존재한다.
- 자동 또한 어차피 valueOf() 방식을 활용하기 때문에, valueOf()가 매우 중요하게 작용됨.
- 인자에 전달되거나 변수에 대입될 때 자동으로 박싱되어서 적용이 됨.
(2) 언박싱(Unboxing)
Double pi = 3.14; // 자동 boxing
double d = Double.doubleValue(pi); // doubleValue() : 기본자료형으로 변경 메서드
double d = pi; // 자동 unboxing
- 래퍼클래스의 참조값을 기본자료형의 값으로 변경하는 것을 의미하며, 자동과 doubleValue() 방식이 존재함
- 박싱과 마찬가지로, 자동 언박싱 또한 doubleValue()가 내부적으로 동작한다고 보면됨.
- 마찬가지로 인자에 전달되거나 변수에 대입될 때 자동으로 박싱되어서 적용이 됨.
✅ 6. System 클래스
- System 클래스는 자바에서 매우 중요한 유틸리티 클래스로, 운영체제와의 인터페이스를 일부 제공하는 표준 입출력, 시스템 속성, 시간 측정, 종료 등 다양한 기능을 제공한다. 한마디로, 자바 프로그램이 JVM 및 OS와 상호작용하는 수단 중 하나임.
- 모든 멤버는 static, 사용할 때 객체를 생성할 필요는 전혀 없음.
- 표준 입출력 객체 제공, JVM 속성과 시스템 환경 변수의 사용과 제어, 배열 복사, 시간 조회, 프로그램의 제어 등을 해줌.
(1) System 클래스 - 표준 입출력 필드
- System.in: 표준 입력 스트림으로 InputStream 유형, 키보드로부터 입력을 받을 때 사용함.
- Systme.out: 표준 출력 스트림 PrintStream 유형, 화면에 데이터를 출력할 때 사용함.
- System.err: 표준 에러 출력 스트림 PrintStream 유형, 오류 메시지를 화면에 출력할 때 사용함.
✅ 7. 그 외
- java.lang 패키지에는 그 외 Process, Thread, Exception, Package, Class, Math 등이 있음.
'공부 > ☕Java' 카테고리의 다른 글
| [Java] java.nio 사용법 | Path, Files, FileChannel 예제 모음 (3) | 2025.05.30 |
|---|---|
| [Java] java.io 패키지 입출력 스트림 쉽게 이해하기 (2) | 2025.05.28 |
| [Java] 자바 함수형 인터페이스와 람다식(Lambda Expression) 쉽게 배우기 (1) | 2025.05.23 |
| [Java] 제네릭(Generic) 문법 정리: 클래스, 메서드, 제한까지 (0) | 2025.05.23 |
| [Java] 익명 클래스(Anonymous Class) (1) | 2025.05.22 |