09009

[Java] Object 클래스, equals(), toString() 본문

Back-End/JAVA
[Java] Object 클래스, equals(), toString()
09009

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

Person.java (toString() 메서드를 따로 오버라이딩하지 않은상태)

✍ PersonEx.java

PersonEx.java

💻 출력

Person.Ex 출력결과

toString() 메서드를 따로 오버라이딩하지 않아 출력 형식을 사용자가 임의로 지정해주지 않았을 때는 위와 같이 해시코드 형태

(패키지명.클래스명@해시코드)로 출력된다. (필자의 위에서 실행한 소스코드 패키지명은 school이므로 school(패키지명)--으로 출력된 것)

 

 

 

재작성한 코드

✍ Person.java (toString() 오버라이딩하여 출력형식 지정한 형태)

toString() 메서드를 오버라이딩하여 출력 형식을 임의로 지정한 모습

💻 출력

Person.Ex 출력 결과

위의 소스코드에 있는 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

PersonEx.java

💻 출력 

Person.Ex 출력 결과

이렇게 함으로써 서로 다른 인스턴스일지라도 같은 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