[Book Review] JAVA의 신 (12)
[Book Review] JAVA의 신 (12)
CH12. 모든 클래스의 부모클래스 Object
Object
모든 클래스에는 부모 클래스가 있다. (java.lang.object)
package c.inheritance; ㅤ public class InheritanceObject { public static void main(String[] args) throws Exception { inheritanceObject object = new InheritanceObject(); System.out.println(object.toString()); } }
아무런 상속을 받지 않으면 java.lang.Object 클래스 (이하 Object클래스)를 확장함
이 클래스가 어떻게 Object클래스를 확장한다는 것을 알 수 있을까?
-> Object 클래스에 있는 메소드 활용
위 예제에서 toString()이라는 메소드 호출 (main메소드 이외에는 메소드 없는데도) 하지만 클래스를 컴파일하는데 실행에 문제가 없음
그렇다면 만약 extends를 사용하여 부모클래스를 상속받을때에는 어떻게 될까?
자바는 한번에 이중상속을 받을 수 없지만 여러단계로 상속 받을 수 있다. 앞 장에서 예제로 사용한 Parent 클래스의 자식인 Child클래스가 있을 때 Parent클래스는 아무런 상속을 받지 않았지만 실제로는 Object클래스의 상속을 받은 것
(Child 클래스는 Object클래스의 자식의 자식)
왜 모든 클래스는 Object 클래스의 상속을 받는가?
이유 : Object클래스에 있는 메소드들을 통해서 클래스의 기본적인 행동을 정의할 수 있기 때문 /클래스라면 이정도의 메소드는 정의되어있어야하고 처리해야한다라는 것을 정의하는 작업이 필요하기 때문
Object 클래스에서 제공하는 메소드 종류
1)두 가지: 객체 처리 위한 메소드 & 2) 쓰레드를 위한 메소드
쓰레드란?
프로그램이 실행되는 작은 단위 중 하나 (어플리케이션 서버처럼 사용자의 요청들을 동시에 받기 위해선 여러 개의 쓰레드가 동작하여야만 정상적으로 동작할 수 있음)
1) 객체 처리를 위한 메소드
순서 : 접근제어자 / 리턴타입 / 메소드이름(매개변수)
- protected Object clone() : 객체의 복사본을 만들어 리턴
- public boolean equals(Object obj) : 현재 객체와 매개변수로 넘겨받은 객체가 같은지 확인 / 같으면 true 다르면 false
- protected void finalize() : 현재 객체가 더 이상 쓸모가 없어졌을 때 가비지 컬랙터(garbage collector)에 의해서 이 메소드가 호출됨, / 신경쓸필요 없음
- public Class<?> getClass() : 현재 객체의 Class 클래스의 객체를 리턴
- public int hashCode() : 객체에 대한 해시코드(hash code) 값을 리턴 / 해시코드 = 16진수로 제공되는 객체의 메모리주소
- public String toString() : 객체를 문자열로 표현하는 값을 리턴
Garbage Collector
자바의 메모리에 있는 쓰레기 청소 (객체 생성하고 그 객체가 쓰인 후 필요어지면 청소)
2) 쓰레드 처리를 위한 메소드
- public void notify() : 이 객체의 모니터에 대기하고 있는 단일 쓰레드를 깨움
- public void notifyAll() : 이 객체의 모니터에 대기하고 있는 모든 쓰레드를 꺠움
- public void wait() : 다른 쓰레드가 현재 객체에 대한 notify() 메소드나 notifyAll() 메소드를 호출할 때까지 현재 쓰레드가 대기하고 있도록함.
- public void wait(long timeout) : wait() 메소드와 동일한 기능 제공 / 매개변수에 지정한 시간만큼 대기 = 매개변수 시간 넘어섰을 때 현재 쓰레드는 다시 깨어남 / 여기서의 시간은 밀리초 1/1,000초 단위 / 만약 1초간 기다리게 할 경우 1000을 매개변수로 넘겨줌
- public void wait(long timeout, int nanos) : wait() 메소드와 동일한 기능 제공 / 하지만 wait(time out)에서 밀리초 단위의 대기시간을 기다린다면 이 메소드는 자세한 밀리초 + 나ㅗ초 (1/1,000,000,000초) 만큼만 대기 / 뒤에 있는 나노초의 값은 0~999,999 사이의 값만 지정가능
사용 빈도수 높은 순으로 객체 처리 메소드
toString()
equals()
hashCode()
getClass()
clone()
finalize()
1) toString()
가장 많이 사용 / 해당 클래스가 어떤 객체인지 쉽게 나타낼 수 있는 메소드
이 메소드가 자동으로 호출되는 경우
a) System.out.println() 메소드에 매개변수로 들어가는 경우
b) 객체에 대하여 더하기 연산을 하는 경우
package c.inheritance; ㅤ public class ToString { public static void main(String args[]) { ToString thisObject = new ToString(); thisObject.toStringMethod(thisObject); } ㅤ public void toStringMethod(Object obj) { System.out.println(obj) System.out.println(obj.toString()); System.out.println(“plus „+obj); } }
- toStringMethod() 메소드의 가장 첫줄 = 객체 그대로 출력
- toStringMethod() 메소드의 두번째 줄 = toString이 클래스에 선언되어있지 않지만 ToString클래스가 Object 클래스에 상속되어있기 떄문에 toString()메소드 호출 가능
- toStringMethod() 메소드의 마지막줄 = 객체의 더하기 연산 수행 (참조 자료형 더하기 연산은 String만 가능하다고 했는데? -> String을 제외한 참조자료형에 더하기연산하면 자동으로 toString()메소드 호출되어 객체의 위치에는 String값 놓임
toStringMethod() 좀 더 깔끔하게
public void toStringMethod() { System.out.println(this); System.out.println(toString()); System.out.println(„plus“ + this); }
이렇게 toString()으로 출력된 결과는 무엇인가?
실제 Object클래스에 구현되어있는 toString() 메소드
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
- Object 클래스에있는 getClass()의 결과에 getName() 메소드를 부르면 현재 클래스의 패키지 이름과 클래스 이름이 나옴
- 여기서는 c.inheritance.InheritanceObject가 여기에 속함
- 그 다음에 at(@)가 붙는다. 그냥 앞의 결과 뒷 결과 구분
- 마지막 부분에 객체의 해시코드값을 출력 / Object 클래스에 선언되어있는 hashCode() 나중에 / hashCode() 메소드에서 int 타입의 값을 리턴 / 그 값을 클래스에서 제공하는 toHexString()이라는 메소드를 활용하여 16진수로 변환
(Integer클래스 : int값을 보다 쉽게 처리할 수 있도록 도움주는 클래스)
클래스 이름 & 해시 코드 값 알필요 ?
클래스 만들 떄 toString() 메소드는 직접 구현해야한다 (= Overriding을 적용해야한다)
*Overriding 제대로 구현하기 위해서 : 접근 제어자 / 리턴 타입 / 메소드 이름 / 매개변수타입과 개수 = 모두 동일해야함
ToString클래스의 toString() 메소드를 다음과 같이 Overriding
package c.inheritance; ㅤ public class ToString { public static void main(String args[]) { ToString thisObject = new ToString(); thisObject.toStringMethod(thisObject); } ㅤ public void toStringMethod() { System.out.println(this); System.out.println(toString()); System.out.println(„plus“ + this); } ㅤ public String toString() { return “ToString class”; } }
이 toString()메소드의 선언부를 보면 접근 제어자는 public이고 리턴 타입은 String인 것을 알 수 있다. 이렇게 toString() 메소드를 변경한 후 ToString 클래스를 컴파일하고 다시실행
-> 결과
ToString class ToString class plus ToString class
패키지를 포함한 클래스이름과 골뱅이 / hashCode()메소드 수행결과 나오지 않음
마찬가지로 MemberDTO에서도
toString() 없다면
MemberDTO dto = new MemberDTO(“sangmin”, “01011111111”, [email protected]); System.out.println(“Name=“+dto.name+“ Phone =”+dto.phone+” eMail=”+dto.email);
toString() 추가
public class MemberDTO { // 중간생략 public String toString() { return “Name=”+name+” Phone=”+ phone+” eMail=”+email; } }
이렇게 toString()을 Overriding해놓으면 다음과 같이 간단하게 사용가능
MemberDTO dto = new MemberDTO(“sangmin”, “01011111111”, [email protected]); System.out.println(dto);
이클립스에서는 파일을 저장하면 바로 컴파일 완료 / 버튼 하나 누르면 실행
or Intelli J (인텔리 제이) 유.무료 / 안드로이드 개발에 사용되는 안드로이드 스튜디오(인텔리 제이 기반)
ㅤ
ㅤ
ㅤ
2) equals()
객체는 ==만으로 같은지 확인이 안되기 때문에 equals() 사용
비교 연산자 (==, !=)들은 주소값을 비교한다
package c.inheritance; ㅤ public class MemberDTO { public String name; public String phone; public String email; // 이하 생략 }
Equals패키지
package c.inheritance; ㅤ public class Equals { public static void main(String args[]) { Equals thisObject = new Equals(); thisObject.equalMethod(); } public void equalMethod() { memberDTO obj1 = new MemberDTO(“sangmin”); memberDTO obj2 = new MemberDTO(“sangmin”)’ if (obj1 == obj2) { System.out.println(“obj1 and obj2 is same”); } else System.out.println(“obj1 and obj2 is different”); } } }
- obj1 obj2 주솟값다름
속성값 (name “sangmin”, phone = email = null) 은 동일
그래서 equals()라는 메소드를 통해 두 객체 비교
Overriding하지 않으면 equals()메소드에서는 hashCode()값을 비교
equals Overriding하면
public class MemberDTO { public boolean equals(Object obj) { if (this == obj) return true; // 주소값 같으므로 true if (obj == null) return false; // obj가 null이므로 false if (getClass() != obj.getClass()) return false; // 클래스의 종류가 다르므로 false ㅤ MemberDTO other = (MemberDTO) obj; // 같은 클래스이므로 형변환 실행 ㅤ ---각 인스턴스 변수가 같은지 비교--- ㅤ if (name == null) { // name이 null일 때 if (other.name != null) return false; // 비교대상의 name이 null이 아니면 false } else if (!name.equals(other.name)) return false; // 두 개의 email값 다르면 false ㅤ if (email == null) { if (other.name != null) return false; } else if (!email.equals(other.email)) return false; ㅤ if (phone == null) { if (other.phone != null) return false; } else if (!name.equals(other.phone)) return false; return true; } }
이클립스에서 자동으로 생성한 equals() 메소드
equals() 메소드를 Overriding 할 때에는 반드시 다섯 조건 만족 (from API)
(1) 재귀(reflexive) : null이 아닌 x라는 객체의 x.equals(x)결과는 항상 true
(2) 대칭(symmetric) : null이 아닌 x와 y객체가 있을 때 y.equals(x)가 true를 리턴했다면, x.equals(y)도 반드시 true를 리턴
(3) 타동적(transitive) : null이 아닌 x,y,z가 있을 때 x.equals(y)가 true를 리턴하고 y.equals(z)가 true를 리턴하면 x.equals(z)는 반드시 true를 리턴
(4) 일관(consistent) : null이 아닌 x와 y가 있을 떄 객첵가 변경되지 않은 상황에서 몇 번 더 호출하더라도 x.equals(y)의 결과는 항상 true이거나 항상 false이어야한다.
(5) null과의 비교 : null이 아닌 x라는 객체의 x.equals(null)결과는 항상 false여야만한다.
- 주의 : equals()메소드를 Overriding할 땐 hashcode()메소드도 같이 Overriding해야함
- 이유: equals()메소드를 Overriding해서 객체가 서로 같다고 이야기할 수 있겠지만, 그 값이 같다고 해서 그 객체의 주소값이 같지는 않음
= equals()메소드의 결과가 true임에도 hascode()메소드의 값은 다르기 때문
public class MemberDTO { // 생략 ㅤ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((email == null) ? 0 : email.hashcode()); result = prime * result + ((name == null) ? 0 : email.hashcode()); result = prime * result + ((phone == null) ? 0 : email.hashcode()); return result; } }
ㅤ
ㅤ
ㅤ
3) hashcode()
기본적으로 객체의 메모리 주소를 16진수로 리턴
만약 어떤 두 개의 객체가 서로 동일하다면 hashcode() 값은 무조건 동일해야함
따라서 equals() 메소드를 override하면, hashCode()메소드도 override해서 동일한 결과가 나오도록 해야함
hashcode Overriding 조건 (from API)
(1) 자바 어플리케이션이 수행되는 동안에 어떤 객체에 대해서 이 메소드가 호출될 땐 항상 동일한 int값 리턴 (하지만 자바 실행할때마다 같은 값이어야할 필요 X)
(2) 어떤 두개의 객체에 대하여 equals()메소드를 사용하여 비교한 결과가 true일 경우 두 객체의 hashCode()메소드를 호출하면 동일한 int값 리턴해야함
(3) 두 객체를 equals()메소드를 사용하여 비교한 결과false 리턴했다고 hashCode()메소드를 호출한 int값이 무조건 달라야할 필요 X ( 이 경우 서로 다른 int값 제공하면 hashtable 성능 향상에 도움)
직접 equals() hashCode() 메소드 작성 권장 X
Author And Source
이 문제에 관하여([Book Review] JAVA의 신 (12)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@anthony16/Book-Review-JAVA의-신-8저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)