티스토리 뷰
728x90
반응형
Object 클래스란
- java.lang.Object 클래스는 모든 클래스의 최상위 클래스로 모든 클래스는 Object 클래스를 상속받습니다.
- 따라서 모든 클래스는 Object 클래스의 메서드를 사용할 수 있고 일부 메서드를 재정의하여 사용할 수 있습니다.
- 다만 final 메서드는 재정의할 수 없습니다.
- java.lang.Object 패키지는 컴파일러에 의해 자동으로 import됩니다.
- Object 클래스는 필드는 없고 메서드로 구성되어 있습니다.
equals()
- 객체 간의 동일성을 비교하고 싶은 경우 == 을 사용하지 않고 equals() 메서드를 사용해야 합니다.
- equals()메서드를 구현해야한다면 hashCode() 메서드도 함께 구현해야 합니다.
- equals() 메서드의 경우 기본적으로 Object 클래스가 가진 equals() 메서드를 그대로 사용하는것을 권장합니다.
- Primitive Type(원시 타입)을 비교하는 경우는 비교 연산자(==)을 사용하고 객체를 비교하는 경우는 equals() 메서드를 사용하면 됩니다.
💡 equals()메서드를 재정의하기 위한 5가지 조건
- 재귀 : null이 아닌 x라는 객체의 x.equals(x)는 항상 true여야 합니다.
- 대칭 : null이 아닌 x와 y 객체가 있을 때 y.equals(x)가 true를 리턴했다면 x.equals(y)도 반드시 true를 리턴해야합니다.
- 타동적 : null아 아닌 x, y, z가 있을 때 x.equals(y)가 true를 리턴하고, y.equals(z)가 true를 리턴한다면 x.equals(z)는 반드시 true를 리턴해야합니다.
- 일관 : null아닌 x와 y가 있을 때 객체가 변경되지 않는 상황에서는 몇 번을 호출하더라도 x.equals(y)의 결과는 항상 true이거나 false여야 합니다.
- null과의 비교 : null이 아닌 x라는 객체의 x.equals(null) 결과는 항상 false여야 합니다.
equals()메서드를 재정의하지 않은 경우
- 아래의 예제를 실행하면 false가 반환이 됩니다. 그 이유는 equals() 메서드의 기본 동작은 == 연산이기 때문에 false가 반환됩니다. 이 경우 equals() 메서드를 재정의하여 동일성을 갖추도록할 수 있습니다.
public class Member {
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
public static void main(String[] args) {
Member member1 = new Member("홍길동", 123);
Member member2 = new Member("홍길동", 123);
System.out.println(member1.equals(member2)); // false
}
}
equals()메서드를 재정의한 경우
- equals() 메서드를 재정의하여 주민번호가 같으면 같은 객체로 판별합니다.
- equals() 메서드의 반환값이 true이면 두 객체가 같다는 의미인데 그렇다면 해시코드값도 같아야합니다. 하지만 아래의 예제의 해시코드를 출력하면 각각 다른 값이 출력되는데 이 이유는 hashCode() 메서드를 재정의 하지 않아서입니다.
public class Member {
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member){
return this.registrationNumber == ((Member) obj).registrationNumber;
}
return false;
}
public static void main(String[] args) {
Member member1 = new Member("홍길동", 123);
Member member2 = new Member("홍길동", 123);
System.out.println(member1.equals(member2)); // true
System.out.println(member1.hashCode()); // 234698513
System.out.println(member2.hashCode()); // 1121172875
}
}
hashCode()
- 해시코드란 객체를 식별할 하나의 정수값입니다.
- Object 클래스의 hashCode()메서드는 객체의 메모리 번지를 이용하여 해시코드를 만들어서 반환합니다. 따라서 각 객체마다 다른 해시코드 값을 가지고 있습니다.
- 해시코드 값이 다르면 다른 객체로 판단하고 값이 같으면 equals() 메서드를 사용하여 다시 검사합니다. 해시코드 값이 같아도 equals() 메서드로 판별하여 true가 아니면 다른 객체가 됩니다.
💡 hashCode() 메서드를 재정의하기 위한 조건
- 자바 애플리케이션이 수행되는 동안에 어떤 객체에 대해서 이 메서드가 호출될 때에는 항상 동일한 int값을 리턴해줘야 합니다. 하지만 자바를 실행할 때마다 같은 값이어야 할 필요는 없습니다.
- 어떤 두개의 객체에 대하여 equals() 메서드를 사용하요 비교한 결과가 true일 경우에 두 객체의 hashCode() 메서드를 호출하면 동일한 int값을 반환해야합니다.
- 두 객체를 equals() 메서드를 사용해 비교한 결과 false를 리턴했다고 해서 hashCode() 메서드를 호출한 int 값이 무조건 달라야 할 필요는 없습니다. 하지만 이 경우에 서로 다른 int 값을 제공하면 hashtable의 성능을 향상시키는데 도움이 됩니다.
hashCode()를 재정의하지 않은 경우
- 아래 예제는 equals() 메서드를 재정의하여 주민등록번호가 같으면 같은 객체이지만 해시코드 값이 다른것을 확인할 수 있습니다. 그 이유는 hashCode() 메서드를 재정의하지 않아서 그렇습니다.
public class Member {
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member){
return this.registrationNumber == ((Member) obj).registrationNumber;
}
return false;
}
public static void main(String[] args) {
Member member1 = new Member("홍길동", 123);
Member member2 = new Member("홍길동", 123);
System.out.println(member1.equals(member2)); // true
System.out.println(member1.hashCode()); // 234698513
System.out.println(member2.hashCode()); // 1121172875
}
}
hashCode()를 재정의한 경우
- 아래 예제는 hashCode() 메서드를 재정의하여 주민등록번호가 같으면 같은 해시코드를 반환합니다.
public class Member {
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member){
return this.registrationNumber == ((Member) obj).registrationNumber;
}
return false;
}
@Override
public int hashCode() {
return this.registrationNumber;
}
public static void main(String[] args) {
Member member1 = new Member("홍길동", 123);
Member member2 = new Member("홍길동", 123);
System.out.println(member1.equals(member2)); // true
System.out.println(member1.hashCode()); // 123
System.out.println(member2.hashCode()); // 123
}
}
toString()
- toString() 메서드는 객체의 문자 정보를 반환합니다.
- 객체의 문자 정보라함은 객체를 문자열로 표현한 값인데 기본적으로 클래스명@16진수해시코드로 구성된 문자정보입니다.
Object obj = new Object();
System.out.println(obj.toString()); // java.lang.Object@de6ced
toString() 재정의한 경우
public class Member {
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
@Override
public String toString() {
return "이름 : " + this.name + ", 주민번호 : " + this.registrationNumber;
}
public static void main(String[] args) {
Member member = new Member("홍길동", 123);
System.out.println(member.toString()); // 이름 : 홍길동, 주민번호 : 123
}
}
clone()
- 객체 복제는 원본 객체의 필드값과 동일한 값을 가지는 새로운 객체를 생성하는 것입니다.
- 어떠한 객체를 복제할려면 이 객체가 복사 가능한 객체라는 사실을 JVM에게 알려줘야하는데 이때 Cloneable이라는 인터페이스를 구현하면 됩니다.
- Cloneable인터페이스는 객체가 복제 가능한 객체라는 사실을 JVM에게 알려주는 구분자에 불과합니다. 즉 Cloneable은 일종의 약속입니다.
- 객체지향 프로그래밍의 정보은닉에 위배될 가능성이 있으므로 복제할 객체는 Cloneable인터페이스를 명시해야합니다.
clone() 재정의한 경우
- Cloneable 인터페이스를 implements해도 구현해야할 메서드는 없습니다. 이런 인터페이스를 마크 인터페이스라고 합니다.
- 복제된 객체는 Object로 반환되므로 명시적인 캐스팅이 필요합니다.
- 메모리가 복제되면서 CloneNotSupportedException이 발생할 수 있으므로 예외처리를 해주어야 합니다.
public class Member implements Cloneable{
String name;
int registrationNumber; // 주민번호
public Member(String name, int registrationNumber) {
this.name = name;
this.registrationNumber = registrationNumber;
}
@Override
public String toString() {
return "이름 : " + this.name + ", 주민번호 : " + this.registrationNumber;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Member member1 = new Member("홍길동", 123);
Member member2 = (Member)member1.clone();
System.out.println(member1.toString()); // 이름 : 홍길동, 주민번호 : 123
System.out.println(member2.toString()); // 이름 : 홍길동, 주민번호 : 123
}
}
finalize()
- 객체 소멸자(finalize())는 자바에서 참조하지 않는 배열이나 객체를 가바지 컬렉터가 힙영역에서 자동으로 소멸시킵니다.
- GC는 객체를 소멸하기 직전에 마지막으로 객체의 소멸자를 실행시킵니다.
- 많은 자바 전문가들이 이 메서드 사용을 여러가지 이유로 만류하고 있기 때문에 직정 구현하는 일은 상당히 적어보입니다.
- 언제 실행될지 알수가 없으므로 실행을 보장하지 않습니다.
- 성능을 저하시킵니다.
- 예외 발생 시 무시가 됩니다. 보통 예외가 발생하면 stack trace가 출력되지만 finalize 내에선 무시되고 처리됩니다.
728x90
반응형
'JAVA > JAVA기본' 카테고리의 다른 글
JAVA - 예외 처리(try, catch, throw, throws, finally) (0) | 2022.01.26 |
---|---|
JAVA - 인터페이스란? (0) | 2022.01.26 |
JAVA - 추상 클래스란? (2) | 2022.01.16 |
JAVA - 다이나믹 메소드 디스패치란? (0) | 2022.01.11 |
JAVA - 상속이란?(feat.extends, super) (0) | 2022.01.11 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- service based architecture
- 레이어드 아키텍처란
- polling publisher spring boot
- redis sorted set으로 대기열 구현
- transactional outbox pattern spring boot
- @ControllerAdvice
- 공간 기반 아키텍처
- 람다 표현식
- redis sorted set
- redis 대기열 구현
- spring boot excel download oom
- java userThread와 DaemonThread
- spring boot redisson destributed lock
- 자바 백엔드 개발자 추천 도서
- spring boot 엑셀 다운로드
- spring boot excel download paging
- pipeline architecture
- JDK Dynamic Proxy와 CGLIB의 차이
- spring boot poi excel download
- transactional outbox pattern
- space based architecture
- 서비스 기반 아키텍처
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- microkernel architecture
- 트랜잭셔널 아웃박스 패턴 스프링부트
- spring boot redisson 분산락 구현
- pipe and filter architecture
- java ThreadLocal
- spring boot redisson sorted set
- spring boot redis 대기열 구현
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함