생활코딩

Coding Everybody

Object 클래스

모든 클래스의 조상인 Object 클래스에 대해서 알아본다.
토픽 생활코딩 > 언어 > Java

상속

자바에서 상속이란 필수적이다. 여러분이 상속하건 하지 않았건 기본적인 상속을 하게 된다.

package org.opentutorials.javatutorials.progenitor;

class O {}

위의 코드는 아래와 코드가 같다.

package org.opentutorials.javatutorials.progenitor;

class O extends Object {}

자바에서 모든 클래스는 사실 Object를 암시적으로 상속받고 있는 것이다. 그런 점에서 Object는 모든 클래스의 조상이라고 할 수 있다. 그 이유는 모든 클래스가 공통으로 포함하고 있어야 하는 기능을 제공하기 위해서다.

API 문서를 보자.

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

메소드의 목록을 살펴보자.

위의 그림은 Object 클래스가 가지고 있는 메소드를 보여준다. 다시 말해서 자바의 객체는 위의 메소드들을 반드시 가지고 있다고 할 수 있다. 이 중에 중요하면서 입문 단계에서 이해할 수 있는 API들을 살펴보자.

toString

toString은 객체를 문자로 표현하는 메소드이다. 기본 예제인 계산기 코드를 보자.

package org.opentutorials.javatutorials.progenitor;

class Calculator{
    int left, right;
     
    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    }
    public void sum(){
        System.out.println(this.left+this.right);
    }
     
    public void avg(){
        System.out.println((this.left+this.right)/2);
    }
}
 
public class CalculatorDemo {
     
    public static void main(String[] args) {
         
        Calculator c1 = new Calculator();
        c1.setOprands(10, 20);
        System.out.println(c1);
    }
 
}

25라인에 아래 코드는 클래스 Calculator의 인스턴스 c1을 화면에 출력하고 있다.

System.out.println(c1);

필자의 결과는 아래와 같다. @ 뒤의 내용은 각자 다를 것이다.

org.opentutorials.javatutorials.progenitor.Calculator@11be650f

이것은 인스턴스 c1이 클래스 Calculator의 인스턴스라는 의미다. @ 뒤의 내용은 인스턴스에 대한 고유한 식별 값이라고 생각하자.

위의 정보도 유용한 정보이지만 클래스 설계자의 필요에 따라서 toString의 결과를 더욱 유용하게 만들 수 있다. 예를들어 계산기 인스턴스의 left, right 값을 알 수 있다면 개발을 좀 더 편하게 할 수 있을 것이다.

package org.opentutorials.javatutorials.progenitor;

class Calculator{
    int left, right;
     
    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    }
    public void sum(){
        System.out.println(this.left+this.right);
    }
     
    public void avg(){
        System.out.println((this.left+this.right)/2);
    }
    
    public String toString(){
        return "left : " + this.left + ", right : "+ this.right;
    }
}
 
public class CalculatorDemo {
     
    public static void main(String[] args) {
         
        Calculator c1 = new Calculator();
        c1.setOprands(10, 20);
        System.out.println(c1);
        System.out.println(c1.toString());
    }
 
}

차이점

실행결과

left : 10, right : 20
left : 10, right : 20

클래스 Calculator에 toString을 재정의(overiding)했다. 그리고 인스턴스를 System.out.println의 인자로 전달하니까 toString을 명시적으로 호출하지 않았음에도 동일한 효과가 나고 있다. toString 메소드는 자바에서 특별히 취급하는 메소드다. toString을 직접 호출하지 않아도 어떤 객체를 System.out.print로 호출하면 자동으로 toString이 호출되도록 약속되어 있다.

이를 통해서 인스턴스 c1의 상태를 쉽게 파악할 수 있게 되었다.

equals

equals는 객체와 객체가 같은 것인지를 비교하는 API이다. 객체 간에 같고 다름은 필요에 따라서 달라질 수 있기 때문이다.

package org.opentutorials.javatutorials.progenitor;

class Student{
    String name;
	Student(String name){
		this.name = name;
	}
	public boolean equals(Object obj) {
		Student _obj = (Student)obj;
		return name == _obj.name;
	}
}

class ObjectDemo {

	public static void main(String[] args) {
		Student s1 = new Student("egoing");
		Student s2 = new Student("egoing");
		System.out.println(s1 == s2);
		System.out.println(s1.equals(s2));

	}

}

결과는 아래와 같다.

false
true

아래 코드를 보자.

System.out.println(s1 == s2);

결과는 false다.

그 이유는 s1과 s2가 서로 다른 객체이기 때문이다. 어찌 보면 당연한 결과다. 하지만 두 개의 객체가 논리적으로는 egoing이라는 값을 가지고 있기 때문에 객체를 만든 필자는 저 두 개의 객체가 같은 객체로 간주 되었으면 좋겠다. 이럴 때 클래스 Object의 메소드 equals를 overiding하면 된다. 

public boolean equals(Object obj) {
	Student _obj = (Student)obj;
	return name == _obj.name;
}

위의 코드 (Student)obj 는 메소드 equals로 전달된 obj의 데이터 타입이 Object이기 때문에 이를 Student 타입으로 형 변환하는 코드다.  아래 코드를 통해서 현재 객체의 변수 name과 equals의 인자로 전달된 객체의 변수 name을 비교한 결과를 Boolean 값으로 리턴하고 있다. 이 값에 따라서 두 개의 객체는 같거나 다른 것이 된다. 

return name == _obj.name;

그런데 eqauls를 제대로 사용하기 위해서는 hashCode라는 클래스도 함께 구현해야 한다. 하지만 이에 대한 이야기는 우리 수업의 범위를 넘어서고 그 효용(사용 빈도)도 높지 않기 때문에 더 이상 설명을 하지 않겠다. 하지만 이 메소드의 취지를 이해하는 것은 또한 중요하기 때문에 언급을 하지 않을 수는 없었다. 메소드 equals에 대해서 필자가 권고하는 입장은 아래와 같다.

1. 객체 간에 동일성을 비교하고 싶을 때는 ==를 사용하지 말고 equals를 이용하자.

2. equals를 직접 구현해야 한다면 hashCode도 함께 구현해야 함을 알고 이에 대한 분명한 학습을 한 후에 구현하자.

3. equals를 직접 구현해야 한다면 eclipse와 같은 개발도구들은 equals와 hashCode를 자동으로 생성해주는 기능을 가지고 있다. 이 기능을 이용하는 것을 고려해보자. 아래 그림을 참고하자.

 4. 그 이유가 분명하지 않다면 비교 연산자 == 은 원시 데이터형을 비교할 때만 사용하자.

원시 데이터 형(Primitive Data Type)이란 자바에서 기본적으로 제공하는 데이터 타입으로 byte, short, int, long, float, double, boolean, char가 있다. 이러한 데이터 타입들은 new 연산자를 이용해서 생성하지 않아도 사용될 수 있다는 특징이 있다.

 finalize

finalize는 객체가 소멸될 때 호출되기로 약속된 메소드이다. 여기서는 이 메소드의 취지만 이해하면 된다. 많은 자바의 전문가들이 이 메소드의 사용을 만류하고 있다.

이 메소드 보다는 가비지 컬렉션(garbage collection)에 대해서 알아보자. 인스턴스를 만드는 것은 내부적으로는 컴퓨터의 메모리를 사용하는 것이다. 여기서 말하는 메모리는 RAM을 의미한다. 램은 가장 빠른 저장 장치이기 때문에 컴퓨터 프로그램들은 이 램에 저장된 후에 동작하게 된다. 하지만 램은 가격이 비싸고 용량이 적기 때문에 램은 컴퓨터에서 가장 소중한 저장 장치라고 할 수 있다. 그러므로 램의 적게 사용하는 프로그램이 좋은 프로그램이다. 그런 이유로 많은 프로그래밍 언어들이 램을 효율적으로 사용하기 위해서 더 이상 사용하지 않는 데이터를 램에서 제거할 수 있는 방법들을 제공한다.

하지만 자바에서는 이러한 방법이 제한적으로 제공되고 있는데 그것은 자동으로 해주기 때문이다. 이 작업을 자동화한 것을 가비지 컬렉션이라고 한다. 이를테면 어떤 인스턴스를 만들었고, 그것을 변수에 담았다. 그런데 그 변수를 사용하는 곳이 더 이상 없다면 이 변수와 변수에 담겨있는 인스턴스는 더 이상 메모리에 머물고 있을 필요가 없는 것이다. 자바는 이를 감지하고 자동으로 쓰지 않은 데이터를 삭제한다. 따라서 개발자가 사용하지 않는 데이터를 직접 삭제하는 작업을 하지 않아도 되는 것이다. 이것은 어려운 메모리 관리로부터 개발자들의 부담을 경감시킨 도약이라고 할 수 있다.

그럼에도 불구하고 좋은 에플리케이션을 만들기 위해서는 가비지 컬렉션에 대한 이해는 필요하다. 하지만 이는 우리 수업의 취지를 벗어나기 때문에 링크로 대체하겠다.

Java Garbage collection(NHN Hello world 블로그)

clone

clone은 복제라는 뜻이다. 어떤 객체가 있을 때 그 객체와 똑같은 객체를 복제해주는 기능이 clone 메소드의 역할이다. 예를 보자.

package org.opentutorials.javatutorials.progenitor;

class Student implements Cloneable{
    String name;
	Student(String name){
		this.name = name;
	}
	protected Object clone() throws CloneNotSupportedException{
		return super.clone();
	}
}

class ObjectDemo {

	public static void main(String[] args) {
		Student s1 = new Student("egoing");
		try {
			Student s2 = (Student)s1.clone();
			System.out.println(s1.name);
			System.out.println(s2.name);
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
	}

}

차이점

Student 예를 조금 변형했다. 결과는 아래와 같다. 복사에 성공했다.

egoing
egoing

위의 코드에서 클래스 Student가 인터페이스 Cloneable을 구현하고 있는 것을 주의 깊게 살펴보자. 인터페이스 Cloneable의 코드는 실제 내용은 아래와 같다.

public interface Cloneable {}

비어있는 인터페이스다. 그럼에도 불구하고 이것을 사용한 이유는 클래스 Student가 복제 가능하다는 것을 표시하기 위한 것이다. 만약 이 인터페이스를 구현하지 않고 있는 클래스에 대한 복제를 시도하면 오류가 발생할 것이다.

만약 복사를 보다 정교하게 하고 싶다면 오버라이딩 한 메소드 clone를 직접 구현하면 된다. 하지만 이에 대한 논의는 우리 수업의 범위를 애매하게 넘어서는 것이기 때문에 필자는 설명하지 않는 것을 택하겠다.

이해해야 하는 것과 알아야 하는 것

Object 클래스를 놓고 생각해보자. 이 클래스가 모든 클래스의 부모라는 사실은 이해의 영역이 아니라 약속의 영역이다. 즉 자바를 만든 측과 자바를 사용하는 측의 약속이다. 그리고 이 클래스가 clone이나 toString과 같은 메소드를 가지고 있다는 것 또한 이해의 영역이 아니라 숙지해야 하는 영역이다. 한편 모든 클래스가 toString을 사용할 수 있고 또한 이 메소드를 새롭게 재정의 할 수 있다는 점은 이해의 영역이다. 어떤 지식을 배울 때는 이해해야 하는 것과 그냥 알아야 하는 것을 잘 분별하는 것이 중요하다.

댓글

댓글 본문
  1. coster97
    어려운데 재미따
  2. wwwqiqi
    완료
  3. Alan Turing
    09/08
  4. PassionOfStudy
    복습 6일차!
  5. PassionOfStudy
    Object 클래스!
  6. 코드파괴자
    22.05.09 Final Form Ride. Obj C.C.C.Class !!
  7. 모찌말랑카우
    22.03.02
  8. aesop0207
    22.02.18. Fri
  9. 드림보이
    2021.12.28. Object 클래스 파트 수강완료
  10. ydj54321
    clone()메소드로 복제한 두 인스턴스는 같은게 아닌가요? 다음코드에서 s2.eauqls(s1) 이 false네요. 궁금해서 여쭤봅니다.

    package study.dec27th;

    public class Student implements Cloneable{
    String name;
    Student(String name){
    this.name = name;
    }
    protected Object clone() throws CloneNotSupportedException{
    return super.clone();
    }
    }

    package study.dec27th;

    class ObjectDemo {
    public static void main(String[] args) {
    Student s1 = new Student("egoing");
    Student s2;
    try {
    s2 = (Student)s1.clone();
    System.out.println(s1.name);
    System.out.println(s2.name);
    System.out.println(s2.equals(s1)); //이부분이 false네요.
    } catch (CloneNotSupportedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
  11. syh712
    2021-12-10
    <오브젝트>
    1. 자바에서 모든 클래스는 사실 Object를 암시적으로 상속받고 있는 것이다.
    2. toString
    toString은 객체를 문자로 표현하는 메소드
    클래스 설계자의 필요에 따라서 toString의 결과를 더욱 유용하게 만들 수 있다. -

    3. equals
    - equals는 객체와 객체가 같은 것인지를 비교하는 API이다. 객체 간에 같고 다름은 필요에 따라서 달라질 수 있기 때문.
    메소드 equals시 권고사항
    1) 객체 간에 동일성을 비교하고 싶을 때는 ==를 사용하지 말고 equals를 이용하자.
    2) equals를 직접 구현해야 한다면 hashCode도 함께 구현해야 함을 알고 이에 대한 분명한 학습을 한 후에 구현하자.
    3) equals를 직접 구현해야 한다면 eclipse와 같은 개발도구들은 equals와 hashCode를 자동으로 생성해주는 기능을 가지고 있다. 이 기능을 이용하는 것을 고려해보자.
    4) 그 이유가 분명하지 않다면 비교 연산자 == 은 원시 데이터형을 비교할 때만 사용하자.
    *원시 데이터 형(Primitive Data Type)이란 자바에서 기본적으로 제공하는 데이터 타입으로 byte, short, int, long, float, double, boolean, char가 있다. 이러한 데이터 타입들은 new 연산자를 이용해서 생성하지 않아도 사용될 수 있다는 특징이 있음.

    4. finalize는 객체가 소멸될 때 호출되기로 약속된 메소드이다. 그러나 쓰는 건 가능하면 자제하도록.
    - 가비지 컬렉션(garbage collection): 자바는 쓰지않는 변수와 변수 딤겨있는 인스턴스를 자동으로 감지하고 자동으로 쓰지 않은 데이터를 삭제한다.

    5. clone
    - clone은 복제라는 뜻이다. 어떤 객체가 있을 때 그 객체와 똑같은 객체를 복제해주는 기능이 clone 메소드의 역할
    - 클래스 Student가 인터페이스 Cloneable을 구현.
    - 인터페이스 Cloneable의 코드는 실제 내용비어있는 인터페이스다.
    - 그럼에도 불구하고 이것을 사용한 이유는 클래스 Student가 복제 가능하다는 것을 표시하기 위한 것임.

    ** Object 클래스를 놓고 생각해보자. 이 클래스가 모든 클래스의 부모라는 사실은 이해의 영역이 아니라 약속의 영역. 이 클래스가 clone이나 toString과 같은 메소드를 가지고 있다는 것도 마찬가지ㅏ.
    ** 모든 클래스가 toString을 사용할 수 있고 또한 이 메소드를 새롭게 재정의 할 수 있다는 점은 이해의 영역.
  12. H4PPY
    1114
  13. IaaS
    2021-11-03 수강완료
  14. super1Nova
    210909
  15. Mark Kim
    toString() 강의 부분에서 toString()의 존재여부에 따라 출력값이 유사하지만 다르게 나오는데, 제 맥북 환경에서는 해쉬값이 동일하게 나옵니다. 혹시 운영체제에 따른 차이가 있을까요?
  16. 김수빈
    Clonealbe은 단순히 복제가 가능한 클래스라는걸 명시할 뿐 아무런 기능이 없습니다.
    즉 복제는 얘가 하는게 아닙니다.

    public object clone()에서 object는 반환값(리턴시에 받는 데이터타입) 이구요
    질문하신 clone이 바로 복제하는 로직을 지닌 메서드 입니다.

    정리하자면 clone() - object 클래스에 포함된 메서드. 복제하는 기능이 있음
    cloneable - clone()을 호출하려면 얘를 구현해야함 (약속)

    즉 Student의 clone()을 호출하게 되면 object(부모클래스)의 clone()을 호출하여
    객체를 복제하고, 그것을 Object 타입으로 Student의 clone()에 다시 리턴받는겁니다.

    그 이후

    복제한 객체는 데이터 타입이 Object 이기 때문에 복제하려는 객체의 데이터타입으로 형변환 해주는 거구요.
    대화보기
    • 악어수장
      2021-5-11 3강까지 완료
    • 석동현
      제 생각에, public object clone() 여기서 object 는, clone 메소드를 정의하는 문구에서
      리턴데이터타입, 을 나타내는 것 같습니다
      클론을 한 결과가 오브젝트(인스턴스지만...)로 나타나기 때문이 아닐까요?
      대화보기
      • 김요한
        한가지 질문이 있습니다.

        Cloneable 클래스를 복제하고 싶은 클래스에 implements(구현화)를 시켜서 복제가 가능하다는 권리를 부여하고

        해당 클래스를 메인 메소드에서 객체를 선언하고 객체 참조변수에 담는데까지는 이해가 되었습니다.

        근데 왜 갑자기 public object clone()이 나오는지 잘 모르겠습니다.
        clone은 object에 소속된 무슨 메소드인가요?
        복제를 가능하게끔 하는 메소드는 cloneable이라는 클래스이고

        object 타입의 clone() 메소드는 대체 무슨 역할을 하기에 student 클래스에 소속되었는지 도무지 이해가 안 되네요 ㅠㅠ
      • 김승민
        2020-04-28
        감사합니다~
      • 이채
        저도 이 부분이 헷갈려서 찾아봤습니다.
        예전 데이터타입 설명하실때 == 와 equals 언급하시면서 string타입은 equals를 사용하면 담긴 내용을 비교하여 true를 출력한다고 하셨었던 듯 해서요.
        검색해보니 string은 이미 equals메소드를 오버라이딩해서 사용하고 있다고 하네요 ㅎㅎ
        대화보기
        • silver94
          잘 들었습니다!!
        • ChapChap
          다형성, 형변환, overriding에 대해서 다시 한번 설명하고 싶으셔서 그런거 아닐까 생각됩니다.
          Students s 를 받게되면 overloading이겠죠??
          대화보기
          • 허공
            감사합니다!
          • 홍주호
            20190929 완료
          • doevery
            수강완료
          • 이고잉따라잡기
            강의 정주행 후 다시 듣다가 갑자기 궁금한게 생겨서 질문드립니다.
            equals 강의에서 equals메소드에서 Object로 받았는데 아래처럼 Student 객체로 받으면 바로 비교할 수 있는거겠죠?
            다형성 설명을 위해서 object로 받아서 진행하신 건가요??

            public boolean equals(Student s) {
            return this.name == s.name;
            }
          • 라또마니
            다시한번 봐야 할 강의네요~ 감사합니다.
          • Daydream
            잘 봤습니다.
            20181028
          • 안녕하세요. 저는 지나가던 관련전공 학부생 입니다. ㅎㅎ

            protected는 말씀하신것처럼 다른 패키지에서 상속받아서 'overriding 한 경우'에 쓸수있는거라고 생각합니다. overriding을 한다는 개념 자체가 super class의 member을 가지고 온다는 말이거든요. overriding 없이 그냥 바로 가져다쓰는것은 하나의 패키지에서 다른 패키지로의 직접적인 접근, 즉 toString()과 같은 public의 경우에 그렇습니다.

            영상에서 이고잉님께서는 Object를 상속받는 클래스를 만들고, protected된 메소드를 overriding 한 다음, 이를 객체로 만들어서 clone()를 꺼내쓰고 계신거 같아요. 말씀하시는 재정의가 바로 이 overriding이라 생각합니다.

            (private/default는 상속받아 overriding을 하든 말든 다른 패키지에서 사용이 안되는 걸로 알고있습니다.)
            대화보기
            • 오크르돌
              맞네요 하나의 클래스 안에 메인메소드 + ClonEx메소드가 동시에 정의되어있어서 그렇네요
            • 전하연
              감사합니다 2018.8.3120:41
            • 정진홍
              죄송한데 교육자 분께서는 main메소드와 다른 클래스를 인스턴스화 해서 사용한것이고 공동공구님은 지금 메소드 정의를 main메소드가 포함된 class에서 정의를 하셨네요 그러면 당연히 그냥 사용 가능하죠. (clone은 protected이니까 다른 패키지의 상속받은 클래스까지 사용가능하죠,, 지금 main은 그 상속받은 클래스내에 있으니까 당연오버라이딩 안해도 사용 가능합니다)
              대화보기
              • 이태호
                7/17
              • 김진홍
                감사합니다.
              • 김현태
                clone 부터 듣기
              • ㄴㅇㅎ
                오홍 이해가 잘갔어요 감사해요!!
              • 공동공구
                저만 clone 오버라이드 안해도 잘 되는건가요?

                public class CloneEx implements Cloneable{

                String name;
                CloneEx(String name){
                this.name = name;
                }

                public static void main(String[] args) throws CloneNotSupportedException {
                CloneEx ex = new CloneEx("Hi");
                CloneEx ex2 = (CloneEx)ex.clone();
                System.out.println(ex.name);
                }
                }

                이게 문제없이 동작합니다;; clone 오버라이드 안했는데도요.
              • 에스이
                저도 이렇게 생각합니다 정말 왜안되는걸까요?
                대화보기
                • 데이비드리
                  논리적인 과정과 수업에 감사드립니다.
                  다만, 이번 챕터의 항목들을 왜 써야 되는지 기능적 동기?가 없다보니
                  이해하는데 어려움이 느껴지네요.

                  왜 클론,toString 등등 어떨때 필요한지 못느끼니...이해가 어려워요 ㅠ
                • protected에 관해서 질문드립니다.
                  이전 접근 제어자 강의를 확인해보면 protected는 패키지가 달라도 상속된 클래스까지 허용된다고 배웠는데,
                  Clone은 왜 재정의가 되어야 하는지 이해가 잘 가지 않습니다 ㅠㅠ
                  Object class가 기본적으로 부모 클래스로 상속이 되어있는건데 clone함수는 protected형이므로 재정의 없이 사용 가능한게 아닌가요??
                • 자바가즈아
                  equals와 hashCode 비교 궁금해서 찾아보았습니다.
                  equals만으로는 HashMap, HashSet과 같이 key, value쌍의 자료구조 형태로 들어오는 값을 판단 할 수 없습니다.
                  따라서 hashCode를 overriding 함으로써 비교 할 수 있습니다. s1.hashCode()와 s2.hashCode()의 값이 같다.
                • GoldPenguin
                  감사합니다.
                • 도또식
                  이걸 한번에 보고 이해하시는분 정말 대단하네요
                • zugi
                  완료.!
                • is1472
                  object클래스는 모든클래스가 상속하니까 다른클래스입장에서 패키지가달라도 obj의 하위이니 clone을 사용할수 있지않나여
                  또 5분 27에 같은패키지도 맞지만 상속관계이기때문에 호출가능하게 맞지않나요?
                • 정은비
                  equal에서 s1==s2 가 false 인지도 이해가 잘 안되네요 ㅠㅠ 한번 끝내고 반복해야 할것 같아요~~
                • 감사합니다.
                  이해해야하는것과 알아야하는것....감명깊어요 ㅠㅠ
                • J_Project
                  잘봤습니다!!
                • 진격의숑숑
                  감사합니다