오늘의 잔디 깃허브 UI가 바꼈네.
오늘의 공부 오늘 머리 깨지고 멘탈 터져가면서 깃허브 새롭게 연동 시켰다 이제 앞으로 무성이 도움 없이 진짜 혼자서 할 수 있을 것이다. 그 시간만 거의 1시간 넘게 쓴 듯 어제 오늘
자바가 기본으로 제공하는 라이브러리(클래스 모음) 중에 가장 기본이 되는 것이 바로 java.lang 패키지이다.
여기서 lang 은 Language (언어)의 줄임말이다. 쉽게 이야기해서 자바 언어를 이루는 가장 기본이 되는 클래스들을 보관하는 패키지를 뜻한다.
java.lang 패키지의 대표적인 클래스들
Object : 모든 자바 객체의 부모 클래스String : 문자열Integer , Long , Double : 래퍼 타입, 기본형 데이터 타입을 객체로 만든 것Class : 클래스 메타 정보System : 시스템과 관련된 기본 기능들을 제공여기 나열한 클래스들은 자바 언어의 기본을 이루기 때문에 반드시 잘 알아두어야 한다.
java.lang 패키지는 모든 자바 애플리케이션에 자동으로 임포트( import )된다. 따라서 임포트 구문을 사용하지 않아도 된다.
다른 패키지에 있는 클래스를 사용하려면 다음과 같이 임포트를 사용해야 한다.
package lang;
import java.lang.System;
public class LangMain {
public static void main(String[] args) {
System.out.println("hello java");
}
}
System 클래스는 java.lang 패키지 소속이다. 따라서 다음과 같이 임포트를 생략할 수 있다.
package lang;
public class LangMain {
public static void main(String[] args) {
System.out.println("hello java");
}
}
import java.lang.System; 코드를 삭제해도 정상 동작한다.이제 본격적으로 java.lang 패키지가 제공하는 기능들을 하나씩 알아보자.
자바에서 모든 클래스의 최상위 부모 클래스는 항상 Object 클래스이다.
다음 그림과 예제 코드를 보자.

package lang.object;
//부모가 없으면 묵시적으로 Object 클래스를 상속받는다.
public class Parent {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
앞의 코드는 다음 코드와 같다.
//extends Object 추가
public class Parent extends Object {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
Object 클래스를 상속 받는다.extends Object 코드를 넣어준다.extends Object 는 생략하는 것을 권장한다.package lang.object;
public class Child extends Parent {
public void childMethod() {
System.out.println("Child.childMethod");
}
}
Object 를 상속 받지 않는다.extends Object 코드를 넣지 않는다.묵시적(Implicit) vs 명시적(Explicit)
묵시적: 개발자가 코드에 직접 기술하지 않아도 시스템 또는 컴파일러에 의해 자동으로 수행되는 것을 의미
명시적: 개발자가 코드에 직접 기술해서 작동하는 것을 의미package lang.object; public class ObjectMain { public static void main(String[] args) { Child child = new Child(); child.childMethod(); child.parentMethod(); // toString()은 Object 클래스의 메서드 String string = child.toString(); System.out.println(string); } }
- 예제에서
toString()은Object클래스의 메서드이다. 이 메서드는 객체의 정보를 제공한다.
실행 결과
Child.childMethod
Parent.parentMethod
lang.object.Child@X001
실행 결과 그림
Parent 는 Object 를 묵시적으로 상속 받았기 때문에 메모리에도 함께 생성된다.

child.toString() 을 호출한다.Child 에서 toString() 을 찾는다. 없으므로 부모 타입으로 올라가서 찾는다.Parent 에서 찾는다. 없으므로 부모 타입으로 올라가서 찾는다.Object 에서 찾는다. Object 에 toString() 이 있으므로 이 메서드를 호출한다.정리
자바에서 모든 객체의 최종 부모는 Object 다.
모든 클래스가 Object 클래스를 상속 받는 이유는 다음과 같다.
공통 기능 제공
객체의 정보를 제공하고, 이 객체가 다른 객체와 같은지 비교하고, 객체가 어떤 클래스로 만들어졌는지 확인하는 기능은모든 객체에게 필요한 기본 기능이다. 이런 기능을 객체를 만들 때 마다 항상 새로운 메서드를 정의해서 만들어야 한다면 상당히 번거로울 것이다.
그리고 막상 만든다고 해도 개발자마다 서로 다른 이름의 메서드를 만들어서 일관성이 없을 것이다. 예를 들어서 객체의 정보를 제공하는 기능을 만든다고 하면 어떤 개발자는 toString() 으로 또 어떤 개발자는 objectInfo() 와 같이 서로 다른 이름으로 만들 수 있다. 객체를 비교하는 기능을 만들 때도 어떤 개발자는 equals() 로 어떤 개발자는 same() 으로 만들 수 있다.
Object 는 모든 객체에 필요한 공통 기능을 제공한다. Object 는 최상위 부모 클래스이기 때문에 모든 객체는 공통 기능을 편리하게 제공(상속) 받을 수 있다.
Object 가 제공하는 기능은 다음과 같다.
toString()equals()getClass()개발자는 모든 객체가 앞서 설명한 메서드를 지원한다는 것을 알고 있다. 따라서 프로그래밍이 단순화되고, 일관성을 가진다.
각각의 기능에 대한 자세한 내용은 이후에 하나씩 알아보자.
다형성의 기본 구현
부모는 자식을 담을 수 있다. Object 는 모든 클래스의 부모 클래스이다. 따라서 모든 객체를 참조할 수 있다.
Object 클래스는 다형성을 지원하는 기본적인 메커니즘을 제공한다. 모든 자바 객체는 Object 타입으로 처리될 수 있으며, 이는 다양한 타입의 객체를 통합적으로 처리할 수 있게 해준다.
쉽게 이야기해서 Object 는 모든 객체를 다 담을 수 있다. 타입이 다른 객체들을 어딘가에 보관해야 한다면 바로
Object 에 보관하면 된다.
Object 는 모든 클래스의 부모 클래스이다. 따라서 Object 는 모든 객체를 참조할 수 있다.
예제를 통해서 Object 의 다형성에 대해 알아보자.

Dog 와 Car 은 서로 아무런 관련이 없는 클래스이다. 둘다 부모가 없으므로 Object 를 자동으로 상속 받는다.
package lang.object.poly;
class Car {
public void move() {
System.out.println("자동차 이동");
}
}
package lang.object.poly;
class Dog {
public void sound() {
System.out.println("멍멍"); }
}
package lang.object.poly;
public class ObjectPolyExample1 {
public static void main(String[] args) {
Dog dog = new Dog();
Car car = new Car();
action(dog);
action(car);
}
private static void action(Object obj) {
//obj.sound(); //컴파일 오류, Object는 sound()가 없다.
//obj.move(); //컴파일 오류, Object는 move()가 없다.
//객체에 맞는 다운캐스팅 필요
if (obj instanceof Dog dog) {
dog.sound();
} else if (obj instanceof Car car) {
car.move();
}
}
}
실행 결과
멍멍
자동차 이동
Object 는 모든 타입의 부모다. 부모는 자식을 담을 수 있으므로 앞의 코드를 다음과 같이 변경해도 된다.
Object dog = new Dog(); //Dog -> Object
Object car = new Car(); //Car -> Object
action(Object obj) 메서드를 분석해보자.
이 메서드는 Object 타입의 매개변수를 사용한다. 그런데 Object 는 모든 객체의 부모다. 따라서 어떤 객체든지 인자로 전달할 수 있다.
action(dog) //main에서 dog 전달
void action(Object obj = dog(Dog)) //Object는 자식인 Dog 타입을 참조할 수 있다.
action(car) //main에서 car 전달
void action(Object obj = car(Car)) //Object는 자식인 Car 타입을 참조할 수 있다.
action(dog) //main에서 dog 전달
private static void action(Object obj) {
obj.sound(); //컴파일 오류, Object는 sound()가 없다.
}
action() 메서드안에서 obj.sound() 를 호출하면 오류가 발생한다. 왜냐하면 매개변수인 obj 는 Object 타입이기 때문이다. Object 에는 sound() 메서드가 없다.

obj.sound() 호출
obj.sound() 를 호출한다.obj 는 Object 타입이므로 Object 타입에서 sound() 를 찾는다.Object 에서 sound() 를 찾을 수 없다. Object 는 최종 부모이므로 더는 올라가서 찾을 수 없다. 따라서 오류가 발생한다.Dog 인스턴스의 sound() 를 호출하려면 다음과 같이 다운캐스팅을 해야한다.
if (obj instanceof Dog dog) {
dog.sound();
}

Object obj 의 참조값을 Dog dog 로 다운캐스팅 하면서 전달한다.dog.sound() 를 호출하면 Dog 타입에서 sound() 를 찾아서 호출한다.Object 는 모든 객체를 대상으로 다형적 참조를 할 수 있다.Object 는 모든 객체의 부모이므로 모든 객체를 담을 수 있다.Object 를 통해 전달 받은 객체를 호출하려면 각 객체에 맞는 다운캐스팅 과정이 필요하다.Object 가 세상의 모든 메서드를 알고 있는 것이 아니다.다형성을 제대로 활용하려면 자바 기본편에서 배운 것 처럼 다형적 참조 + 메서드 오버라이딩을 함께 사용해야 한다. 그런면에서 Object 를 사용한 다형성에는 한계가 있다.
Object 는 모든 객체의 부모이므로 모든 객체를 대상으로 다형적 참조를 할 수 있다. 하지만 Object 에는
Dog.sound() , Car.move() 와 같은 다른 객체의 메서드가 정의되어 있지 않다. 따라서 메서드 오버라이딩을 활용할 수 없다. 결국 각 객체의 기능을 호출하려면 다운캐스팅을 해야 한다.
참고로 Object 본인이 보유한 toString() 같은 메서드는 당연히 자식 클래스에서 오버라이딩 할 수 있다. 여기서 이야기하는 것은 앞서 설명한 Dog.sound() , Car.move() 같은 Object 에 속하지 않은 메서드를 말한다.
결과적으로 다형적 참조는 가능하지만, 메서드 오버라이딩이 안되기 때문에 다형성을 활용하기에는 한계가 있다.
그렇다면 Object 를 언제 활용하면 좋을까? 지금부터 하나씩 알아보자.