Programming

; develop a program

Back-End/Java

[Java] Object 클래스

Clloud_ 2023. 2. 10. 09:14
반응형

자바로 프로그램을 구현하면서 주로 사용하는 String, Integer와 같은 클래스는  java.lang 패키지에 속해 있다.

  • String >> java.lang.String
  • Integer >> java.lang.Integer
java.lang 패키지에는 기본적으로 많이 사용하는 클래스들이 포함되어 있다.

 

이번 포스팅에서는 자바(Java)에서 최상위 클래스인 java.lang.Object에 대하여 공부를 해보고자 한다.

 


Object 클래스란

Object 클래스는 java.lang 패키지 중에서 가장 많이 사용되는 클래스이자 모든 자바 클래스의 최상위 클래스이다.

따라서 자바의 모든 클래스는 Object 클래스의 모든 메서드를 상속받아 바로 사용할 수 있다.

 

이러한 Object 클래스는 필드를 가지지 않으며, 메서드로 구성되어 있다.

이 메서드들은 모든 클래스들이 Object 클래스를 상속하므로, 모든 클래스에서 이용할 수 있다.

 

주로 사용되는 Object 메서드

메서드 설명
String toString( ) 객체를 문자열로 표현하여 반환
재정의하여 객체에 대한 설명이나 특정 멤버 변수 값을 반환
boolean equals(Object obj) 두 인스턴스가 동일한지 여부를 반환
재정의하여 논리적으로 동일한 인스턴스임을 정의할 수 있다.
int hashCode( ) 객체의 해시 코드 값을 반환
Object clone( ) 객체를 복제하여 동일한 멤버 변수 값을 가진 새로운 인스턴스 생성
Class getClass( ) 객체의 Class 클래스를 반환
void finalize( ) 인스턴스가 힙 메모리에서 제거될 때 가비지 컬렉터에 의해 호출되는 메서드
네트워크 연결 해제, 열려있는 파일 스트링 해제 등을 구현
void wait( ) 멀티스레드 프로그램에서 사용하는 메서드
스레드를 '기다리는 상태'(non runnable)로 만든다.
void notify( ) wait( ) 메서드에 의해 기다리고 있는 스레드(non runnable 상태)를 실행 가능한 상태(runnable)로 가져온다.
  • Object 메서드 중에는 재정의할 수 있는 메서드도 있고, 그렇지 않은 메서드도 있다.

 


toString( ) 메서드

  • toString( ) 메서드는 이름처럼 객체 정보를 문자열(String)로 바꾸어 준다.
  • Object 클래스를 상속받은 모든 클래스는 toString( )을 재정의할 수 있다.
  • String이나 Integer 등 여러 JDK 클래스에는 toString( ) 메서드가 이미 재정의되어 있다.
  • toString( )의 원형은 생성된 인스턴스의 클래스 이름과 주소 값을 보여준다.

 

toString( ) 메서드 사용

class Book{
    int bookNumber;
    String bookTitle;

    Book(int bookNumber, String bookTitle){	//책 번호와 제목을 매개변수로 입력받는 생성자
        this.bookNumber = bookNumber;
        this.bookTitle = bookTitle;
    }
}

public class ToStringEx {
    public static void main(String[] args) {
    Book book1 = new Book(200, "개미");

    //인스턴스 정보(클래스 이름 주소 값)
    System.out.println(book1);	
    //toString() 메서드로 인스턴스 정보(클래스 이름, 주소 값)을 보여준다
    System.out.println(book1.toString());	.
    }
}
  • 16행 System.out.println( ) 출력문에 참조 변수를 넣으면 인스턴스 정보가 출력되는데, 이때 자동으로 호출되는 메서드가 toString( )이다.
  • 여기에서 호출되는 toString( )은 Book 클래스의 메서드가 아닌 Object 클래스의 메서드이다.
Object 클래스의 toString( ) 메서드 원형은 다음과 같다.
//클래스 이름@해시 코드 값
getClass().getName() + '@' + Integer.toHexString(hashCode())​

 

출력 화면

object.Book@16f65612
object.Book@16f65612

 

toString( ) 메서드 재정의

class Book{
    int bookNumber;
    String bookTitle;

	Book(int bookNumber, String bookTitle){
        this.bookNumber = bookNumber;
        this.bookTitle = bookTitle;
    }

    //toString() 메서드 재정의
    @Override
    public String toString() {		
        return bookTitle + "," + bookNumber;
    }
}

public class ToStringEx {
    public static void main(String[] args) {
    Book book1 = new Book(200, "개미");

    System.out.println(book1);
    System.out.println(book1.toString());
    }
}
  • toString( ) 메서드를 직접 재정의하면 객체의 참조 변수를 이용해 원하는 문자열을 표현할 수 있다.

 

출력 결과

개미,200
개미,200

 


equals( ) 메서드

equals( ) 메서드는 두 인스턴스의 주소 값을 비교하여 boolean 값(true/false)을 반환해 주는 것이다.

주소값이 같다면 당연히 같은 인스턴스이다.

 

서로 다른 주소 값을 가질 때도 같은 인스턴스라고 정의할 수 있는 경우가 있다.

  • 물리적 동일성(인스턴스의 메모리 주소가 같음)
  • 논리적 동일성(논리적으로 두 인스턴스가 같음)
두 가지 경우를 구현할 때도 equals( ) 메서드를 재정의하여 사용한다.

 

인스턴스를 가리키는 참조 변수가 두 개 있을 때 이 두 인스턴스가 물리적으로 같다는 것은, 두 인스턴스의 주소 값이 같은 경우를 말한다.

두 변수가 같은 메모리 주소를 가리키고 있다는 뜻이다.

Student studentHong = new Student(100, "홍길동");
Student studentHong2 = studentHong;	// 주소 복사

System.out.println(studentHong.equals(studentHong2));	//true
  • Student 클래스를 생성하고, 생성된 인스턴스를 가리키는 참조 변수(studentHong)를 다른 변수(studentHong2)에 복사한다.
  • 두 변수는 동일한 인스턴스를 가리킨다.
    (equals( ) 메서드를 이용해 두 변수를 비교하면 동일하다는 결과가 나온다.)

 

다음 코드는 이름과 학번이 동일한 한 명을 더 생성하고 다른 변수(studentDong)가 가리키는 코드이다.

Student studentHong = new Student(100, "홍길동");
Student studentHong2 = studentHong;	
Student studentDong = new Student(100, "홍길동");

System.out.println(studentHong.equals(studentDong));	//false
  • studentHong, studentHong2가 가리키는 인스턴스와 studentDong이 가리키는 인스턴스는 서로 다른 주소를 가지고 있지만, 저장된 학생의 정보는 같다.

 

String과 Integer 클래스의 equals( ) 메서드

public class StringEquals {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1 == str2);  // 두 스트링 인스턴스의 주소 값은 다름
        System.out.println(str1.equals(str2)); // String 클래스의 equals 메소드가 재정의 됨

        Integer i1 = new Integer(100);
        Integer i2 = new Integer(100);

        System.out.println(i1 == i2);   // 두 정수 인스턴스의 주소 값은 다름 
        System.out.println(i1.equals(i2)); // Integer 클래스의 equals 메소드가 재정의 됨
    }
}
  • str1과 str2는 서로 다른 인스턴스를 가리키기 때문에 str1 == str2의 결과는 false이다.
  • String 클래스의 equals( ) 메서드는 같은 문자열의 경우 true를, 그렇지 않은 경우 false를 반환하도록 재정의되어 있다.
  • 두 문자열은 "abc"로 같은 값을 가지기 때문에 str1.equals(str2)의 반환 값은 true이다.
  • Integer 클래스의 경우도 정수 값이 같은 경우 true를 반환하도록 equals( ) 메서드가 재정의되어 있음을 알 수 있다.

 

출력 결과

false
true
false
true

 


hashCode( ) 메서드

  • 해시(hash)는 정보를 저장하거나 검색할 때 사용하는 자료구조다.
  • 정보를 어디에 저장할 것인지, 어디서 가져올 것인지 해시 함수를 사용하여 구현한다.
  • 해시 함수는 객체의 특정 정보(키 값)을 매개변수 값으로 넣으면 그 객체가 저장되어야 할 위치나 저장된 해시 테이블 주소(위치)를 반환한다.
    (객체 정보를 알면 해당 객체의 위치를 빠르게 검색할 수 있다.)
  • 해시 함수[(hash(key))]는 개발하는 프로그램 특성에 따라 다르게 구현된다.

 

인스턴스를 힙 메모리에 생성하여 관리할 때 해시 알고리즘을 사용한다.

//객체의 해시코드 값(메모리 위치 값)이 반환됨
hashCode = hash(key);
  • 자바에서는 두 인스턴스가 같다면 hashCode( ) 메서드에서 반환하는 해시 코드 값이 같아야 한다.
  • 논리적으로 같은 두 객체도 같은 해시 코드 값을 반환하는 해시 코드 값이 같아야 한다.
  • 따라서 논리적으로 같은 두 객체도 같은 해시 코드 값을 반환하도록 hashCode( ) 메서드를 재정의해야 한다.
    (즉, equals( ) 메서드를 재정의했다면 hashCode( ) 메서드도 재정의해야 한다.)

 

String과 Integer 클래스의 hashCode( ) 메서드

public class HashCodeTest {
    public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");

        //abc 문자열의 해시 코드 값 출력
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());

        Integer i1 = new Integer(100);
        Integer i2 = new Integer(100);

        //Integer(100)의 해시 코드 값 출력
        System.out.println(i1.hashCode());
        System.out.println(i2.hashCode());
    }
}
  • 7~8행을 보면 String 클래스는 같은 문자열을 가진 경우, 즉 equals( ) 메서드의 결과 값이 true인 경우 hashCode( ) 메서드는 동일한 해시 코드 값을 반환한다.
  • Integer 클래스의 hashCode( ) 메서드는 정수 값을 반환하도록 재정의되어 있다.

 


clone( ) 메서드

clone( ) 메서드는 객체 원본을 유지해 놓고 복사본을 사용한다거나, 기본 틀(prototype)의 복사본을 사용해 동일한 인스턴스를 만들어 복잡한 생성 과정을 간단히 하려는 경우에 clone( ) 메서드를 사용할 수 있다.

 

clone( ) 메서드는 다음과 같이 선언되어 있으며, 객체를 복제해 또 다른 객체를 반환해 주는 메서드이다.

protected Object clone();

 

clone( ) 메서드로 인스턴스 복제

class Point{	//원점을 의미하는 Point 클래스
    int x;
    int y;

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

    public String toString(){
        return "x = " + x + "," + "y = " + y;
    }
}

//객체를 복제해도 된다는 의미로 Cloneable 인터페이스를 함께 선언
class Circle implements Cloneable{
    Point point;
    int radius;

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

    public String toString(){
        return "원점은 " + point + "이고," + "반지름은 " + radius + "입니다"; 
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
	}
}

public class ObjectCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Circle circle = new Circle(10, 20, 30);
        //clone() 메서드를 사용해 circle 인스턴스를 copyCircle에 복제함
        Circle copyCircle = (Circle)circle.clone();

        System.out.println(circle);
        System.out.println(copyCircle);
        System.out.println(System.identityHashCode(circle));
        System.out.println(System.identityHashCode(copyCircle));
    }
}
  • clone( ) 메서드를 사용하려면 객체를 복제해도 된다는 의미로 클래스에 Cloneable 인터페이스를 구현해야 한다.
  • 만약 clone( ) 메서드만 재정의하고 Cloneable 인터페이스를 명시하지 않으면 clone( ) 메서드를 호출할 때 CloneNotSupportedException이 발생한다.
  • Object의 clone( ) 메서드는 클래스의 인스턴스를 새로 복제하여 생성해준다.
    (멤버 변수가 동일한 인스턴스가 다른 메모리에 새로 생성하는 것이다.)

 


반응형

'Back-End > Java' 카테고리의 다른 글

[Java] 인터페이스 요소  (0) 2023.02.10
[Java] 인터페이스와 다형성  (0) 2023.02.09
[Java] 인터페이스(Interface)  (0) 2023.02.09
[Java] final 예약어  (0) 2023.02.08
[Java] 템플릿 메서드(Template Method)  (0) 2023.02.07