- Object 클래스
- 자바의 모든 클래스는 Object 클래스를 상속받음
- 자바의 최상위 클래스
- 컴파일러는 아무런 클래스로 상속하지 않으면 자동으로 extends Object를 삽입해 Object 클래스를 상속
class A {
//class A extends Object
//상속을 하지 않을때 extends Object 자동으로 추가
}
class B extends A {
}
- Object <- A <- B 의 관계
- 자바의 모든 클래스는 어떤 객체로 만들든지 Object타입으로 선언 가능
Object oa = new A();
Object ob = new B();
- System.out.println(Object X)
-기본 자료형 이외에 Object를 입력매개변수로 하는 println()메서드를 오버로딩
- 사용자가 어떤 클래스 타입의 객체를 생성하더라도 다형성에 따라 Object타입이라고 불릴 수 있으므로
입력 매개변수로 모든 타입의 객체 받아들일 수 있음
1. Object 클래스의 주요 메서드
- 자바의 모든 클래스가 Object 클래스의 메서드를 포함
1) toString() - 객체 정보를 문자열로 출력
- 객체 정보 : '패키지명.클래스명@해시코드'
- 해시코드 : 객체가 저장된 위치와 관련된 값
- 실제 객체의 정보를 표현하고자 할 때는 대부분 클래스명이나 숫자로 나열된 해시코드보다는
객체에 포함돼 있는 필드값 출력
- 자식 클래스에서는 toString() 메서드를 오버라이딩해 사용
class A {
int a = 3;
int b = 4;
}
A aa = new A();
System.out.print("%x\n", aa.hashcode()); //70dea4e3
System.out.println(aa); //aa.toString()이 자동으로 실행
//패키지.클래스명@해시코드
- A 객체를 생성한 후 hashCode() 메서드의 리턴값을 16진수로 출력하면 aa 객체의 위칫값과 관련된 고유값 출력
- println() 메서드는 객체를 출력하면 자동으로 객체 내의 toString() 메서드를 호출
System.out.println(aa) == System.out.println(aa.toString())
class B { //toString overriding
int a = 3;
int b = 4;
@override
public String toString(0 {
return "필드값 : a" + a + "b:" +b;
}
}
- toString()의 출력 결과인 '패키지명.클래스명@해시코드'는 객체의 직관적인 정보를 제공하지 못함
- 자식 클래스에서 toString() 메서드를 오버라이딩해 사용하는것이 일반적
B bb = new B();
System.out.println(bb); // bb.toString()이 자동으로 실행
// 필드값 : a =3, b = 4
- 클래스 B에서 오버라이딩한 toString메서드에서는 자신의 필드 2개의 값을 출력하는 문자열을 리턴
package ObjectMethod_toString;
class A { //extends Object(컴파일러에 따라 자동으로 추가)
int a=3;
int b=4;
}
class B {
int a=3;
int b=4;
public String toString() {
return "필드값(a,b) =" +a +" "+b;
}
}
public class OB_toString {
public static void main(String[] args) {
//객체 생성
A a = new A();
B b = new B();
//메서드 호출
System.out.printf("%x\n", a.hashCode()); //hashcode를 16진수로 표현
System.out.println(a.toString());
System.out.println(b);
}
}
2) equals(Object obj) - 스택 메모리값 비교
- 입력매개변수로 넘어온 객체와 자기 객체의 스택 메모리 변숫값을 비교해 그 결과를 true / false로 리턴하는 메서드
- 객체의 스택메모리값 비교
- 실제 데이터값이 아닌 실제 데이터의 위치(번지)를 비교
- 등가 비교 연산(==)과 완벽하게 동일한 기능 수행
class A {
String name;
A(String name) {
this.name = name;
}
}
- 필드 name 생성자를 이용해 초기화
A aa1 = new A("안녕");
A aa2 = new A("안녕");
System.out.println(aa1 == aa2); //false
System.out.println(aa1.equals(aa2)); //false
- 객체 내부의 값은 동일하지만, 실제 객체는 다른 곳에 위치하므로 위칫값을 나타내는 스택 메모리값은 서로 다름
class B { //equals() 메서드 overriding
String name;
B(String name) {
this.name = name;
}
@Overriding
public boolean equals(Object obj) {
if(obj instance of B) {
if(this.name ==((B) obj).name)
return true;
}
return false;
}
}
- 실제 내용을 비교하고자 할 때는 equals()메서드를 오버라이딩해 사용
- equals()메서드를 오버라이딩
- 메서드 내부에서는 자신의 name값과 입력받은 객체의 name 값을 비교해 동일하면 ture, 동일하지 않으면 false
- 자신의 객체 타입을 일치시키기 위해 캐스팅을 할 수 있는지를 확인하는 instanceof 키워드와 다운캐스팅을 사용
B bb1 = new B("안녕");
B bb2 = new B("안녕");
System.out.println(bb1 == bb2); //false
System.out.println(bb1.equals(bb2)); //true
3) hashCode() - 객체의 위치와 연관된값
- 객체의 위치와 관련된 값, 실제 위치를 나타내는 값은 아님
- 객체의 위칫값을 기준으로 생성된 고윳값
- 두 객체의 내용을 비교하기 위해서는 equals() 메서드를 오버라이딩하는 것으로 충분
- Hash 형태의 자료구조에서는 동등 비교를 위해 hashCode() 결과값을 비교하므로
equals() 메서드 오버라이딩 + hashcode() 오버라이딩
- HashMap 자료구조에서는 데이터를 (key, value)의 쌍으로 저장하며, key 값은 중복되지 않음
- 추가하고자 하는 데이터셋의 key가 기존의 key들과 동일한지를 확인하는 과정 필요
- HashMap에서의 두 객체 동일 조건
1. 두 객체의 hashcode()값 비교
2. 두 객체의 hashcode()값이 동일할때 equals() 메서드를 호출
3. equals() 메서드를 호출하면, 이 값이 true이면 같은 객체로 인식
step 1. key1.hashCode() == key2.hashCode()
- 두 key의 hashCode()값이 동일한지를 확인
step 2. key1.equals(key2) == true
- equals() 메서드를 이용해 동일 여부를 확인
- step1, step2둘다 만족하면 같은 key 객체로 인식하므로 해당 데이터셋은 기존 데이터셋을 덮어씀
- step1, step2 둘 중 하나라도 만족하지 않으면 다른 객체로 인식하므로 새로운 데이터셋으로 추가
class A {
String name;
A(String name) {
this.name = name;
}
@override
public boolean equals(Object obj) {
if(obj instanceof A) {
if(this.name == ((A)obj.name)
return ture;
}
return false;
}
@override
public String toString() {
return name;
}
}
- 클래스 A
- equals() 메서드만 오버라이딩
- 비교대상의 객체와 name 필드값이 동일하면 true를 리턴
class B {
String name;
A(String name) {
this.name = name;
}
@override
public boolean equals(Object obj) {
if(obj instanceof A) {
if(this.name == ((A)obj.name)
return ture;
}
return false;
}
@override
public int hashCode() {
return name.hashcode();
}
@override
public String toString() {
return name;
}
}
- 클래스 B
- equals() 메서드 + hashCode() 메서드
- String 클래스 내부의 hashCode() 메서드는 문자열마다 고유의 해시코드를 만들어 리턴해 주는 메서드
- 문자열이 동일하면, 동일한 해시코드 리턴
HashMap<Integer, String> hm1 = new HashMap<>();
hm1.put(1,"데이터1");
hm1.put(2,"데이터2");
hm1.put(3,"데이터3");
System.out.println(hm1); // {1=데이터2, 2= 데이터3}
- 동일한 2개의 Key값이 중복돼 들어감
- 최종적으로 저장된 데이터셋은 2개
- key=1일때의 Value값은 나중에 들어간 "데이터2"
HashMap<A,String> hm2 = new HashMap<>();
hm2.put(new A("첫번째"), "데이터1");
hm2.put(new A("첫번째"), "데이터2");
hm2.put(new A("두번째"), "데이터3");
System.out.println(hm2); // {첫번째= 데이터1, 두번째=데이터2, 세번째=데이터3}
- 클래스 A는 hashcode()를 오버라이딩 하지 않음
- 클래스 A 내부에서 사용할 수 있는 hashcode()는 Object의 hashCode()
- object의 hashcode()는 객체의 위치에 따라 생성한 고윳값을 리턴
- 두 객체가 서로 다른 위치에 생성 -> 두 객체의 hashcode()값도 서로 다름
HashMap<B,String> hm3 = new HashMap<>();
hm3.put(new B("첫번째"),"데이터1");
hm3.put(new B("두번째"),"데이터2");
hm3.put(new B("세번째"),"데이터3");
System.out.println(hm3); // {첫번째=데이터2, 두번째=데이터3}
- 클래스 B는 hashCode() 오버라이딩
- name.hashCode()를 사용해 문자열에 따라 해시코드값을 리턴
- 두 객체의 name 값이 같으므로 두 값의 hashCode()값도 같을 것임
- equals()도 true 리턴
'Java > 문법' 카테고리의 다른 글
16 -1장 제네릭 클래스와 제네릭 인터페이스 (0) | 2023.06.15 |
---|---|
15 - 5장 쓰레드의 상태 (0) | 2023.06.15 |
10 - 5장 super 키워드와 super() 메서드 (0) | 2023.06.01 |
10-4장 인스턴스 필드와 정적 멤버의 중복 (0) | 2023.06.01 |
10-3장 메서드 오버라이딩 (0) | 2023.05.04 |