[Java] 자바 중급(1) - Object 클래스

wony·2024년 3월 29일

Java

목록 보기
8/30

0.개요

주제 : 김영한님의 자바 중급 1편 총 정리
내용 : Object 클래스에 대해 공부

챕터1. Object 클래스

1) java.lang 패키지 소개

자바가 기본적으로 제공하는 라이브러리 중에 가장 기본이 되는 것이 바로 java.lang 패키지이다. 여기서 langLanguage의 줄임말이다.

java.lang 패키지의 대표적인 클래스들

  • Object : 모든 자바 객체의 부모 클래스
  • String : 문자열
  • Integer , Long , Double : 래퍼 타입, 기본형 데이터 타입을 객체로 만든 것
  • Class : 클래스 메타 정보
  • System : 시스템과 관련된 기본 기능들을 제공

import 생략 가능
java.lang 패키지는 모든 자바 애플리케이션에 자동으로 임포트된다. 따라서, 임포트 구문을 사용하지 않아도 된다.

//import java.lang.System; //없어도 된다.
public class LangMain{
	public static void main(String[] args){
    	System.out.println("hello java");
	}
}

2) Object 클래스

자바에서 모든 클래스의 최상위 부모 클래스는 항상 Object 클래스이다.

package lang.object;
//부모가 없으면 묵시적으로 Object 클래스를 상속받는다.
public class Parent {
	public void parentMethod() {
		System.out.println("Parent.parentMethod");
	}
}

앞의 코드는 다음 코드와 같다 : extends Object 추가

package lang.object;
//부모가 없으면 묵시적으로 Object 클래스를 상속받는다.
public class Parent extends Object{
	public void parentMethod() {
		System.out.println("Parent.parentMethod");
	}
}
  • 클래스에 상속 받을 부모 클래스가 없으면 묵시적으로 Object 클래스를 상속 받는다.
    • 쉽게 이야기해서 자바가 extends Object 코드를 넣어준다.

부모 클래스를 상속 받은 코드

public class Child extends Parent{
	public void childMethod(){
    	System.out.println("Child.childMehotd");
    }
}
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

1. child.toString() 을 호출한다.
2. 먼저 본인의 타입인 Child 에서 toString() 을 찾는다. 없으므로 부모 타입으로 올라가서 찾는다.
3. 부모 타입인 Parent 에서 찾는다. 없으므로 부모 타입으로 올라가서 찾는다.
4. 부모 타입인 Object 에서 찾는다. ObjecttoString() 이 있으므로 이 메서드를 호출한다.

자바에서 Object 클래스가 최상위 부모 클래스인 이유
모든 클래스가 Object 클래스를 상속 받는 이유는 다음과 같다.
1. 공통 기능 제공

  • Object 가 제공하는 기능은 다음과 같다.
    • 객체의 정보를 제공하는 toString()
    • 객체의 같음을 비교하는 equals()
    • 객체의 클래스 정보를 제공하는 getClass()
    • 기타 여러가지 기능

2. 다형성의 기본 구현

  • Object는 모든 클래스의 부모 클래스이다. 따라서, 모든 객체를 참조할 수 있다.

2-1) Object 다형성

Object를 활용한 다형성의 한계

  • Object 는 모든 객체를 대상으로 다형적 참조를 할 수 있다.
    • 쉽게 이야기해서 Object 는 모든 객체의 부모이므로 모든 객체를 담을 수 있다.
  • Object 를 통해 전달 받은 객체를 호출하려면 각 객체에 맞는 다운캐스팅 과정이 필요하다.
    • Object 가 세상의 모든 메서드를 알고 있는 것이 아니다.
    • Object에서 sound()를 찾을 수 없다. 호출하려면 다운 캐스팅을 해주어야 한다.
public class Car {
    public void move(){
        System.out.println("자동차 이름");
    }
}
public class Dog {
    public void sound(){
        System.out.println("멍멍");
    }
}
public class ObjectPolyExample1 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Car car = new Car();
        action(dog);
        action(dog);
    }
    private static void action(Object obj){
        //obj.sound();
        //obj.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로 수정 가능

2-2) Object 배열

Object는 모든 타입의 객체를 담을 수 있다. 따라서, Object[]을 만들면 세상의 모든 객체를 담을 수 있는 배열을 만들 수 있다.

public class ObjectPolyExample2 {
	public static void main(String[] args) {
		Dog dog = new Dog();
		Car car = new Car();
		Object object = new Object(); //Object 인스턴스도 만들 수 있다.
		Object[] objects = {dog, car, object};
        size(objects);
        }      
    private static void size(Object[] obejcts){
        System.out.printlne("전달된 객체의 수는:" + objects.length);
    }
}

Object가 없다면?
만약 Object 와 같은 개념이 없다면 어떻게 될까?

  • void action(Object obj) 과 같이 모든 객체를 받을 수 있는 메서드를 만들 수 없다.
  • Object[] objects 처럼 모든 객체를 저장할 수 있는 배열을 만들 수 없다.

3) toString()

Object.toString() 메서드는 객체의 정보를 문자열 형태로 제공한다.

println()과 toString()
그런데, toString() 의 결과를 출력한 코드와 objectprintln() 에 직접 출력한 코드의 결과가 완전히 같다.

public class ToStringMain1 {
	public static void main(String[] args) {
		Object object = new Object();
		String string = object.toString();
		//toString() 반환값 출력
		System.out.println(string);
		//object 직접 출력
		System.out.println(object);
	}
}

System.out.println() 메서드는 사실 내부에서 toString() 을 호출한다.
Object 타입(자식 포함)이 println() 에 인수로 전달되면 내부에서 obj.toString() 메서드를 호출해서 결과를 출력한다.

public void println(Object x) {
	String s = String.valueOf(x);
}

따라서 println() 을 사용할 때, toString() 을 직접 호출할 필요 없이 객체를 바로 전달하면 객체의 정보를 출력할 수 있다

3-1) toSting() 오버라이딩

Object.toString() 메서드가 클래스 정보와 참조값을 제공하지만 이 정보만으로는 객체의 상태를 적절히 나타내지 못한다. 그래서 보통 toString() 을 재정의(오버라이딩)해서 보다 유용한 정보를 제공하는 것이 일반적이다.

public class Car {
    private String carName;
    public Car(String carName) {
        this.carName = carName;
    }
}
public class Dog {
    private String dogName;
    private int age;
    public Dog(String dogName, int age){
        this.dogName = dogName;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Dog{" +
                "dogName='" + dogName + '\'' +
                ", age=" + age +
                '}';
    }
}
  • DogtoString() 을 재정의했다.
  • toString() 메서드는 IDE의 도움을 받아서 작성하는 것이 매우 편리하다. generator 단축키: ⌘N (macOS) / Alt+Insert (Windows/Linux)

4) Object와 OCP

OCP 원칙

Open:

  • 새로운 클래스를 추가하고, toString() 을 오버라이딩해서 기능을 확장할 수 있다.

Closed:

  • 새로운 클래스를 추가해도 ObjecttoString() 을 사용하는 클라이언트 코드인ObjectPrinter 는 변경하지 않아도 된다.
  • 다형적 참조, 메서드 오버라이딩, 그리고 클라이언트 코드가 구체적인 Car , Dog 에 의존하는 것이 아니라 추상적인Object 에 의존하면서 OCP 원칙을 지킬 수 있었다.
  • 덕분에 새로운 클래스를 추가하고 toString() 메서드를 새롭게 오버라이딩해서 기능을 확장할 수 있다.
  • 그리고 이러한 변화에도 불구하고 클라이언트 코드인 ObjectPrinter 는 변경할 필요가 없다.

자바 언어는 객체지향 언어답게 언어 스스로도 객체지향의 특징을 매우 잘 활용한다.
toString( ) 메서드와 같이, 자바 언어가 기본으로 제공하는 다양한 메서드들은 개발자가 필요에 따라 오버라이딩해서 사용할 수 있도록 설계되어 있다.

5-1) equals() 동일성과 동등성

Object 는 동등성 비교를 위한 equals() 메서드를 제공한다.

자바는 두 객체가 같다라는 표현을 2가지로 분리해서 제공한다.

  • 동일성(Identity): == 연산자를 사용해서 두 객체의 참조가 동일한 객체를 가리키고 있는지 확인 (완전 같음)
  • 동등성(Equality): equals() 메서드를 사용하여 두 객체가 논리적으로 동등한지 확인

단어 정리
"동일"은 완전히 같음을 의미한다. 반면 "동등"은 같은 가치나 수준을 의미하지만 그 형태나 외관 등이 완전히 같지는 않을 수 있다.

쉽게 이야기해서 동일성은 물리적으로 같은 메모리에 있는 객체 인스턴스인지 참조값을 확인하는 것이고, 동등성은 논리적으로 같은지 확인하는 것이다.

예를 들어 같은 회원 번호를 가진 회원 객체가 2개 있다고 가정해보자

User a = new User("id-100") //참조 x001
User b = new User("id-100") //참조 x002

이 경우 물리적으로 다른 메모리에 있는 다른 객체이지만, 회원 번호를 기준으로 생각해보면 논리적으로 같은 회원으로 볼 수 있다. 따라서, 동일성은 다르지만 동등성은 같다.

예제를 통해서 동일성과 동등성을 비교해보자.

UserV1 예제

public class UserV1 {
	private String id;   
    public UserV1(String id){
    	this.id = id;
    }
}
public class EqualsMainV1 {
	public static void main(String[] args){
    	UserV1 user1 = new UserV1("id-100");
        UserV1 user2= new UserV1("id-100");
        System.out.println("identity = " + (user1 == user2));
        System.out.println("equality = " + user1.equals(user2));
    }
}

실행 결과
identity = false
equality = false

eqaulity(동등성)은 논리적으로 같으면(값이 같으면) 같다고 했는데 왜 false가 나오지????

-> Object가 기본으로 제공하는 equals()는 ==으로 동일성 비교를 제공한다.

동등성 비교 Object.equals() 메서드

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

equals 실행 순서 예시

user1.equals(user2)
return (user1 == user2) //Object.equals 메서드 안
return (x001 == x002) //Object.equals 메서드 안
return false
false

따라서 동등성 비교를 사용하고 싶으면 equals() 메서드를 오버라이딩해야 한다. 그렇지 않으면 Object는 동일성 비교를 기본으로 제공한다.

5-2) equals() 구현(항상 이걸로 구현해야!!)

UserV2 예제

UserV2id(고객번호)가 같으면 논리적으로 같은 객체로 정의하겠다.

public class UserV2 {
	private String id;
    public UserV2(String id){
    	this.id = id;
    }
    @Override
    public boolean equals(Object obj){
    	USerV2 user = (UserV2) obj;
        return id.equals(user.id);
    }
}
  • Objectequals() 메서드를 재정의했다.
  • UserV2 의 동등성은 id (고객번호)로 비교한다.
  • equals()Object 타입을 매개변수로 사용한다. 따라서 객체의 특정 값을 사용하려면 다운캐스팅이 필요하다.
  • 여기서는 현재 인스턴스( this )에 있는 id 문자열과 비교 대상으로 넘어온 객체의 id 문자열을 비교한다.
  • UserV2 에 있는 idString 이다. 문자열 비교는 == 이 아니라 equals() 를 사용해야 한다.

5-2-1) 정확한 equals() 구현

  • 앞서 UserV2에서 구현한 equals()는 이해를 돕기 위해 매우 간단히 만든 버전이고, 실제로 정확하게 동작하려면 다음과 같이 구현해야 한다. 정확한 equals() 메서드를 구현하는 것은 생각보다 쉽지 않다.
  • IntelliJ를 포함한 대부분의 IDE는 정확한 equals() 코드를 자동으로 만들어준다.

문제1 : toString(), equals() 구현하기

팁: 멤버변수만 선언하면 생성자, toString, equals 다 alt+insert가 처리해준다.

문제 설명

  • 다음 코드와 실행 결과를 참고해서 Rectangle 클래스를 만들어라
  • Rectangle 클래스에 IDE의 기능을 사용해서 toString() , equals() 메서드를 실행 결과에 맞도록 재정의해라.
    rect1rect2 는 넓이( width )와 높이( height )를 가진다. 넓이와 높이가 모두 같다면 동등성 비교에 성공해야 한다
profile
안녕하세요. wony입니다.

0개의 댓글