Java sınıfı neden karşılaştırılabilir bir uygulama yapmalı?


Yanıtlar:


213

İşte gerçek hayattan bir örnek. Not Stringda uygular Comparable.

class Author implements Comparable<Author>{
    String firstName;
    String lastName;

    @Override
    public int compareTo(Author other){
        // compareTo should return < 0 if this is supposed to be
        // less than other, > 0 if this is supposed to be greater than 
        // other and 0 if they are supposed to be equal
        int last = this.lastName.compareTo(other.lastName);
        return last == 0 ? this.firstName.compareTo(other.firstName) : last;
    }
}

sonra..

/**
 * List the authors. Sort them by name so it will look good.
 */
public List<Author> listAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    Collections.sort(authors);
    return authors;
}

/**
 * List unique authors. Sort them by name so it will look good.
 */
public SortedSet<Author> listUniqueAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    return new TreeSet<Author>(authors);
}

15
Sadece genellikle yönteminizle tutarlı olmak için geçersiz kılmak equals(ve bu nedenle hashCode) isteyeceğinizi belirtmek isterim compareTo. Örneğin, sınıfın a ile iyi oynamasını istiyorsanız bu gereklidir TreeSet.
pidge

Neden sadece geri dönmeyelim last?
Anirban Nag 'tintinmj'

@ AnirbanNag'tintinmj 'soyadının aynı olması durumunda otomatik olarak ilk ada göre sıralar.
OddDev

Artı CompareTo neden bir int döndürür ve ne anlama geldiğini iyi bir açıklama için. En yararlı.
james.garriss

1
@ user3932000: Doğru, hemen hemen tüm arayüzlerin amacı bu. Ancak "diğer Java yöntemleri" nin kullanıcı tarafından yazılan yöntemleri içerdiğini unutmayın! Aslında arayüzlerin çoğunun kullanıcı kodu tarafından tüketildiğini iddia ediyorum. Daha büyük kod tabanlarında, "kendiniz" hızlıca "diğerleri" olur
Enno Shioji

40

Karşılaştırılabilir bir doğal düzen tanımlar. Bunun anlamı, bir nesnenin "küçük" veya "büyük" olarak kabul edilmesi gerektiğinde onu tanımlamanızdır.

Bir grup tamsayıya sahip olduğunuzu ve bunları sıralamak istediğinizi varsayalım. Bu oldukça kolay, onları sıralı bir koleksiyona koyun, değil mi?

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

Ama şimdi, sıralamanın benim için anlamlı olduğu ancak tanımsız olduğu bazı özel nesnelerim olduğunu varsayalım. Diyelim ki, nüfus yoğunluğuna sahip posta koduyla bölgeleri temsil eden verilerim var ve bunları yoğunluğa göre sıralamak istiyorum:

public class District {
  String zipcode; 
  Double populationDensity;
}

Şimdi onları sıralamanın en kolay yolu, Karşılaştırılabilir'i uygulayarak doğal bir sıralama ile tanımlamaktır, bu da bu nesnelerin sipariş edilecek şekilde tanımlandığı standart bir yol olduğu anlamına gelir .:

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

Bir karşılaştırıcı tanımlayarak eşdeğer bir şey yapabileceğinizi unutmayın. Fark, karşılaştırıcının nesnenin dışındaki sıralama mantığını tanımlamasıdır . Belki ayrı bir süreçte aynı nesneleri zipcode ile sipariş etmem gerekiyor - bu durumda sipariş mutlaka nesnenin bir özelliği değildir veya nesnelerin doğal siparişinden farklıdır. Tamsayılarda özel bir sıralama tanımlamak için, örneğin bunları alfabetik değerlerine göre sıralayarak harici bir karşılaştırıcı kullanabilirsiniz.

Temel olarak sipariş mantığı bir yerde var olmak zorundadır. Bu olabilir -

  • nesnenin kendisinde, doğal olarak karşılaştırılabilirse (Karşılaştırılabilir -eg tam sayılarını genişletir)

  • Yukarıdaki örnekte olduğu gibi harici bir karşılaştırıcıda sağlanmıştır.


iyi bir örnek, ancak bunun TreeSet<Integer>yerine TreeMap<Integer>, ikincisi mevcut olmadığından, TreeMaps her zaman <Key,Value>-pairs olmalıdır. Btw, bir varsayım TreeMap<District, Object>sadece Bölge Karşılaştırılabilir uygularsa işe yarardı, değil mi? Hala bunu anlamaya çalışıyorum
phil294

14

Javadoc'tan alıntı;

Bu arabirim, onu uygulayan her sınıfın nesnelerine tam bir sıralama uygular. Bu sıralamaya sınıfın doğal sıralaması denir ve sınıfın CompareTo yöntemi de doğal karşılaştırma yöntemi olarak adlandırılır.

Bu arabirimi uygulayan nesne listeleri (ve dizileri) Collections.sort (ve Arrays.sort) tarafından otomatik olarak sıralanabilir. Bu arabirimi uygulayan nesneler, karşılaştırıcı belirtmeye gerek kalmadan, sıralanmış bir haritada anahtarlar olarak veya sıralanmış bir kümedeki öğeler olarak kullanılabilir.

Düzenleme: ..ve önemli bit kalın yaptı.


4
Ben cümle söyleyebilirim sonra sen kalın ettik biri gibi (daha) önemlidir.
Michael Borgwardt

8

Bir sınıfın uygulanması Comparable, o sınıftan iki nesne alabileceğiniz ve karşılaştırabileceğiniz anlamına gelir. Nesnelerin karşılaştırılabilir olmasını sağlamak için belirli koleksiyonlar (bir koleksiyondaki sıralama işlevi) gibi bazı sınıflar (sıralamak için hangi nesnenin "en büyük" olduğunu bilmeniz gerekir).


8

Yukarıdaki örneklerin çoğu, CompareTo işlevinde var olan karşılaştırılabilir bir nesnenin nasıl yeniden kullanılacağını gösterir. Aynı sınıftaki iki nesneyi karşılaştırmak istediğinizde, kendi CompareTo öğesini uygulamak isterseniz, fiyata (daha az önce sıralanır), ardından mola sayısına (tekrar, daha az ilk sırada), aşağıdakileri yaparsınız:

class AirlineTicket implements Comparable<Cost>
{
    public double cost;
    public int stopovers;
    public AirlineTicket(double cost, int stopovers)
    {
        this.cost = cost; this.stopovers = stopovers ;
    }

    public int compareTo(Cost o)
    {
        if(this.cost != o.cost)
          return Double.compare(this.cost, o.cost); //sorting in ascending order. 
        if(this.stopovers != o.stopovers)
          return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
        return 0;            
    }
}

6

Birden fazla alan karşılaştırması yapmanın kolay bir yolu Guava'nın CompareChain'idir - o zaman diyebilirsiniz

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

onun yerine

  public int compareTo(Person other) {
    int cmp = lastName.compareTo(other.lastName);
    if (cmp != 0) {
      return cmp;
    }
    cmp = firstName.compareTo(other.firstName);
    if (cmp != 0) {
      return cmp;
    }
    return Integer.compare(zipCode, other.zipCode);
  }
}

3

Örneğin, sıralanmış bir koleksiyona veya haritaya sahip olmak istediğinizde


Fernando'nun anlamı: Sıralı bir kapsayıcı sınıfında Karşılaştırılabilir'i uygulayan "şeyleri" depolarsanız, sıralı kap sınıfı bu "şeyleri" otomatik olarak sipariş edebilir.
Ian Durkan

2

Karşılaştırılabilir, sınıfınızın örneklerini karşılaştırmak için kullanılır. Örnekleri birçok yolla karşılaştırabiliriz, bu nedenle örnekleri compareTonasıl karşılaştırmak istediğimizi (nitelikler) bilmek için bir yöntem uygulamamız gerekir .

Dog sınıf:

package test;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Main sınıf:

package test;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Java'da karşılaştırılabilir nasıl kullanılacağına dair iyi bir örnek:

http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2


2

Eğer uygulamak Comparablearayüzü, sen yöntemini uygulamak gerekir compareTo(). Örneğin ArrayListsınıf sınıflandırma yöntemini kullanmak için nesneleri karşılaştırmanız gerekir . Nesnelerinizi sıralayabilmek için bunları karşılaştırmanın bir yoluna ihtiyacınız var. compareTo()Sınıfınızda özel bir yönteme ihtiyacınız var, böylece ArrayListsort yöntemiyle kullanabilirsiniz. compareTo()Yöntem döner -1,0,1.

Java Head 2.0'daki uygun bir bölümü okudum, hala öğreniyorum.


1

Tamam, ama neden sadece compareTo()karşılaştırılabilir arayüz uygulamadan bir yöntem tanımlamıyorsunuz . Örneğin City, nameve temperatureile tanımlanmış bir sınıf

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}

Bu çalışmıyor. Kıyaslanabilir olmadan - Classcast istisnası alıyorum
Karan Ahuja
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.