JAVA_Object클래스

호근·2022년 12월 14일
0

java

목록 보기
31/35

Object클래스

object클래스는 모든 클래스의 조상클래스이다.
덕분에 모든 클래스에서 바로 사용가능하다.

Object 클래스의 메서드

protected Object clone() // 객체 자신의 복사본을 return
public boolean equals(Object obj) // 객체 자신과 객체 obj가 같은 객체인지 비교한다. 같으면 true
protected void finalize() // 객체가 소멸될 때 가비지 컬렉터에 의해 자동호출된다. 이 때 수행되어야 하는 코드가 있을 때 오버라이딩한다. (거의 안씀)
public Class getClass() // 객체 자신의 클래스 정보를 담고있는 Class인스턴스를 return
public int hashCode() // 객체 자신의 해시코드를 return
public String toString // 객체 자신의 정보를 문자열로 return

public void notify() // 객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨움
public void notifyAll() // 다깨움

public void wait() // 다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 무한히 or 지정된 시간(time, nanos)동안 기다리게 한다.
public void wait(longtime) // "
public void wait(longtime, nanos) // "

Object클래스는 위 11개의 메서드만 가지고 있다.

이 중 가장 많이 쓰이는 메서드를 정리하려한다.

equals(Object obj)

public class Obj_Equals {

	public static void main(String[] args) {
		Person p1 = new Person(1414124123123L);
		Person p2 = new Person(1414124123123L);
	
		if(p1 == p2) { // 두 인스턴스가 바라보는 참조변수가 서로 다르다.
			System.out.println("p1 과 p2는 같은 사람입니다.");
		} else {
			System.out.println("p1 과 p2는 다른 사람입니다.");
		}
		
		if(p1.equals(p2)) { // 같은 참조변수를 바라보고있다. equsls() 는 오버라이딩되어 두 인스턴스의 타입을 비교한 뒤 true 이면 id와 매개변수의 id를 비교한다.
			System.out.println("p1 과 p2는 같은 사람입니다.");
		} else {
			System.out.println("p1 과 p2는 다른 사람입니다.");
		}
		
		
	}

}

class Person{
	long id; // 

	// equals 메서드 오버라이딩, 재정의 하였다.
	public boolean equals(Object obj) {
		if(obj != null && obj instanceof Person) { // obj가 null 이외의 값을 가지면서, Person 타입일 때.
			return id == ((Person)obj).id; // true, this.id와 Person타입으로 long타입으로 형변환된 매개변수obj.id를 비교한다.
		} else {
			return false; 
		}
	}

	public Person(long id) { // long타입의 id를 매개변수로 갖는 Person 메서드
		this.id = id; // 매개변수를 this.id에 초기화한다.
	}
	
	
}

여기서 눈여겨볼것은
비교대상간의 비교 전에 타입을 일치시켜줘야한다는 것.


hashCode()

equals()와 유사하게 객체의 변수값을 비교해야한다면,
hashCode()도 오버라이딩 해야하는데

일반적으로는 해시코드가 같은 두객체가 존재하는 것이 가능하다.
하지만 Object클래스의 hashCode() 메서드에서는 객체의 주소값을 이용해 해시코드를 반환하기 때문에 서로 다른 객체는 같은 해시코드를 가질 수 없다.

때문에 적절히 오버라이딩 해야한다.

오버라이딩을 안하면?
원래 Object클래스에 정의된대로 모든 해시코드가 각기 다른 값을 가지게 된다.

public class Obj_HashCode {

	public static void main(String[] args) {

		String str1 = new String("ABC");
		String str2 = new String("ABC");
	
		System.out.println(str1.equals(str2));
		System.out.println(str1.hashCode()); // override가 가능한 Object의 hashCode
		System.out.println(str2.hashCode()); // str1과 str2는 같은 객체를 참조한 같은 문자열을 가진다, hashCode의 값이 같다.
		
		System.out.println(System.identityHashCode(str1)); // 고유한 hashCode를 return
		System.out.println(System.identityHashCode(str2)); // 출력해보면 str1과str2는 상이함.

		// 어쨋거나 실무에서 원하는 것은 두 인스턴스를 오차없이 비교하는 것이다.
		// String클래스를 상속받는 hashCode()는 문자열이 같으면 동일한 해시코드를 반환
		// identityHashCode는 객체의 주소값으로 해시를 생성
	
	
	
	}

}

toString()

이 메서드는 인스턴스에 대한 정보를 문자열로 반환한다.

toString은 항상 오버라이딩 되어야한다.

Object클래스에 정의된 toString은 아래와 같다.

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

만약 오버라이딩하지 않고 그대로 가져다 사용하면,
16진수의 해시코드를 마주하게된다.

	public static void main(String[] args) {

		
		String country = new String("Korea");
		java.util.Date today = new java.util.Date();
		
		System.out.println(country); // korea 
		System.out.println(country.toString()); // korea 
		System.out.println(today); // today
		System.out.println(today.toString()); // today
		
	}

String 클래스의 toString()은 인스턴스가 갖고있는 문자열을 return하도록 overriding되어있다.

Date 클래스의 경우 Date인스턴스가 갖고있는 날짜와 시간을 문자열로 return하도록 overriding되어있다.

toString()은 인스턴스나 클래스에 대한 정보, 인스턴스변수의 값을 문자열로 변환하여 return하도록 overriding하는것이 일반적이다.

public class Card {
	String kind;
	int number;
	
	 Card() {
		 this("Spade",1); 
	}
	
	public Card(String kind, int number) {
		this.kind = kind;
		this.number = number;
	}
	@Override
	public String toString() {
		return "Card [kind=" + kind + ", number=" + number + "]";
	}
}

class CardToString {
	public static void main(String[] args) {
		Card c1 = new Card();
		Card c2 = new Card("Heart",10);
		
		System.out.println(c1);
		System.out.println(c2);
		
	}
}

Card클래스의 toString을 오버라이딩했다.


clone()

자신을 복제하여 새로운 인스턴스를 생성하는 메서드이다.

원형을 보존하고 새로운 클론을 생성하여 변경 전의 값을 참고하는데 도움을 준다.

단, 인스턴스 변수의 값만을 복제하기에 참조타입의 인스턴스 변수가 있다면 완벽히 복제되지 않는다.


import java.awt.Point;

// cloneable 인터페이스 구현
public class Obj_clone implements Cloneable{ // 클론 구현시 Cloneable을 반드시 implements 구현해줘야한다. 안해주면 예외발생한다.

	int x, y;

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

	

	@Override
	public String toString() {
		return "Obj_clone [x=" + x + ", y=" + y + "]";
	}

	public Object clone() { // 접근제한자를 protected에서 public 으로 변경.
		Object obj = null;
		try {
			obj = super.clone();  // 조상클래스의 클론 호출
		} catch (CloneNotSupportedException e) {}// clone은 반드시 예외처리해주어야한다.
		return obj;
	}
}

class CloneEX1{
	public static void main(String[] args) {
		Point original = new Point(2, 6);
		Point copy = (Point)original.clone();
		System.out.println(original);
		System.out.println(copy);
	}

}

주의할 것.

  • cloneable 인터페이스 구현
  • clone() 오버라이딩 할 때 접근제한자는 public
  • 반드시 예외처리할 것.(CloneNotSupportedException)

얕은복사와 깊은복사 이슈

clone은 단순히 객체에 담긴 값만을 복사하기 때문에
객체 배열을 복제하는 경우에는 원본과 복제본이 같은 값을 공유하므로,
완전한 복사라고 보기어렵다.

이를 얕은복사라고한다.

반면,
원본이 참조하고 있는 객체까지 복사하는 것을 깊은복사라고 칭한다.
깊은복사에서는 원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 값변경이 복사본에 영향을 주지 않는다.

매우 중요하다.


getClass

getClass는 자신이 속한 클래스의 Class객체를 반환한다.

Class 객체를 얻는 방법

  • 생성된 객체로부터 얻는 방법
  • 클래스 리터럴로부터 얻는 방법
  • 클래스 이름으로부터 얻는 방법
Class Iobj = new Card().getClass(); // 생성된 객체로부터 얻기
Class Oobj = Card.class; // 리터럴로 얻기
Class Kobj = Class.forName("card"); // 클래스 이름으로 얻기

일어나서 String Class 공부하기

profile
22.11.28 ~

0개의 댓글