☕️ 김영한의 실전 자바 - 중급 1편 을 듣고 작성하는 복습 블로그 입니다.
1. java.lang 패키지
- java.lang 패키지는 자바가 기본으로 제공하는 라이브러리의 가장 기본
- 자바 언어를 이루는 가장 기본이 되는 클래스들을 보관하는 패키지
- java.lang 패키지의 대표적인 클래스들로는 Object (모든 자바 객체의 부모 클래스) , String (문자열), Integer (래퍼타입), Class (클래스 메타 정보) , System (시스템 관련 기본 기능) 들이 있다
- java.lang 패키지에 있는 클래스들은 모두 자바 애플리케이션에 자동으로 임포트되기 때문에 임포트 구문을 따로 사용하지 않아도 된다
// import 구문 미사용 가능
public class LangMain {
public static void main(String[] args) {
System.out.println("hello java");
}
}
2. Object 클래스
- 자바에서 모든 클래스의 최상위 부모 클래스는 항상 Object
- Object 는 모든 클래스에 묵시적 상속된다
2-1. 묵시적 상속
🔥 묵시적 (Implicit)
개발자가 코드에 직접 기술하지 않아도 시스템 또는 컴파일러에 의해 자동으로 수행되는 것
class Test {
}
만약 이런 클래스가 존재하고, 클래스에 상속 받을 부모 클래스가 없는 경우
class Test extends Object {
}
위처럼 컴파일러가 컴파일 시점에 extends Object 를 코스에 묵시적으로 추가해준다
그렇기 때문에 Test 클래스들은 자동으로 Object 의 메서드들을 상속받고 사용할 수 있게 된다 (toString(), equals() 등)
2-2. 명시적 상속
🔥 명시적 (Explicit)
개발자가 코드에 직접 기술해서 작동하는 것
class Test extends Parent {
}
위처럼 클래스에 상속받을 부모 클래스를 명시적으로 지정하는 경우에는 Object 를 상속받지 않는다
이런 경우에는 Object 의 메서드들을 사용할 수 없다
2-3. 자바에서 Object 클래스가 최상위 부모 클래스인 이유
- 공통 기능 제공
- 객체를 만들때마다 기본 기능을 정의해야하면 상당히 번거롭다
- 만든다고 해도 일관성이 없다
- 그렇기 때문에 Object 클래스를 통해 모든 객체에 필요한 공통 기능을 제공한다
- 다형성의 기본 구현
- Object는 모든 클래스의 부모 클래스이기 때문에 모든 객체를 참조할 수 있다
- 다형성을 지원하는 기본적인 매커니즘을 지원한다
- 모든 자바 객체는 Object 타입으로 처리되고, 다양한 타입의 객체를 통합적으로 처리할 수 있다
3. Object 다형성
Object 는 모든 클래스의 부모 클래스이기 때문에 모든 객체를 참조할 수 있다
class Test {
}
Test 클래스는 부모가 없기 때문에 Object 를 자동으로 상속받는다
void action(Object obj) {
}
Object 를 상속받고 있기 때문에 action 메서드의 매개변수로 Test 클래스를 넘길 수 있다
이런 경우 자동으로 업캐스팅된다
3-1. Object 다형성의 장점
Object는 모든 객체의 부모이기 때문에 어떤 객체든지 인자로 전달할 수 있다
class Test { }
public class Main {
public static void main(String[] args) {
Test test = new Test();
action(test);
}
static void action(Object obj) {
System.out.println("매개변수 타입: " + obj.getClass().getName());
}
}
3-2. Object 다형성의 한계
자식에 있는 메서드를 호출하지 못한다.
만일, 자식에 있는 메서드를 호출해야 한다면 다운캐스팅을 해야한다
if (obj instanceof Test test) {
test.a();
}
- instanceof 로 Test 클래스인지 확인하고, Test 클래스로 다운캐스팅하면서 전달한다
- test.a() 를 호출하면 Test 타임에서 a() 메소드를 찾아서 호출한다
4. toString()
- 객체의 정보를 문자열 형태로 제공한다
- 디버깅과 로깅에 유용하게 사용할 수 있다
- Object 클래스에 정의되므로 모든 클래스에서 상속받아 사용가능하다
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
4-1. println 내부 코드
public void println(Object x) {
String s = String.valueOf(x);
if (getClass() == PrintStream.class) {
// need to apply String.valueOf again since first invocation
// might return null
writeln(String.valueOf(s));
} else {
synchronized (this) {
print(s);
newLine();
}
}
}
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
println 내부 코드에서도 넘어온 객체(x) 를 곧바로 출력하지 않고, String.valueOf(x) 를 호출한다
- 파라미터로 어떤 객체든지 받는다 (Object x)
- String.valueOf(x) 를 호출해서 null 을 확인하고 toString() 을 실행한다
- toString() 의 결과 문자열을 실제로 출력한다
→ 객체의 출력 형태를 제어하고 싶다면 toString() 을 오버라이딩하면 된다
4-2. toString() 오버라이딩
toString() 메서드는 클래스의 정보와 참조값만 제공하기 때문에 객체의 상태를 적절하게 나타내지 못한다
그렇기 때문에 각 클래스에서 toString() 을 재정의 (오버라이딩) 해서 유용한 정보를 제공해야 한다
public class Test {
private String name;
private int age;
public Test(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Test{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Test test = new Test("밥", 25);
System.out.println(test);
- println(Object obj) 메소드로 test 클래스가 전달된다
- 메서드 내부에서 obj.toString() 을 호출한다
- 자식에서 재정의된 메서드가 있는지 없는지 찾는다
- Test 클래스에 재정의된 메서드가 있으므로 Test.toString() 을 실행한다
5. Object 와 OCP
public class ObjectPrinter {
public static void print(Object obj) {
String string = "객체 정보 출력: " + obj.toString();
System.out.println(string);
}
}
모든 객체를 출력할 수 있는 ObjectPrinter
추상적인 Object 클래스를 사용해 추상적인 것에 의존한다
위 코드는 다형적 참조와 메서드 오버라이딩을 적절하게 사용하므로 다형성을 매우 잘 활용하고 있다
- 다형적 참조 : Object 타입을 매개변수로 사용해서 다형적 참조를 사용한다
- 메서드 오버라이딩 : Object 는 모든 클래스의 부모이기 때문에 모든 클래스가 toString() 메서드를 오버라이딩 할 수 있다
5-1. OCP 원칙
Open : 새로운 클래스를 추가하고, toString() 을 오버라이딩해서 기능을 확장할 수 있다
Closed : 새로운 클래스를 추가해도 Object 와 toString() 을 사용하는 클라이언트 코드는 변경하지 않아도 된다
5-2. System.out.println()
- System.out.println() 메서드도 Object 매개변수를 사용하고, 내부에서 toString() 을 호출한다
- 자바는 객체지향 언어답게 언어 스스로도 객체지향의 특징을 매우 잘 활용한다
- 자바 언어가 기본적으로 제공하는 다양한 메서드들은 개발자가 필요에 따라 오버라이딩해서 사용할 수 있다
6. equals()
6-1. 동일성과 동등성
동일성 (Identity) : == 연산자
- 두 객체의 참조가 동일한 객체를 가리키고 있는지를 확인한다
- 완전히 같음을 의미
- 물리적으로 같은 메모리에 있는 객체 인스턴스인지 참조값을 확인한다
동등성 (Equality) : equals() 메서드
- 두 객체가 논리적으로 동등한지 확인한다
- 같은 가치나 수준을 의미하지만, 그 형태나 외관이 완전히 같지 않을수도 있다
- 논리적으로 같은지 확인한다
User a = new User("id-100"); // x001
User b = new User("id-100"); // x002
위의 코드의 경우 🙅♀️ 동일성은 x001, x002 로 다르지만 🙆♀️ 동등성은 id-100, id-100 으로 같다
6-2. Object equals()
public boolean equals(Object obj) {
return (this == obj);
}
- Object 의 equals() 는 기본적으로 == 로 제공한다
- 동등성 비교를 사용하고 싶으면 equals() 메서드를 재정의하면 된다
@Override
public boolean equals(Object obj) {
User user = (User) obj;
return this.id.equals(user.id);
}
6-3. equals() 메서드를 구현할 때 지켜야 하는 규칙
- 반사성 : 객체는 자기 자신과 동등해야 한다
- 대칭성 : 두 객체가 서로에 대해 동일하다고 판단하면, 이는 양방향으로 동일해야 한다
- 추이성 : 만약 한 객체가 두 번째 객체와 동일하고, 두 번째 객체가 세번째 객체와 동일하다면 첫번째 객체는 세번째 객체와도 동일해야 한다
- 일관성 : 두 객체의 상태가 변경되지 않는 한, equals() 메소드는 항상 동일한 값을 반환해야 한다
- null 에 대한 비교 : 모든 객체는 null 과 비교했을 때 false 를 반환해야 한다
'🌱 인프런 > ☕️ 김영한의 실전 자바 - 중급 1편' 카테고리의 다른 글
| 자바 래퍼, Class 총정리 (0) | 2025.07.19 |
|---|---|
| 자바 예외처리 총정리 (1) | 2025.07.11 |
| 자바 열거형 ENUM 총정리 (2) | 2025.07.10 |
| 자바 중첩 클래스와 내부 클래스 (3) | 2025.07.09 |
| 자바 날짜와 시간 라이브러리 총정리 (0) | 2025.07.07 |