Java의 Object Class 에 대해 알아보자!

LSM ·2022년 3월 3일
1

Object Class 란 무엇일까?


Object Class는 모든 클래스의 최상위 클래스이다!

즉, 모든 클래스는 Object 클래스를 상속 받는다라고 할 수 있는 것이다.

컴파일러가 자동으로 extends Object를 추가한다.

class Student => class Student extends Object

Object Class는 java.lang 패키지 내에 존재하며,

java.lang 패키지는 프로그래밍시 import 하지 않아도 자동으로 imort된다!

import.java.lang.*;

java.lang 패키지에는 일반적으로 많이 사용하는 기본 클래스들이 속해 있으며,

예로, String, Integer, System... 등이 있다.

다시 원점으로 돌아가,

모든 클래스는 Object에서 상속받고, Object 클래스의 메서드 중 일부는 재정의해서 사용할 수 있다.

그렇가면 재정의 가능한 Object 클래스의 메서드 일부를 알아 보겠다!

💁 toString()

대표적인 Object 클래스의 메서드는 'toString()' 메서드가 있다.

객체의 정보를 String으로 바꾸어서 사용할 때 쓰이는 메서드이며,

아마 이 글을 보는 대부분의 분들께서는 @Override toString을 통해 toString()' 메서드를 재정의 하여 사용해보았을 것이다!

여기서 @Override를 사용할 수 있는 이유가 해당 클래스가 이미 Object 클래스를 상속 받았음을 알 수 있다.


💁 equals()

다음으로 이 역시 널리 알려진, 메서드이다.

'equals()' 메서드는, 두 인스턴스의 주소 값을 비교하여 true/false를 반환한다!

  • 여기서 주소 값이라 하면, heap 영역의 물리적 주소를 말한다!

하지만 'equals()' 메서드는, 사용자가 재정의 하여 두 인스턴스가 논리적으로 동일함의 여부를 구현할 수 있다

즉 인스턴스가 다르더라도 논리적으로 동일한 경우 true를 반환하도록 재정의 할 수 있음

예를 들어 다른 인스턴스라도 (같은 학번, 같은 사번, 같은 아이디의 회원...)이면 같은 인스턴스라고 취급해야 한다.


💁 hashCode()

hashCode()는 인스턴스의 저장 주소를 반환하도록 Object Class에 정의 되어있다!

힙메모리에 인스턴스가 저장되는 방식이 hash 방식이기에 위와 같은 이름으로 메서드가 정의된 것이다.

즉, 자료의 특정 값(키 값)에 대한 저장 위치를 반환해주는 해시 함수를 사용한다.

해시함수(hash function)란 데이터의 효율적 관리를 목적으로 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수입니다. 이 때 매핑 전 원래 데이터의 값을 키(key), 매핑 후 데이터의 값을 해시값(hash value), 매핑하는 과정 자체를 해싱(hashing)라고 합니다. ex) 검색 및 정보저장에 많이 사용되는 자료구조이다.

그렇다면 두 인스턴스가 같다는 것은 무엇을 의미하는가?

  • 두 인스턴스에 대한 equals()의 반환 값이 true
  • 동일한 hashCode() 값을 반환

논리적으로 동일함을 위해 equals() 메서드를 재정의 하였다면 hashCode()메서드도 재정의 하여 동일한 hashCode 값이 반환되도록 한다

예시 코드

public class Student {

	private int studentId;
	private String studentName;

	public Student(int studentId, String studentName)
	{
		this.studentId = studentId;
		this.studentName = studentName;
	}
	
	public boolean equals(Object obj) {
		if( obj instanceof Student) {
			Student std = (Student)obj;
			if(this.studentId == std.studentId )
				return true;
			else return false;
		}
		return false;
		
	}
	
	@Override
	public int hashCode() {
		return studentId;
	}
}

💁 clone()

객체의 원본을 복제하는데 사용하는 메서드이며,

생성과정의 복잡한 과정(생성자 생성 및 변수 초기화 등)을 반복하지 않고 복제 할 수 있다!

clone()메서드를 사용하면 객체의 정보(멤버 변수 값등)가 동일한 또 다른 인스턴스가 생성되는 것이므로, 객체 지향 프로그램에서의 정보 은닉, 객체 보호의 관점에서 위배될 수 있음

따라서 !!

해당 클래스의 clone() 메서드의 사용을 허용한다는 의미로 cloneable 인터페이스를 반드시 명시해 주어야 한다!!

예시 코드

public class Student implements Cloneable{

    .......

	@Override // 추가적으로 작성할 것은 없다!
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
}

얕은 복사 vs. 깊은 복사

clone() 메서드를 사용해서 객체의 복사를 수행할 때 주의할 점은 깊은복사(deep copy)를 하지 않는다는 점이다.

변수가 가리키는 값만 복사하는 얕은 복사(shallow copy)를 하기 때문에 모든 멤버 변수가 primitive 타입이거나 immutable 하다면 문제가 되지는 않지만, 만약 참조형 타입이면서 mutable한 변수가 포함되어 있다면 예상치 못한 문제가 발생할 수 있다.

public class Member implements Cloneable {
    private String name;
    private int age;
    private Address address;

    @Override
    public Member clone() {
        try {
            return (Member) super.clone();
        } catch (CloneNotSupportedException e) {
            // Cloneable을 구현했기 때문에 이 블록이 실행되는 일은 없다.
            return null;
        }
    }
}

위 의 코드를 1개의 member를 만들고 이를 클론 시 어떤 문제가 생길까?

member1.address 와 member2.address 가 참조변수가 가리키고 있는 객체의 주소 값만을 복사하는 얕은 복사가 일어날 수 있다.

앞서 설명했듯이 만약 Address 객체가 변경 불가능한 객체, 즉 immutable 하다면 상태가 변경될 일이 없기 때문에 크게 문제가 되지는 않을 것이다.

그러나 Address 객체가 변경 가능하고 실제로 값을 변경한다면 문제가 될 수 있다.

따라서 이는 override 한 clone() 영역에서 Adress 부분을 deepcopy 해주기 위한 추가적인 코드가 필요하다!!


지금까지 그냥 당연히 존재하는 줄 만 알았던 Object 클래스에 대해 알아보고 이해하는 시간을 가졌다!

틀렸거나, 질문사항은 댓글로 남겨주세요 ㅎㅎㅎ


참고자료

https://developer-youngjun.tistory.com/20

Fastcampus Java.spring 수업 ch4 - object class

profile
개발 및 취준 일지

0개의 댓글