CodeGym /Java Blog /무작위의 /Java에서 문자열 비교 및 같음 비교
John Squirrels
레벨 41
San Francisco

Java에서 문자열 비교 및 같음 비교

무작위의 그룹에 게시되었습니다
안녕! 오늘 우리는 매우 중요하고 흥미로운 주제, 즉 객체와 객체를 비교하는 것(문자열과 같음 비교)에 대해 이야기할 것입니다. 그래서 Java에서 객체 A가 객체 B 와 정확히 같은 때는 언제입니까 ? 예제를 작성해 봅시다:

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {
      
       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
콘솔 출력: false 대기, 중지. 이 두 자동차가 동등하지 않은 이유는 무엇입니까? 동일한 속성을 할당했지만 비교 결과는 false입니다. 답은 간단합니다. == 연산자 는 개체 속성이 아닌 개체 참조를 비교합니다. 두 객체는 ​​동일한 값을 가진 500개의 필드를 가질 수 있지만 이들을 비교하면 여전히 false가 생성됩니다. 결국 car1car2를 참조합니다.두 개의 다른 객체, 즉 두 개의 다른 주소를 가리킵니다. 사람들을 비교하는 상황을 상상해 보십시오. 확실히, 세상 어딘가에 당신과 같은 이름, 눈 색깔, 나이, 키, 머리 색깔 등을 공유하는 사람이 있습니다. 그것은 당신을 많은 면에서 비슷하게 만듭니다. 하지만 당신은 여전히 ​​쌍둥이가 아닙니다. 같은 사람.
같음 및 문자열 비교 - 2
== 연산자 는 두 개체를 비교하는 데 사용할 때 이와 거의 동일한 논리를 사용합니다. 그러나 다른 논리를 사용하기 위해 프로그램이 필요한 경우에는 어떻게 해야 합니까? 예를 들어 프로그램이 DNA 분석을 수행한다고 가정합니다. 그것은 두 사람의 유전자 코드를 비교하고 그들이 쌍둥이인지 여부를 결정합니다.

public class Man {

   int geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = 1111222233;

       Man man2 = new Man();
       man2.geneticCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
콘솔 출력: false 우리는 동일한 논리적 결과를 얻었지만(많이 변경하지 않았기 때문에) 이제 그 논리는 좋지 않습니다! 결국 실생활에서 DNA 분석은 우리 앞에 쌍둥이가 있다는 것을 100% 보장해야 합니다. 그러나 우리 프로그램과 == 연산자는 그 반대를 말합니다. DNA가 일치할 때 이 동작을 변경하고 프로그램이 올바른 결과를 출력하도록 하려면 어떻게 해야 합니까? Java에는 이를 위한 특별한 메서드가 있습니다: equals() . 앞서 논의한 toString() 메서드 와 마찬가지로 equals()는 다른 모든 클래스가 파생되는 클래스인 Java에서 가장 중요한 클래스인 Object 클래스 에 속합니다 . 그러나 같음()프로그램의 동작을 자체적으로 변경하지 않습니다.

public class Man {

   String geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = "111122223333";

       Man man2 = new Man();
       man2.geneticCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
콘솔 출력: false 정확히 같은 결과이므로 이 메서드가 필요한 이유는 무엇입니까? :/ 모두 간단합니다. 여기서 문제는 Object 클래스 에서 구현되는 이 메서드를 현재 사용하고 있다는 것입니다 . 그리고 Object 클래스 의 코드로 이동하여 메서드의 구현을 보면 다음과 같이 표시됩니다.

public boolean equals(Object obj) {
   return (this == obj);
}
이것이 프로그램의 동작이 변경되지 않은 이유입니다! 매우 동일한 == 연산자(참조를 비교함)가 Object 클래스 의 equals() 메서드 내에서 사용됩니다 . 하지만 이 방법의 요령은 우리가 그것을 재정의할 수 있다는 것입니다. 재정의한다는 것은 Man 클래스 에 자신만의 equals() 메서드를 작성하여 필요한 동작을 제공하는 것을 의미합니다! 현재 man1.equals(man2) 가 본질적으로 man1 == man2 와 동일하다는 사실이 마음에 들지 않습니다 . 이 상황에서 우리가 할 일은 다음과 같습니다.

public class Man { 

   int dnaCode; 

   public boolean equals(Man man) { 
       return this.dnaCode ==  man.dnaCode; 

   } 

   public static void main(String[] args) { 

       Man man1 = new Man(); 
       man1.dnaCode = 1111222233; 

       Man man2 = new Man(); 
       man2.dnaCode = 1111222233; 

       System.out.println(man1.equals(man2)); 

   } 
} 
콘솔 출력: true 이제 완전히 다른 결과를 얻습니다! 우리만의 equals() 메서드를 작성하고 표준 메서드 대신 사용함으로써 우리는 올바른 동작을 생성했습니다. 이제 두 사람이 동일한 DNA를 가지고 있으면 프로그램은 "DNA 분석 결과 그들이 쌍둥이임을 증명했습니다"라고 보고하고 true를 반환합니다! 클래스에서 equals() 메서드를 재정의하면 필요한 객체 비교 논리를 쉽게 만들 수 있습니다. 사실 우리는 객체 비교에 대해서만 다루었습니다. 우리 앞에는 여전히 이 주제에 대한 큰 독립형 강의가 있습니다 (관심이 있다면 지금 훑어보세요).

Java에서 문자열 비교

문자열 비교를 다른 모든 것과 별도로 고려하는 이유는 무엇입니까? 현실은 문자열이 프로그래밍에서 그 자체로 주제라는 것입니다. 첫째, 지금까지 작성된 모든 Java 프로그램을 살펴보면 그 안에 있는 개체의 약 25%가 문자열이라는 것을 알 수 있습니다. 그래서 이 주제는 매우 중요합니다. 둘째, 문자열을 비교하는 과정은 다른 개체와 정말 많이 다릅니다. 간단한 예를 고려하십시오.

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
콘솔 출력: false 하지만 왜 false가 되었습니까? 결국 문자열은 정확히 동일 합니다 . 분명히 s1s2는 메모리에서 다른 주소를 가집니다. 당신이 그것을 생각했다면, 우리의 예를 다시 만들어 봅시다:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
이제 다시 두 개의 참조가 있지만 결과는 정반대입니다. 콘솔 출력: true 무기력하게 혼란스럽습니까? 무슨 일이 일어나고 있는지 알아 봅시다. == 연산자 는 실제로 메모리 주소를 비교합니다. 이것은 항상 사실이며 의심할 필요가 없습니다. 즉, s1 == s2가 true를 반환하면 이 두 문자열의 주소는 동일합니다. 그리고 실제로 이것은 사실입니다! 문자열을 저장하기 위한 특별한 메모리 영역인 문자열 풀을 소개할 시간입니다.
같음 및 문자열 비교 - 3
문자열 풀은 프로그램에서 생성한 모든 문자열 값을 저장하는 영역입니다. 왜 만들어졌나요? 앞에서 말했듯이 문자열은 모든 개체의 엄청난 비율을 나타냅니다. 큰 프로그램은 많은 문자열을 생성합니다. 문자열 풀은 메모리를 절약하기 위해 만들어졌습니다. 문자열이 여기에 배치된 다음 이후에 생성된 문자열은 동일한 메모리 영역을 참조하므로 매번 추가 메모리를 할당할 필요가 없습니다. String = "......." 라고 쓸 때마다 프로그램은 문자열 풀에 동일한 문자열이 있는지 확인합니다. 있는 경우 새 문자열이 생성되지 않습니다. 그리고 새 참조는 문자열 풀에서 동일한 주소(동일한 문자열이 있는 위치)를 가리킵니다. 그래서 우리가 썼을 때

String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 는 s1 과 같은 위치를 가리킵니다 . 첫 번째 문은 문자열 풀에 새 문자열을 만듭니다. 두 번째 명령문은 단순히 s1 과 동일한 메모리 영역을 나타냅니다 . 다른 500개의 동일한 문자열을 만들 수 있으며 결과는 변경되지 않습니다. 잠깐 기다려요. 그것이 사실이라면 왜 이전에는 이 예제가 작동하지 않았습니까?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
나는 당신의 직감이 이미 당신에게 그 이유를 말해주었다고 생각합니다 =) 더 읽기 전에 추측해 보십시오. 이 두 문자열이 서로 다른 방식으로 선언되었음을 알 수 있습니다. 하나는 new 연산자가 있는 것이고 다른 하나는 없는 것입니다. 여기에 그 이유가 있습니다. new 연산자를 사용 하여 개체를 만들면 해당 개체에 대해 새 메모리 영역을 강제로 할당합니다. 그리고 new를 사용하여 생성된 문자열은 문자열 풀에서 끝나지 않습니다. 텍스트가 문자열 풀의 문자열과 완벽하게 일치하더라도 별도의 객체가 됩니다. 즉, 다음 코드를 작성하면

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
메모리에는 다음과 같이 표시됩니다.
같음 및 문자열 비교 - 4
그리고 new 를 사용하여 새 객체를 만들 때마다 새 문자열 내부의 텍스트가 동일하더라도 새 메모리 영역이 할당됩니다! == 연산자를 알아낸 것 같습니다 . 그러나 우리의 새로운 지인인 equals() 메서드 는 어떻습니까 ?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
콘솔 출력: true 흥미롭습니다. 우리는 s1s2가 메모리의 다른 영역을 가리킨다 고 확신합니다 . 그러나 equals() 메서드는 여전히 둘이 같다고 알려줍니다. 왜? 객체를 원하는 대로 비교하기 위해 equals() 메서드를 재정의할 수 있다고 이전에 말한 것을 기억하십니까 ? 그것이 그들이 String 클래스로 한 일입니다. equals()를 재정의합니다.방법. 참조를 비교하는 대신 문자열의 문자 시퀀스를 비교합니다. 텍스트가 동일한 경우 생성 방법이나 저장 위치(문자열 풀 또는 별도의 메모리 영역)는 중요하지 않습니다. 비교 결과는 참이 됩니다. 그런데 Java에서는 대소문자를 구분하지 않는 문자열 비교를 수행할 수 있습니다. 일반적으로 문자열 중 하나에 모두 대문자가 있는 경우 비교 결과는 false가 됩니다.

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
콘솔 출력: false 대소문자를 구분하지 않는 비교의 경우 String 클래스에는 equalsIgnoreCase() 메서드가 있습니다. 대소문자가 아닌 특정 문자의 순서만 비교하는 데만 신경쓰는 경우에 사용할 수 있습니다. 예를 들어 다음 두 주소를 비교할 때 유용할 수 있습니다.

public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
이 경우 분명히 같은 주소에 대해 이야기하고 있으므로 equalsIgnoreCase() 메서드 를 사용하는 것이 좋습니다 .

String.intern() 메서드

String 클래스 에는 까다로운 메서드가 하나 더 있습니다: intern() ; intern () 메서드는 문자열 풀과 직접 작동합니다. 일부 문자열에서 intern() 메서드를 호출하는 경우 :
  • 문자열 풀에 일치하는 문자열이 있는지 확인합니다.
  • 있는 경우 풀의 문자열에 대한 참조를 반환합니다.
  • 그렇지 않은 경우 문자열을 문자열 풀에 추가하고 이에 대한 참조를 반환합니다.
new 를 사용 하여 얻은 문자열 참조에서 intern() 메서드를 사용한 후 == 연산자를 사용하여 문자열 풀의 문자열 참조와 비교할 수 있습니다.

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
콘솔 출력: true 이전에 intern() 없이 이 문자열을 비교했을 때 결과는 false였습니다. 이제 intern() 메서드는 "CodeGym은 Java 학습을 위한 최고의 사이트입니다!" 라는 문자열을 확인합니다. 문자열 풀에 있습니다. 물론입니다.

String s1 = "CodeGym is the best website for learning Java!";
s1 과 s2.intern() 이 반환한 참조가 동일한 메모리 영역을 가리키는 지 확인합니다 . 그리고 물론 그들은 그렇게 합니다 :) 요약하면, 이 중요한 규칙을 기억하고 적용하십시오: 항상 equals() 메소드를 사용하여 문자열을 비교하십시오! 문자열을 비교할 때 우리는 거의 항상 참조, 메모리 영역 또는 기타 항목이 아닌 문자를 비교하는 것을 의미합니다. equals () 메서드는 정확히 필요한 작업을 수행합니다. 배운 내용을 보강하려면 Java 과정에서 비디오 강의를 시청하는 것이 좋습니다.

더 읽어보기:

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION