JavaRush /Java Blog /Random-KO /자바의 비교기

자바의 비교기

Random-KO 그룹에 게시되었습니다
안녕하세요! 오늘은 객체 비교에 대해 이야기하겠습니다. 흠... 그런데 우리는 이 문제에 대해 이미 여러 번 이야기한 것 같은데요? :/ 우리는 " ==" 연산자가 어떻게 작동하는지와 equals()및 메소드를 알고 있습니다 hashCode(). 비교는 실제로 그것에 관한 것이 아닙니다. 이전에는 “개체의 동등성을 테스트하는 것”에 더 가깝다는 의미였습니다. Java의 비교기 - 1그러나 객체를 서로 비교하는 목적은 완전히 다를 수 있습니다! 가장 확실한 것은 정렬입니다. 숫자나 문자열 목록을 정렬하라고 하면 ArrayList<>문제 없이 처리할 수 있을 것 같습니다.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       String name1 = "Masha";
       String name2 = "Sasha";
       String name3 = "Даша";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
콘솔 출력:

[Даша, Маша, Саша]
Collections클래스 와 메소드를 기억해 두시면 좋습니다 sort(). 숫자에도 문제가 없을 것 같아요. 다음은 더 어려운 작업입니다.
public class Car {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   //...геттеры, сеттеры, toString()

}

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);
   }
}
매우 간단합니다. 클래스 Car와 해당 객체 3개입니다. 목록에 있는 자동차를 정렬할 정도로 친절하세요! 아마도 당신은 “어떻게 정렬해야 합니까?”라고 물을 것입니다. 이름, 제조 연도, 최대 속도로? 좋은 질문입니다. 우리는 현재 클래스의 객체를 정렬하는 방법을 모릅니다 Car. 그리고 당연하게도 Java도 이 사실을 모릅니다! Collections.sort()객체 목록을 메소드에 전달하려고 하면 Car오류가 발생합니다.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       //ошибка компилятора!
       Collections.sort(cars);
   }
}
그리고 실제로, 당신이 작성한 객체를 정렬하는 방법을 언어가 정확히 어떻게 아는가? 이는 프로그램의 목표에 따라 다릅니다. 우리는 이러한 객체를 비교하기 위해 어떻게든 Java를 가르쳐야 합니다. 그리고 우리에게 필요한 방식을 비교해 보세요. 이를 위해 Java에는 특별한 도구인 인터페이스가 있습니다 Comparable. 영어에서는 "비교 가능"으로 번역됩니다. 객체를 Car서로 비교하고 어떻게든 정렬하려면 클래스가 이 인터페이스를 구현하고 유일한 메서드를 구현해야 합니다 compareTo().
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return 0;
   }

   //...геттеры, сеттеры, toString()

}
주의하세요:Comparable<Car>우리는 인터페이스 뿐만 아니라 인터페이스도 지정했습니다 Comparable. 이는 형식화된 인터페이스입니다. 즉, 연결된 특정 클래스를 지정해야 합니다. 원칙적으로 <Car>인터페이스에서 제거할 수 있지만 기본적으로 개체를 비교합니다 Object. compareTo(Car o)우리 클래스의 메소드 대신에 우리는 다음을 갖게 될 것입니다:
@Override
   public int compareTo(Object o) {
       return 0;
   }
물론 우리가 작업하는 것이 훨씬 쉽습니다 Car. 메서드 내에서 compareTo()기계를 비교하는 논리를 구현합니다. 제조 연도별로 정렬해야 한다고 가정해 보겠습니다. 메소드가 compareTo()int이 아닌 값을 반환한다는 것을 눈치챘을 것입니다 boolean. 이것이 당신을 놀라게 하지 않도록 하세요. 사실 두 객체를 비교하면 3가지 가능한 옵션이 제공됩니다.
  • а < b
  • a > b
  • a == b.
true와 false의 2가지 값만 있어서 boolean개체를 비교하는 데 불편합니다. 모든 것이 int훨씬 간단합니다. 반환 값이 > 0이면 입니다 a > b. 결과 compareTo < 0가 이면 а < b. 결과가 이면 == 0두 개체는 동일합니다 a == b. 우리 수업에서 제조 연도별로 자동차를 분류하도록 가르치는 것은 배를 까는 것만큼 쉽습니다.
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
여기서 무슨 일이 일어나고 있는 걸까요? 우리는 이 자동차의 제조 연도인 하나의 자동차 객체( this)에서 다른 자동차의 제조 연도(객체를 비교하는 객체)를 뺍니다. 첫 번째 자동차의 제조 연도가 더 크면 메서드는 를 반환합니다 int > 0. 즉 자동차 this >는 자동차라는 뜻이다 о. 반대로 두 번째 자동차의 제조 연도( о)가 더 큰 경우 메서드는 음수를 반환하므로 가 반환됩니다 о > this. 음, 동일하다면 메소드는 를 반환할 것입니다 0. 이러한 간단한 메커니즘은 이미 개체 모음을 정렬하는 데 충분합니다 Car! 다른 작업을 수행할 필요가 없습니다. 여기 있어요:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       //тут раньше была ошибка
       Collections.sort(cars);
       System.out.println(cars);
   }
}
콘솔 출력:

[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}, 
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
자동차는 원래대로 정렬되어 있습니다! :) Java 비교기 - 2어떤 경우에 사용해야 하나요 Comparable? 구현된 비교 방법을 Comparable"자연순서"라고 합니다. compareTo()이는 프로그램에서 이 클래스의 개체에 사용되는 가장 일반적인 비교 방법을 메서드에서 설명하기 때문입니다 . 자연순서는 이미 Java에 존재합니다. 예를 들어, Java는 문자열이 알파벳순으로 정렬되는 경우가 많고 숫자는 값의 오름차순으로 정렬되는 경우가 가장 많다는 것을 알고 있습니다. 따라서 숫자 또는 문자열 목록에서 메서드를 호출하면 sort()정렬됩니다. Comparable<Car>우리 프로그램에서 자동차가 대부분의 경우 제조 연도별로 비교되고 정렬된다면 인터페이스 와 방법을 사용하여 자동차에 대한 자연스러운 정렬을 정의하는 것이 좋습니다 compareTo(). 하지만 그것만으로는 충분하지 않다면 어떨까요? 우리 프로그램이 그렇게 간단하지 않다고 상상해 봅시다. 대부분의 경우 자연적인 자동차 분류(제조 연도별로 설정)가 우리에게 적합합니다. 그러나 때때로 우리 고객 중에는 빠른 운전을 좋아하는 팬이 있습니다. 고객이 선택할 수 있는 자동차 카탈로그를 준비하는 경우 최대 속도순으로 주문해야 합니다. Java의 비교기 - 3예를 들어, 15%의 경우에는 이러한 정렬이 필요합니다. 이는 Car제조 연도 대신 속도를 기준으로 자연 정렬을 설정하는 것만으로는 충분하지 않습니다. 하지만 우리는 고객의 15%를 무시할 수 없습니다. 우리는 무엇을해야합니까? 여기에 또 다른 인터페이스가 도움이 됩니다 Comparator. 와 마찬가지로 Comparable입력됩니다. 차이점이 뭐야? Comparable객체를 "비교 가능"하게 만들고 대부분의 경우에 사용되는 가장 자연스러운 정렬 순서를 만듭니다. Comparator- 이것은 별도의 "비교기" 클래스입니다(번역이 약간 서투르지만 이해할 수 있음). Car특정 정렬을 구현해야 하는 경우 클래스에 들어가서 논리를 변경할 필요가 없습니다 compareTo(). 대신, 프로그램에 별도의 비교 클래스를 만들고 필요한 정렬을 수행하도록 가르칠 수 있습니다!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
보시다시피 우리는 Comparator매우 간단합니다. 메소드는 단 하나뿐입니다 . 이는 구현해야 하는 compare()인터페이스 메소드 입니다 . Comparator두 개의 개체를 입력으로 사용 Car하고 일반적인 방법(뺄셈)으로 최대 속도를 비교합니다. 와 마찬가지로 compareTo()숫자를 반환하며 int비교 원리는 동일합니다. 이것을 어떻게 사용할 수 있나요? 매우 간단합니다:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       Comparator speedComparator = new MaxSpeedCarComparator();
       Collections.sort(cars, speedComparator);

       System.out.println(cars);
   }
}
콘솔 출력:

[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}, 
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
Collections.sort()우리는 단순히 비교기 객체를 생성하고 이를 정렬할 목록과 함께 메소드에 전달합니다 . 비교기를 입력으로 받은 메소드는 클래스 메소드 sort()에 정의된 자연 정렬을 사용하지 않습니다 . 대신 전달된 비교기의 정렬 알고리즘을 적용합니다. 이것이 우리에게 어떤 이점을 제공합니까? 첫째, 작성된 코드와의 호환성입니다. 우리는 대부분의 경우에 사용되는 현재 정렬 방법을 유지하면서 새롭고 구체적인 정렬 방법을 만들었습니다. 우리는 수업에 전혀 손을 대지 않았습니다 . 그는 그대로 남아 있었다: compareTo()CarCarComparable
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return this.getManufactureYear() - o.getManufactureYear();
   }

   //...геттеры, сеттеры, toString()

}
둘째, 유연성입니다. 원하는 만큼 종류를 추가할 수 있습니다. 색상, 속도, 무게 또는 배트맨 영화에서 자동차가 사용된 횟수를 기준으로 자동차를 정렬할 수 있습니다. 추가로 하나를 만드는 것만으로도 충분합니다 Comparator. 그게 다야! 오늘 여러분은 실제 직장 프로젝트에서 자주 사용하게 될 매우 중요한 두 가지 메커니즘을 배웠습니다. 그러나 아시다시피 실천이 없는 이론은 아무것도 아닙니다. 그러므로 이제 지식을 통합하고 여러 문제를 해결해야 할 때입니다! :)
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION