toString 메서드는 객체 자체의 정보를 알려주는 역할을 하는 메서드로
최상위 클래스인 Object에 선언되어 있다.
Object에 선언된 기능은 해당 객체의 클래스 이름과 16진수로 변환한 해시코드가 출력이 된다.
실제로 사용하기엔 그닥 유용한 정보라고 할 수 없다.
값을 가진 클래스에서는 별도의 toString을 Overriding 하여 자기가 가진 값이 리턴되도록 재정의 해줘야 사용하기 편하다.
Object 클래스의 toString 메서드는
클래스_이름@16진수로_표시한_해시코드
를 반환한다.
String에서 this를 반환하는데 어떻게 문자열 그대로 출력이 되는지 의문.. 본인의 객체가 리턴되는 거면 참조하고 있는 해시코드값이 나와야 하는게 아닐지 왜 이미 자기자신이 문자열인지 모르겠다. this.value도 아니고 내부적인 필드에 coder, serialVersionUID도 있는데 어떻게 문자열이 나오는걸까?
public static void main(String[] args) {
String hello = "hello";
// 내부적으로 toString을 호출하고 있다.
System.out.println(hello); // hello
System.out.println(hello.toString()); // hello
}
println, printf, 문자열 연결 연산자(+), assert 구문에 넘길 때 혹은 디비거가 객체를 출력할 때 컴파일러가 내부적으로 toString메서드를 호출하고 있다. toString메서드 사용이 명시적으로 보이지 않아도 어디선가 쓰이고 있다.
그런데 실제로 입력한 값이 왜 어디가 잘못한건지 알기위해서는 객체 이름과 해시코드 값이 아닌 쓰여진 값을 출력해주는 것이 디버깅 하기 훨씬 편하다.
toString의 규약은 "모든 하위 클래스에서 이 메서드를 재정의하라" 이다.
상위 클래스에서 이미 알맞게 재정의한 경우는 예외로 모든 구체 클래스에서 Object의 toString을 재정의하자. toString을 재정의한 클래스는 사용하기도 즐겁고 그 클래스를 사용한 시스템을 디버깅하기 쉽게 해준다. toString은 해당 객체에 관한 명확하고 유용한 정보를 읽기 좋은 형태로 반환해야 한다.
하지만 예외적으로 toString은 해당 객체 정보를 알기 위해 public으로 선언하여 사용하는 메서드이지만 해당 객체 정보가 외부로 유출되면 안되는 내용이 포함이 되었을 경우?
User 클래스에 암호화 되지 않은 비밀번호나 주민등록 번호가 있을 경우
toString 메서드에서 해당 정보를 제외한 정보만 제공하는 방법을 쓰던지 해야겠다.
package item12;
public class PhoneNumber {
private final int areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum) {
super();
this.areaCode = rangeCheck(areaCode, 999, "지역코드");
this.prefix = rangeCheck(prefix, 999,"프리픽스");
this.lineNum = rangeCheck(lineNum, 9999, "가입자 번호");
}
private static int rangeCheck(int val, int max, String arg) {
if(val < 0 || val > max) {
throw new IllegalArgumentException(arg + " : " + val);
}
return val;
}
/**
* 전화번호의 문자열 형식은 "XXX-YYY-ZZZZ" 형태의 12글자
* XXX는 지역코드, YYY는 프리픽스, ZZZZ는 가입자 번호
* 각 대문자는 10진수 숫자를 나타낸다.
* 각 부분의 자릿수를 채울 수 없다면 앞에서부터 0으로 채운다.
*/
@Override
public String toString() {
return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
}
// PhoneNumber 클래스의 정보를 제공하는 팩터리 메서드
public static PhoneNumber of(String phoneNumberString) {
String[] split = phoneNumberString.split("-");
PhoneNumber pn = new PhoneNumber(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
return pn;
}
@Override
public boolean equals(Object obj) {
if(obj == this) return true;
if(!(obj instanceof PhoneNumber)) return false;
PhoneNumber pn = (PhoneNumber) obj;
return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
}
@Override
public int hashCode() {
int result = Integer.hashCode(areaCode);
result = 31 * result + Integer.hashCode(prefix);
result = 31 * result + Integer.hashCode(lineNum);
return result;
}
public static void main(String[] args) {
PhoneNumber jenny = new PhoneNumber(707, 789, 1304);
System.out.println("제니의 번호 : " + jenny); // 제니의 번호 : 707-789-1304
PhoneNumber pn = PhoneNumber.of("707-789-1304");
System.out.println(pn); // 707-789-1304
System.out.println(jenny.equals(pn)); // true
System.out.println(jenny.hashCode() == pn.hashCode()); // true
} // end of main
}// end of class
https://www.inflearn.com/course/%EC%9D%B4%ED%8E%99%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94-1/dashboard
'Effective Java > 정리' 카테고리의 다른 글
Item.14 Comparable을 구현할지 고려하라 (0) | 2023.02.12 |
---|---|
Item.13 clone 재정의는 주의해서 진행하라. (0) | 2023.02.05 |
Item11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2023.01.31 |
item10. equals는 일반 규약을 지켜 재정의하라. (0) | 2023.01.29 |
[Item 9] try-finally보다는 try-with-resources를 사용하라 (0) | 2023.01.17 |