본문 바로가기
공부/Spring

[Spring][Lombok] @Data 어노테이션의 분석 (equals, hashCode)

by 웅대 2023. 2. 4.
728x90
반응형

어떠한 객체의 필드 값을 설정하는 방법은 여러가지가 있다.

 

일반적으로 필드 값에 직접적으로 접근하는 것이 아닌 getter와 setter를 이용하여 필드 값에 접근한다.

 

그런데 클래스 내부에서 getter와 setter를 지정하면 코드가 상당히 길어져 가독성이 떨어지는 단점이 있다.

 

그래서 lombok 라이브러리에서는 @Getter와 @Setter라는 어노테이션을 제공해 코드의 길이를 단축할 수 있다.

 

다른 사람들의 코드를 보다보면 @Getter와 @Setter를 둘 다 사용해야 할 때 @Data 어노테이션을 사용하는 모습을 볼 수 있다.

 

그동안 @Getter와 @Setter를 합친 것이 @Data 어노테이션이라고 알고 있었는데 더 추가적인 기능들을 가지고 있어서 한번 정리해보려 한다.

 

@Data 어노테이션은 다음과 같은 어노테이션을 가지고 있다.

 

@ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor

 

이를 천천히 살펴보려한다.

 

1. @ToString

 

아래와 같은 클래스를 생성해보자.

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name=name;
        this.age=age;
    }
}

 

 

 그리고 인스턴스를 하나 생성해서 이를 출력해보면 어떤 결과가 나올까?

@SpringBootApplication
public class NoticeApplication {

   public static void main(String[] args) {
      Person person = new Person("chulsoo", 12);
      System.out.println("person = " + person);
   }

}

출력

person = com.board.notice.Person@497470ed

해당 객체에 대한 정보를 알려주고 있다.

 

그러나 우리는 출력을 할 때 해당 객체가 어떠한 필드 값들을 가지고 있는데 궁금할 때가 있다.

 

그럴 때는 모든 Object가 가지고 있는 toString() 메소드를 재정의하면 된다.

 

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name=name;
        this.age=age;
    }
    @Override
    public String toString() {
        return "name : "+name+" age : "+age;
    }
}

 이전에 실행했던 코드를 실행하면

출력

person = name : chulsoo age : 12

우리가 원하는 객체 안의 필드 값들을 확인해볼 수 있다.

 

이렇게 toString 메소드를 알아서 형식에 맞게 재정의해주는 어노테이션이 @ToString 어노테이션이다.

@ToString
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name=name;
        this.age=age;
    }
}

어노테이션을 달고 다시 출력해보면

 

출력

person = Person(name=chulsoo, age=12)

필드 값들을 보여주는 모습을 확인할 수 있다.

 

2. @EqualsAndHashCode

 

이 어노테이션은 Object가 공통적으로 가지고 있는 equals와 hashcode 메소드를 재정의하는 어노테이션이다.

 

여기서 equals 메소드는 객체의 동일성을 판단하는 메소드이다.

 

동일성과 동등성을 구분해야한다.

 

  1. 동일성 : 두 객체가 같은 메모리 주소를 가리키고 있다.
  2. 동등성 : 두 객체가 같은 값을 가지고 있다.

같은 값을 가지는 인스턴스를 두 개를 새롭게 생성했다고 하자.

 

같은 값을 가지기 때문에 동등하다고 볼 수 있지만 다른 곳을 가리키고 있으므로 동일하다고는 볼 수 없다.

 

아래 코드를 실행하면 false가 출력된다. 동등하지만 동일하지는 않기 때문이다.

@SpringBootApplication
public class NoticeApplication {

   public static void main(String[] args) {
      Person person = new Person("chulsoo", 12);
      Person person1 = new Person("chulsoo", 12);

      System.out.println(person.equals(person1));
   }

}

출력

false

 

그런데 우리는 객체 안의 값들이 같은지를 확인하고 싶을 때가 있다.

 

이럴 때 equals 메소드를 재정의하여 사용하는 것이다.

 

그런데 equals 메소드만 재정의해서는 완전하다고 할 수 없다.

 

위처럼 단순 객체끼리 비교를 할 때는 equals 메소드만 재정의해도 원하는 결과를 나타내지만 HashSet이나 HashMap 같은 자료구조에 저장할 때는 문제가 생길 수 있다.

 

HashSet 자료구조는 중복을 허용하지 않는다.

 

중복인지 아닌지 판단하는 방법은 객체의 고유한 해시 값을 비교하는 것이다.

 

이미 존재하는 객체의 hashCode 값과 들어가려는 객체의 hashCode값이 동일하면서 equals 메소드를 실행한 결과가 True라면 중복이 발생했다고 판단하는 것이다.

 

그래서 이러한 자료구조에 equals 메소드만 재정의하여 넣는다면 같은 값을 가짐에도 불구하고 서로 다르다고 판단하여 HashSet에 중복된 객체가 들어가는 일이 발생할 수 있다.

 

그래서 객체의 해시 값을 반환하는 hashCode 메소드 또한 재정의를 해줘야한다.

 

이렇게 equals와 hashCode 메소드를 재정의 해주는 어노테이션이 @EqualsAndHashCode 어노테이션이다.

 

3. @Getter와 @Setter

 

말 그대로 Getter와 Setter를 만들어준다.

 

Getter와 Setter를 직접 구현한 모습은 아래와 같다.

public class Person {
    private String name;
    private int age;

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

필드가 2개밖에 없는데 코드의 양이 상당하다.

 

@Getter와 @Setter를 사용해서 코드의 양을 줄일 수 있다.

 

@Getter
@Setter
public class Person {
    private String name;
    private int age;

}

4. @RequirredArgsConstructor

final, 혹은 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성해준다.

생성자를 자동 생성해주는 어노테이션 보통 3가지가 쓰인다.
 
  1. @NoArgsConstructor : 파라미터가 없는 생성자를 만든다.
  2. @RequiredArgsConstructor : final, 혹은 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 만든다.
  3. @AllArgsConstructor : 모든 필드에 대한 생성자를 만든다.

 

지금까지 설명한 어노테이션을 포함하는 어노테이션이 바로 @Data 어노테이션이다.

 

@Getter와 @Setter 이외에도 이렇나 어노테이션들을 포함하고 있다.

728x90
반응형

댓글