JAVA - Object 클래스

ubiies·2023년 5월 13일
0

JAVA

목록 보기
2/4
java.lang.*;

프로그래밍 시 import하지 않아도 자동으로 추가가 되며 많이 사용하는 기본 클래스들이 속한 패키지이다.
하위 클래스로는 Object 클래스가 있다.

Object 클래스

모든 클래스의 최상위 클래스이다.
모든 클래스는 Object 클래스를 상속받으며 구현된 메소드들을 전부 사용 가능하다.
모든 클래스는 Object 클래스의 메서드 중 일부 메서드를 재정의할 수 있다. (final로 선언된 메서드 제외)

하지만, Object 클래스를 상속 받았다는 것을 표현하지 않고도 Object 클래스의 메서드를 이용할 수 있다.

class Student{
	int studentID;
	String studentName;
}

왜냐하면, 컴파일러가 자동으로 extends Object를 추가해주기 때문이다.

class Student extends Objects{
	int studentID;
	String studentName;
}

Object 클래스 메서드

우리가 자주 쓰는 Object 클래스의 메서드에 대해 알아보자.

  1. toString() 메서드
    객체의 정보를 String, 문자열로 바꾸어서 사용할 때 많이 쓰인다. 또한 재정의하여 객체에 대한 설명이나 특정 멤버 변수 값을 반환할 수도 있다.
class Student2{
    int StudentID;
    String StudentName;

    public Student2(int studentID, String studentName) {
        StudentID = studentID;
        StudentName = studentName;
    }
}

public class ToStringEx2 {
    public static void main(String[] args) {
        Student2 student2 = new Student2(20194440, "은비");
        System.out.println(student2);
    }
}
section3.object.Student2@7a81197d

toString() 메서드를 재정의하지 않을 경우 이렇게 자신의 주소값을 반환한다. 그렇다면 toString 메서드를 재정의해보자.

Student2 클래스 내부에서 cmd+n을 누르면 이렇게 친절하게 Object의 메서드들을 바로 재정의할 수 있다.

@Override
    public String toString() {
        return "Student2{" +
                "StudentID=" + StudentID +
                ", StudentName='" + StudentName + '\'' +
                '}';
    }

inteliJ가 이렇게 자동으로 오버라이딩 해준다.

Student2{StudentID=20194440, StudentName='은비'}

아까의 주소값이 아닌, 재정의한대로 결과가 나왔다.

String str = new String("test");   
System.out.println(str);
test

하지만, String 클래스의 경우 toString을 재정의하지 않아도 주소값이 아닌 test를 출력한다. 그 이유는 바로 String 클래스에 이미 toString이 재정의되어 있기 때문이다.


  1. equals(Objects obj) 메서드
    두 인스턴스가 동일한지 여부를 반환하며 재정의하여 논리적으로 동일한 인스턴스임을 정의할 수 있다.
  • 두 개의 인스턴스가 같다 = 같은 메모리여야 한다
    논리적으로 같은 두 개의 인스턴스는 동일한 해시 코드의 값을 반환하는 게 맞으며 논리적으로 같은 값이라면 해시 코드의 값 또한 같아야 한다.
public class EqualsEx2 {
    public static void main(String[] args) {
        String str1 = new String("test");
        String str2 = new String("test");
        System.out.println(str1 == str2);
    }
}

String 인스턴스를 생성하고 같은 값인지 확인해보자.

false

이 둘은 논리적으로 같은 값이나 물리적으로 다른 주소 값을 가지기 때문에 결과는 false가 나온다.

System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
918221580
2055281021

System.identityHashCode를 이용하여 주소값을 확인하니 역시 다르게 저장되어 있다.

class Member{
    int memberID;
    String memberName;

    public Member(int memberID, String memberName) {
        this.memberID = memberID;
        this.memberName = memberName;
    }
}

public class EqualsEx2 {
    public static void main(String[] args) {
        String str1 = new String("test");
        String str2 = new String("test");
        System.out.println(str1 == str2);
        System.out.println(System.identityHashCode(str1));
        System.out.println(System.identityHashCode(str2));

        Member member1 = new Member(2001,"eunbi");
        Member member2 = new Member(2001,"eunbi");
        System.out.println(member1==member2);
        System.out.println(System.identityHashCode(member1));
        System.out.println(System.identityHashCode(member2));

    }
}

직접 Member 클래스를 생성해서 위와 같이 다시 확인해보자.

false
918221580
2055281021
false
617901222
1159190947

역시나 결과는 이렇다. 그러면 Member 클래스에 equals 메서드를 재정의해보자.

아까와 같이 command+n을 누르고 추가하면 된다.

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Member member = (Member) o;
        return memberID == member.memberID && Objects.equals(memberName, member.memberName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(memberID, memberName);
    }

위와 마찬가지로 Member 클래스에 오버라이딩되었다. 역시나 편한 inteliJ

public class EqualsEx2 {
    public static void main(String[] args) {
        Member member1 = new Member(2001, "eunbi");
        Member member2 = new Member(2001, "eunbi");

        System.out.println(member1.equals(member2));
        System.out.println(System.identityHashCode(member1));
        System.out.println(System.identityHashCode(member2));
        System.out.println(member1.hashCode());
        System.out.println(member2.hashCode());
    }
}
true
2055281021
1554547125
96933013
96933013

equals 메서드로 논리적으로 같음을 정의하고, System.identityHashCode로 확인해본 결과 원래 다른 주소값에 저장되어 있던, 즉 물리적으로 다른 값이였던 두 인스턴스가 hashCode() 메서드를 이용하여 같은 물리적 주소값이 반환된 것을 확인할 수 있다.


  1. hashCode() 메서드
    hash : 정보를 저장, 검색하기 위해 사용되는 자료 구조이다. 힙 메모리에 인스턴스가 저장되는 방식이 바로 hash이다.
    hashCode() 메서드는 자료의 특정 값(키 값)에 대해 저장 위치를 반환해주는 해시 함수를 사용한다. 해시 함수는 어떤 정보인가에 따라서 다르게 구현된다.

  2. clone() 메서드
    객체의 원본을 복제하는데 사용하는 메서드이다. 원본을 유지해 놓고 복사본을 사용할 때, 기본 틀을 두고 복잡한 생성과정을 반복하지 않고 복제할 때 사용된다.객체의 클론 메서드를 사용을 허용한다는 의미로 cloneable 인터페시를 반드시 명시해야한다.
class Point{
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

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

class Circle implements Cloneable {
    Point point;
    private int radius;

    public Circle(int x, int y, int radius) {
        point = new Point(x,y);
        this.radius = radius;
    }

    @Override
    public String toString() {
        return "Circle{" +
                "point=" + point +
                ", radius=" + radius +
                '}';
    }

    // 반환형이 오브젝트
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class CloneEx {
    // clone할 수 없을 때 예외처리가 생김 일단 throws 처리
    public static void main(String[] args) throws CloneNotSupportedException {
        Circle circle = new Circle(10,20,5);
        Circle cloneCircle = (Circle)circle.clone();

        System.out.println(System.identityHashCode(circle));
        System.out.println(System.identityHashCode(cloneCircle));

        System.out.println(circle);
        System.out.println(cloneCircle);
    }
}

0개의 댓글