09009
[Java] Object 클래스, equals(), toString() 본문
Object 클래스 - 모든 클래스의 최고 조상
• 모든 Java 클래스의 최상위 클래스
• 상속계층도의 최상위에는 Object 클래스가 위치한다.
• 다른 클래스로부터 상속 받지 않는 모든 클래스들은 자동적으로 Object 클래스로부터 상속받게 된다.
→ Java에서 모든 클래스들은 Object 클래스의 멤버들을 상속받으므로 Object 클래스에 정의된 멤버들을 그대로 사용 가능
(toString(), equals()와 같은 메서드를 따로 정의하지 않고도 사용할 수 있다.)
equals(0bject obj) - Object 클래스의 메서드
• equals(): 매개변수로 객체의 참조변수를 받아서 두 인스턴스의 주소값을 비교하여 같은 인스턴스인지의 여부를 확인 후 같으면 true, 다르면 false를 return하는 반환형이 boolean인 메서드이다.
public boolean equals(Object obj) {
return (this==obj);
}
• Object 클래스에 정의된 equals()는 두 객체의 같고 다름을 참조변수 값(객체의 주소)으로 판단하여 비교한다.
그러므로 서로 다른 두 객체를 equals() 메서드로 비교하면 항상 false를 반환하게 된다.
• String 클래스에서 equals() 메서드: 비교하고자 하는 두 가지 대상의 값 자체(내용)를 비교함
(Object 클래스의 equals() 메서드를 오버라이딩한 것)
equals() 메서드는 클래스에서 오버라이딩하여 사용자가 비교 기준을 임의로 변경할 수 있다.
아래와 같이 equals() 메서드의 판단 기준을 재정의하고자 한다.
• 주소가 아닌 두 객체에 저장된 내용을 비교하도록 한다.
• 객체 자신과 주어진 객체(obj)를 비교한다.
@override
public boolean equals(Object obj) { // '같다'라는 기준을 정해줌
return name.equals(((Person)obj).name);
}
위의 코드는 equals() 메서드를 주소값이 아닌 멤버변수 name의 값을 비교하도록 하기 위해 equals() 메서드를 오버라이딩한 것이다.
toString() - Object 클래스의 메서드
• 객체에 대해 출력할 형태를 지정하는 메서드
• 객체의 정보를 문자열(String)로 제공할 목적으로 정의된 메서드
→ 객체의 정보를 제공한다는 것 = 객체에 저장된 값들을 문자열로 표현
• 클래스 작성 시, toString()을 오버라이딩하지 않은채 toString()을 호출하면 16진수의 해시코드를 얻게 된다.
✍ Person.java
✍ PersonEx.java
💻 출력
toString() 메서드를 따로 오버라이딩하지 않아 출력 형식을 사용자가 임의로 지정해주지 않았을 때는 위와 같이 해시코드 형태
(패키지명.클래스명@해시코드)로 출력된다. (필자의 위에서 실행한 소스코드 패키지명은 school이므로 school(패키지명)--으로 출력된 것)
재작성한 코드
✍ Person.java (toString() 오버라이딩하여 출력형식 지정한 형태)
💻 출력
위의 소스코드에 있는 equals 메소드는 Person 클래스에서 오버라이딩한 것이다.
String 클래스에 있는 매개변수끼리의 비교이므로 Object 클래스가 아닌 String클래스의 equals() 메서드(값 비교)를 사용하는 것이다.
그리고 equals 메소드에서 name.equals(((Person)obj).name);라는 코드를 확인할 수 있는데 equals() 메서드에서 매개변수로 받은 obj가 Object 타입이므로 name값을 참조하기 위해서는 Person타입으로 꼭 형변환을 해주어야 한다.
최고 조상인 Object 클래스에는 name이라는 변수가 선언되지 않았고, 조상 클래스는 자손 클래스의 변수나 메서드를 직접 사용할 수 없기 때문에 꼭 자손 타입으로 형변환을 해주어야 하는 것이다.
그리고 Object 클래스로부터 상속받은 toString()을 오버라이딩하여 출력하고자 하는, 원하는 문자열 형태로 변환하였다.
→ toString()은 인스턴스나 클래스에 대한 정보, 인스턴스 변수들의 값을 문자열로 변환하여 오버라이딩하는 것이 일반적이다.
조상에 정의된 메서드(toString())를 자손에서 오버라이딩할 경우, 자손의 접근 제어자는 조상에 정의된 접근 범위보다 같거나 더 넓어야 한다.
Object 클래스에 정의된 toString()의 접근 제어자가 public이므로 Person 클래스의 toString()의 접근 제어자도 public으로 지정하였다.
✍ PersonEx.java
💻 출력
이렇게 함으로써 서로 다른 인스턴스일지라도 같은 name을 가지고 있다면 equals 메서드로 비교하였을 때 true로 결과를 출력할 수 있게 되고 toString 메서드를 오버라이딩하여 사용자가 원하는 형태로 출력할 수 있게 한다.
위 소스코드의 equals() 메서드에서는 name이 같으면 동일인물이라는 결과를 출력할 수 있도록 기준을 정하였다.
이번에는 juminNo(주민번호)가 같으면 같은 인물임을 출력하는 코드를 작성하였다.
✍ Person.java
juminNo(주민번호)는 기본형 int로 선언하였기 때문에 ==로 비교하였다.
(기본형 데이터는 ==, 참조형 데이터는 equals()로 비교함)
✍ PersonEx.java
💻 출력
Person.java에 있는 equals() 메서드에서 juminNo(주민번호)가 같으면 동일인물로 출력하도록 설정하였다.
그 결과, p1과 p2의 juminNo(주민번호)가 다르므로 "다르다"라는 결과가 출력된 것을 확인할 수 있다.
예제
package exercises;
public class MemberDTO {
public String name;
public String phone;
public String email;
@Override
public String toString() {
return "Name = " + name + " Phone = " + phone + " email = " + email;
}
public MemberDTO(String name, String phone, String email) {
this.name = name; this.phone = phone; this.email = email;
}
public static void main(String[] args) {
MemberDTO dto = new MemberDTO("Sangmin", "010XXXYYYY", "javatuning@gmail.com");
System.out.println(dto);
// System.out.println("Name = " + dto.name + " Phone = " + dto.phone + " email = " + dto.email);
MemberDTO dto1 = new MemberDTO("Sangmin", "010XXXYYYY", "javatuning@gmail.com");
if (dto.equals(dto1)) // 메모리에 저장된 위치를 비교하는 것임
System.out.println("동일 인물입니다");
else System.out.println("다른 인물입니다");
// 동일 인물이 아니라고 출력되는데 이것을 동일 인물로 출력시키기 위해 사용하는것이 equals() 메서드이다.
// 같다는 기준을 사용자 임의로 정하고 싶을 때 equals() 메서드를 오버라이딩(재정의)한다.
}
}
💻 출력
Name = Sangmin Phone = 010XXXYYYY email = javatuning@gmail.com
다른 인물입니다
* equals() 메서드 재정의하기
package exercises;
public class MemberDTO {
public String name;
public String phone;
public String email;
@Override
public String toString() {
return "Name = " + name + " Phone = " + phone + " email = " + email;
}
@Override
public boolean equals(Object obj) {
if (name.equals(((MemberDTO)obj).name) && phone.equals(((MemberDTO)obj).phone)
&& email.equals(((MemberDTO)obj).email)) {
return true;
} else return false;
}
public MemberDTO(String name, String phone, String email) {
this.name = name; this.phone = phone; this.email = email;
}
public static void main(String[] args) {
MemberDTO dto = new MemberDTO("Sangmin", "010XXXYYYY", "javatuning@gmail.com");
System.out.println(dto);
// System.out.println("Name = " + dto.name + " Phone = " + dto.phone + " email = " + dto.email);
MemberDTO dto1 = new MemberDTO("Sangmin", "010XXXYYYY", "javatuning@gmail.com");
if (dto.equals(dto1)) // 메모리에 저장된 위치를 비교하는 것임
System.out.println("동일 인물입니다");
else System.out.println("다른 인물입니다");
// 동일 인물이 아니라고 출력되는데 이것을 동일 인물로 출력시키기 위해 사용하는것이 equals() 메서드이다.
// 같다는 기준을 사용자 임의로 정하고 싶을 때 equals() 메서드를 오버라이딩(재정의)한다.
}
}
💻 출력
Name = Sangmin Phone = 010XXXYYYY email = javatuning@gmail.com
동일 인물입니다
예제
- Card
kind, number
생성자를 통하여 초기값 설정
- CardEx
card 1,2,3 스페이드 10, 스페이드 7, 하트 10
1) 번호가 같으면 같다고 변경하고 확인
2) 종류가 같다면 같다고 수정하고 확인
3) 출력 형식: 카드[종류:xxx, 번호:xxx]
1) 번호가 같으면 같다고 기준으로 정하였을 때
✍ CardEx.java
!!! 주의 number변수는 기본형으로 선언하였기 때문에 equals메서드가 아닌 ==로 비교하여야 한다.
package ch09;
class Card {
String kind;
int number;
Card(String kind, int number) {
this.kind = kind; this.number = number;
}
@Override
public boolean equals(Object obj) {
return number == ((Card)obj).number;
// return kind.equals(((Card)obj).kind);
}
@Override
public String toString() {
return "카드[종류: " + kind + ", 번호 : " + number + "]";
}
}
public class CardEx {
public static void main(String[] args) {
Card card1 = new Card("스페이드", 10);
Card card2 = new Card("스페이드", 7);
Card card3 = new Card("하트", 10);
if (card1.equals(card2)) System.out.println("card1과 card2는 같다.");
if (card1.equals(card3)) System.out.println("card1과 card3는 같다.");
if (card2.equals(card3)) System.out.println("card2과 card3는 같다.");
System.out.println(card1);
System.out.println(card2);
System.out.println(card3);
}
}
💻 출력 결과
card1과 card3는 같다.
카드[종류: 스페이드, 번호 : 10]
카드[종류: 스페이드, 번호 : 7]
카드[종류: 하트, 번호 : 10]
2) 종류가 같으면 같다고 기준으로 정하였을 때
✍ CardEx.java
kind변수는 참조형이므로 equals메서드로 비교하여야 한다.
package ch09;
class Card {
String kind;
int number;
Card(String kind, int number) {
this.kind = kind; this.number = number;
}
@Override
public boolean equals(Object obj) {
// return number == ((Card)obj).number;
return kind.equals(((Card)obj).kind);
}
@Override
public String toString() {
return "카드[종류: " + kind + ", 번호 : " + number + "]";
}
}
public class CardEx {
public static void main(String[] args) {
Card card1 = new Card("스페이드", 10);
Card card2 = new Card("스페이드", 7);
Card card3 = new Card("하트", 10);
if (card1.equals(card2)) System.out.println("card1과 card2는 같다.");
if (card1.equals(card3)) System.out.println("card1과 card3는 같다.");
if (card2.equals(card3)) System.out.println("card2과 card3는 같다.");
System.out.println(card1);
System.out.println(card2);
System.out.println(card3);
}
}
💻 출력 결과
card1과 card2는 같다.
카드[종류: 스페이드, 번호 : 10]
카드[종류: 스페이드, 번호 : 7]
카드[종류: 하트, 번호 : 10]
📖 문제
ManageStudent 클래스 생성 main함수 포함
따로 Student 클래스를 만들고 name, address, phone, email 필드를 추가.
네 필드를 입력값으로 생성자 추가
네 필드의 값이 같으면 같은 객체로 인식되도록 equals 메소드 추가.
ManageStudent 클래스에서
Student a=new Student("Min","Seoul","010XXXXXXXXX","ask@godofjava.com");
Student b=new Student("Min","Seoul","010XXXXXXXXX","ask@godofjava.com");
객체 생성후 입력하여 Equal 다르면 Not Equal 을 출력하도록 작성하고 main에서 테스트.
✍ 정답 코드 1)
package exercises;
class Student {
String name, address, phone, email;
public Student(String name, String address, String phone, String email) {
this.name = name;
this.address = address;
this.phone = phone;
this.email = email;
}
@Override
public boolean equals(Object obj) {
return (name.equals(((Student)obj).name) && address.equals(((Student)obj).address)
&& phone.equals(((Student)obj).phone) && email.equals(((Student)obj).email));
}
}
public class ManageStudent {
public static void main(String[] args) {
Student a=new Student("Min","Seoul","010XXXXXXXXX","ask@godofjava.com");
Student b=new Student("Min","Seoul","010XXXXXXXXX","ask@godofjava.com");
if (a.equals(b)) System.out.println("Equal");
else System.out.println("Not Equal");
}
}
💻 출력
equal
equals() 메서드 작성 시 규칙
- 재귀적 reflexive: null이 아닌 x에 대해 x.equals(x)는 항상 참
- 대칭적 symmetric: null이 아닌 x, y에 대해 x.equals(y)와 y.equals(x)의 결과는 같음
- 타동적 transitive: null이 아닌 x,y,z에 대해 x.equals(y)가 참이고 y.equals(z)가 참이면 x.equals(z)도 참
- 일관성 consistent: null이 아닌 x,y에 대해 x.equals(y)는 호출 시기와 관계 없이 일정
- null과의 비교: null이 아닌 x에 대해 x.equals(null)은 항상 거짓
✍ 정답 코드 2)
package exercises;
class Student {
String name, address, phone, email;
public Student(String name,String address,String phone,String email) {
this.name = name; this.address = address; this.phone = phone; this.email = email;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (phone == null) {
if (other.phone != null)
return false;
} else if (!phone.equals(other.phone))
return false;
return true;
}
}
public class ManageStudent {
public static void main(String[] args) {
Student a = new Student("Min", "Seoul", "010XXXXXXXXX", "ask@godofjava.com");
Student b = new Student("Min", "Seoul", "010XXXXXXXXX", "ask@godofjava.com");
if (a.equals(b)) System.out.println("equal");
else System.out.println("not equal");
}
}
/
5/11
'Back-End > JAVA' 카테고리의 다른 글
[Java] Arrays 클래스 (0) | 2023.03.12 |
---|---|
[Java] collection (0) | 2023.03.11 |
[Java] 클래스 간의 관계 - 포함관계 (0) | 2023.03.11 |
[Java] 상속 (0) | 2023.03.11 |
[Java] 다형성, 오버라이딩 (1) (0) | 2023.03.10 |