코드 그라데이션

<보충> Day25. equals 예제 본문

Java/Mega

<보충> Day25. equals 예제

완벽한 장면 2023. 5. 4. 13:07

예제코드

class F{
	void xxxx() {
    
    }
}

public class Main {

  public static void main(String[] args) {
  
  	// 여기 만약에

    F f = new F();
    F f1 = new F();
    F f2 = f1; // 하나의 물리적 주소를 두 개가 동시에 바라보게 되는 것.
    if(f == f1) {
      System.out.println("f == f1"); // 출력 안 됨 객체가 달라
    }
    if(f.equals(f1)) {
      System.out.println("f.equals(f1)"); // 출력 안 됨.
    }
    if(f1 == f2) { // f1과 f2는 참조변수가 가지고 있는 값이 같다.
      System.out.println("f1 == f2");
    }

    // f와 f1은 물리적으론 다르지만
    // equals를 정상적으로 구현했다면 출력이 될 수도.


    String str = "하이";

    if(str == "하이") {
      System.out.println("str == 하이");
    }
    if(str.equals("하이")) {
      System.out.println("str.equals(\"하이\")");
    }
  }

}

 

Equals() 특이한 점

- 기본 구현은 == 비교이다.

(ctrl + 클릭 해보면 나옴)

 

- equals의 출처는 Object 클래스의 기본 메서드

public boolean equals(Object obj) {
	return (this == obj);
}

 

그래서

if(f.equals(f1)) {
      System.out.println("f.equals(f1)"); 
}

이게 출력이 안 되는 것. 이거는

 if(f == f1) {
      System.out.println("f == f1"); // 출력 안 됨 객체가 달라
    }

이것과 의미적으로 다를 바가 없음.

 

 

정렬할 때,

정수배열은 정렬 가능

문자열 배열도 뒷 문자가 더 크다는 규칙이 있으므로 정렬 가능.

지금 예제에서 F클래스가 있고,

Main에 F[] 배열이 있다면?

이것은 정렬이 안 된다.

F는 내가 만든 사용자 정의 클래스고, 자바 컴파일러는 얘를 어떻게 정렬하는지 모르기 때문에 예외를 던진다.

=> 정렬하고 싶으면 컴파일러에게 어떻게 정렬하라고 알려줘야 한다.

 

왜 equals() 이야기하다가 정렬 이야기냐?

=> 맥락이 비슷하다.

동등하다는 것도 내가 알려주지 않으면 컴파일러가 알 방법이 없다.

=> 알려주는 방법은 equals를 오버라이드 하는 것.

=> 지금은 오버라이드 하지 않았기 때문에 동등성 비교를 그냥 동일성 비교랑 똑같이 수행한 것.


그럼

if(f.equals(f1)) {
      System.out.println("f.equals(f1)"); 
}

이게 출력되게 하고 싶다면?

(동일성은 건드리지 않되, 동등함을 의미하고 싶다면?)

 

가장 간단한 방법은

class F {

  @Override
  public boolean equals(Object obj) {
    return true; // 이게 가장 간단한 방법(실용적이지는 않음.)
  }
}

이렇게 equals를 오버라이드 해서 만져주는 것.


 그럼 보다 현실적인 방법은?

 

일단 다시 데이터베이스로 와서,

데이터베이스에는 PK(Primary Key) 라는 개념이 있다.

 

PK는 식별 위해 인위적인 개념을 이용하는데,

장소 1에서 A라고 주장하는 사람이랑, 장소 2에서 A라고 주장하는 사람이랑 동등한지 확인하려면,

그 때 확인해 보는 게 바로 Key 값이다.

 

예를 들면, F가 id를 가지고 있는데, 그 id가 일치하면 동등한 사람으로 보자 

이렇게 생각할 수 있음.

 

조금 만져준 코드

class F {

  int id;

  void xxxx() {

  }

  @Override
  public boolean equals(Object obj) {
    // 그런데 Object는 id가 없으므로 강제 형변환
    F f = (F) obj;

    if(id == f.id) {
      return true;
    }
    else {
      return false;
    }
  }
}

public class Main {

  public static void main(String[] args) {

    F f = new F();
    f.id= 10;
    F f1 = new F();
    f1.id = 10;
    F f2 = f1;

    if(f.equals(f1)) {
      System.out.println("f.equals(f1)");
    }

  }

}

이렇게 하면, 원하는 결과를 얻을 수 있게 됨!

<출력 결과>

f.equals(f1)

이제 문자열을 보면,

문자열에서 핵심적인 개념은

리터럴

 

String도 클래스

클래스는 인스턴스화가 가능한 것도 있고 불가능한 것도 있었지.

String은 인스턴스화 가능.

 

public class Main {

  public static void main(String[] args) {

    String str1 = "하이";
    String str2 = "하이";
    String str3 = new String("하이");

    System.out.println(str1 == str2);

    System.out.println(str1 == str3);
  }

}

실행 결과

true
false

 

String의 가장 큰 특징 = 불변

예를 들면

String str = "A";
str = str + "B";

라는 식이 있으면,

우리가 의도한 결과는 AB

 

그런데 내부 동작은 A옆에 B가 바로 붙는 것이 아니라,

A는 그대로 두고, 새로 AB를 만든다.(원본 문자열이 변한 게 아니라, 새로운 문자열이 만들어져 결과가 만들어지 것)

그 값을 반환하는 것.

-> 그래서 문자열 더하기는 성능이 나쁘다.

 

그런데 불변의 좋은 점도 있다

=> 자원을 공유해서 써도 안전하다.

 

 

str1이 하이를 만들어서 가리키고 있다면,

str2가 똑같이 하이를 만들었을 때,

새로운 공간에 하이가 생성되어서 그 곳을 str2가 가리키고 있는 것이 아니라,

문자열 pool 안에 만들어진 하이를 둘 다 같이 가리키고 있는 모양새가 되는 것.

자바 메모리와 문자열 pool

 

메모리상에 문자열의 불변 특성을 살려서 메모리를 조금 더 효율적으로 쓰기 위한 방법으로

문자열 pool 이라는 공간을 두었고,

이 곳에는 애플리케이션에 등장한 문자열들이 모두 저장이 된다.

그래서 물리적으로 완전히 똑같은 위치가 맞는 것!

 

그런데 new String("하이"); 는

문자열이 pool에 있건 말건, 새로운 공간에 하이를 만들겠다는 뜻.

이런 모양새

그렇기 때문에 다른 것.

728x90

'Java > Mega' 카테고리의 다른 글

<보충> Day13. call by Value와 call by Reference  (0) 2023.05.06
Thread 퀴즈  (0) 2023.05.05
<보충> Day25. 추상화  (0) 2023.05.04
<보충> Day25, equals() 개념  (0) 2023.05.04
함수 유의사항 + 물 가져오기 문제 유의사항  (0) 2023.05.04
Comments