자바 (ref. 자바의정석)

Object 클래스 - JAVA

쿠쿠s 2022. 4. 11. 21:31

 

java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Obecjt이다. Obejct 클래스는 모든 클래스의 최고 조상이기 때문에 해당 멤버들은 모든 클래스에서 바로 사용이 가능합니다. 멤버변수는 없고 11개의 메서드만 가지고 있습니다. 해당 포스터에서는 5가지만 정리하도록 하겠습니다.

 

 


 

 

equals(Object obj) 


매개변수로 객체의 참조변수를 받아 비교하여 boolean 값으로 return 합니다.

 

Object.java 에 equals

 

두 객체의 같고 다름을 참조변수의 값으로 판단합니다. 그래서 두 객체가 다르면 항상 false를 반환하게 됩니다.

예제 코드를 들어 설명을 드리겠습니다.

 

import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);
        String a = new String("abc");
        String b = new String("abc");


        System.out.println("Value 객체 결과 =>" + num1.equals(num2));
        System.out.println("String 결과 =>" + a.equals(b));
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }
}

출력 결과

 

 

분명 Value의 인스턴스인 num1, num2 의 값은 같은데 false를 출력하고, String a, b 의 값은 같은데 왜 true라는 다른 결과가 나왔을까요? 그 이유는 Value의 equals는 실제 인스턴스 주소를 비교를 하기 때문에 값이 10으로 같더라도 주소값이 달라서 false를 반환합니다. String클래스의 equals는 오버라이딩을 통해 재정의 되었으며, 주소값이 아닌 실제 문자열을 비교하기 때문에 true가 반환됩니다.

 

 

String.java 의 equlas

그래서 객체에 대한 어떤 값을 비교하고자 하면 오버라이딩을 통하여 equals 를 재정의 하여 사용하면 됩니다.

 

*String 클래스뿐만 아니라 Date, File, wrapper클래스(Integer, Double 등)의 equals 메서드도 주소값이 아닌 내용을 비교하도록 오버라이딩 되어있다. 의외로 StringBuffer, Builder 클래스는 오버라이딩되어 있지 않다.

 

 

 

hashCode( )


해당 메서드는 해싱기법에 사용되는 해시함수를 구현한 것입니다. 해시함수는 찾고자 하는 값을 입력하면 그 값이 저장된 위치를 알려주는 해시코드를 반환합니다. Object의 hashCode 는 객체의 주소값을 이용해 해시코드를 만들어 반환하기 때문에 서로 다른 두 객체는 결코 같은 해시코드를 가질 수 없습니다.

 

import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);
        String a = new String("abc");
        String b = new String("abc");


        System.out.println("Value num1 해시코드 결과 =>" + num1.hashCode());
        System.out.println("Value num1 해시코드 결과 =>" + num2.hashCode());
        System.out.println("String a 해시코드 결과 =>" + a.hashCode());
        System.out.println("String b 해시코드 결과 =>" + b.hashCode());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }

    }
}

출력 결과

 

 

결과를 보고 눈치를 채셨을 것입니다. Value 클래스로 생성된 인스턴스는 '다른 객체' 이기에 다른 해시코드값을 반환을 하였고, String 클래스로 생성된 인스턴스는 hashCode가 오버라이딩 되어있기 때문에 같은 해시코드를 반환하게 됩니다.

 

 

 


 

 

toString( )


해당 메서드는 인스턴스에 대한 정보를 문자열(String)로 제공할 목적으로 정의한 것입니다. 인스턴스 변수에 저장된 값들을 문자열로 표현한다는 뜻입니다.

 

Object.java 의 toSting

실제 Obejct 클래스의 내부를 보면 16진수의 해시코드를 얻기 때문에 오버라이딩을 하여 사용을 해야 합니다.

 

 

오버라이딩 사용X 코드

import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);

        System.out.println("Value num1 해시코드 결과 =>" + num1.toString());
        System.out.println("Value num2 해시코드 결과 =>" + num2.toString());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }
}

오버라이딩 사용x 결과

 

오버라이딩을 사용하지 않으면 실제로 Value클래스의 16진수 해시값을 반환하는 결과를 얻게 됩니다.

 

 

오버라이딩 사용한 코드

import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);

        System.out.println("Value num1 toString 결과 =>" + num1.toString());
        System.out.println("Value num2 toString 결과 =>" + num2.toString());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }

        @Override
        public String toString() {
            return "Value{" +
                    "x=" + x +
                    '}';
        }
    }
}

오버라이딩 사용 출력 결과

 


 

clone( )


자신을 복제하여 새로운 인스턴스를 생성한다. 단순히 인스턴스 변수의 값만을 복사하기 때문에 참조 타입의 인스턴스 변수가 있는 클래스는 완전한 인스턴스가 복제가 되지 않습니다. 즉 주소를 복사하는 얕은 복사가 이루어져 복사본을 수정해도 같은 주소값을 가지기 때문에 원본도 같이 수정이 됩니다. 그래서 오버라이딩을 통하여 해결을 해야 합니다. 

그런데 clone을 오버라이딩해서 사용하려면 Cloneable 인터페이스를 구현을 해야 합니다. 이유는 Cloneable 인터페이스를 구현을 하지 않으면 예외가 발생할 뿐만 아니라, 인스턴스의 데이터를 보호하기 위해서입니다. 해당 인터페이스가 구현되어 있다는 것은 클래스 작성자가 복제를 허용한다는 의미입니다.

 

 

 

import java.io.*;
import java.util.ArrayList;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }

        ArrayList<Integer> cloneList = (ArrayList<Integer>) list.clone();
        cloneList.remove(2);

        System.out.println("원본 =" + list.toString());
        System.out.println("사본 =" + cloneList.toString());

    }
}

출력 결과

 

 

clone()을 사용하여 ArrayList를 복사를 해봤습니다. ArrayList도 객체이기 때문에 Object클래스를 상속받으며 동시에 Cloneable인터페이스와 Serializable인터페이스가 구현이 되어 있습니다. 그래서 Obejct의 클래스 멤버들을 모두 상속받으며, public으로 오버라이딩 해서 직접 호출이 가능하고 반환값이 Obejct 이기 때문에 형변환을 해야 합니다.

 

 

Cloneable, Serializable 상속

 

ArrayList.java 의 clone

 

ArrayList뿐만 아니라 Vector, LinkedList, HashSet, TreeSet, HashMap, TreeMap, Calendar, Date와 같은 클래스들이 이와 같은 방식으로 복제가 가능합니다.

 

 

 

 

getClass( )


해당 메서드는 자신이 속한 클래스의 Class 객체를 반환하는 메서드 입니다. Class객체는 클래스의 모든 정보를 담고 있으며, 클래스당 오직 1개만 존재합니다. 클래스 파일이 '클래스 로더(ClassLodaer)` 에 의해서 메모리에 올라갈 때 자동 생성됩니다. 

Class객체를 이용하면 클래스에 모든 정보를 얻을 수 있기 때문에 동적으로 코드 작성이 가능한데 여기서는 생략을 하겠습니다 '리플렉션 API' 를 검색하시면 됩니다.

 

 

import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new ValueChild(10);
        String a = new String("abc");

        System.out.println("Value num1 getClass 결과 =>" + num1.getClass());
        System.out.println("Value num2 getClass 결과 =>" + num2.getClass());
        System.out.println("String a getClass 결과 =>" + a.getClass());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }

    static class ValueChild extends Value{

        public ValueChild(int x) {
            super(x);
        }
    }
}

출력결과