2013-06-06 35 views
6

Tôi đã thêm một số đối tượng đơn giản vào TreeSet, nhưng khi tôi gọi phương thức remove() và contains() của TreeSet, chúng không hoạt động. Tuy nhiên, khi tôi lặp qua tập hợp, đối tượng được in. Các đối tượng nhân viên sẽ được thêm vào tập hợp trong khi tính duy nhất của đối tượng dựa trên thuộc tính tên đối tượng. Thuộc tính Id là giá trị cần được sắp xếp, nhưng không phải là duy nhất.Java TreeSet: xóa và chứa() không hoạt động

public class Employee { 
    private String name; 
    private int id; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getName() { 
    return name; 
    } 

    public void setName(String name) { 
    this.name = name; 
    } 

// Two objects are considered equal if their names are equal 
    @Override 
    public boolean equals(Object o) { 
    if (o == null) 
     return false; 
    if (this == o) 
     return true; 
    if (o.getClass() == this.getClass()) { 
     Employee p = (Employee) o; 
     if (p.getName() != null && this.getName() != null) 
     return this.getName().equals(p.getName()); 
     else 
     return false; 
    } else { 
     return false; 
    } 
    } 
} 

//******************************************************* 

public class EmployeeComp implements Comparator<Employee> { 

    // Sort Ids, but allow duplicates, hence this function is never returning 0 
    @Override 
    public int compare(Employee p1, Employee p2) { 
    int re = 0; 

    boolean scoreLt = (p1.getId() > p2.getId()); 
    boolean scoreGt = (p1.getId() < p2.getId()); 

    if(scoreLt) 
     re = -1; 
    if(scoreGt) 
     re = 1; 
    else 
     re = -1;      
     return re;     
    }  
} 
//******************************************************* 
// Collection shall store unique names with ordered values like: 
// Alex, 923 
// Toni, 728 
// Eddi, 232 
// Peter, 232 
// Eddi, 156 *** not allowed 
import java.util.TreeSet; 


public class Main { 
    private static EmployeeComp comp = new EmployeeComp(); 
    private static TreeSet<Employee> employees = new TreeSet<Employee>(comp); 

    public static void main(String[] args) { 

    Employee p1 = new Employee(); 
    p1.setName("Eddi"); 
    p1.setId(232); 

    Employee p2 = new Employee(); 
    p2.setName("Toni"); 
    p2.setId(728); 

    Employee p3 = new Employee(); 
    p3.setName("Peter"); 
    p3.setId(232); 

    Employee p4 = new Employee(); 
    p4.setName("Alex"); 
    p4.setId(923); 

    employees.add(p1); 
    employees.add(p2); 
    employees.add(p3); 
    employees.add(p4); 

    // Here, contains() and remove() should check the object address 
    // and not perform their actions based on compareTo 

     } 
} 
+0

Không, tôi đã thực hiện điều đó trước tiên, nhưng đã nhận xét sau, vì vậy đây không thể là sự lặp lại. – user1812379

+0

@fge chắc chắn, bạn nói đúng, tôi đã bỏ qua điều này. –

+0

OK, xem giải pháp, và một điều bạn cần lưu ý: bạn không thể làm những gì bạn muốn với '.equals()' /'.hashCode() 'hoặc' Comparator' một mình - bạn không thể có cả hai bánh và ăn nó. Ví dụ 'BigDecimal' của tôi đã cho bạn một gợi ý! – fge

Trả lời

21

Một TreeSet chèn/loại bỏ theo kết quả của Comparable, không .equals()/.hashCode()!

Điều này có nghĩa, BTW, mà các đối tượng của Set bạn làm thực hiện Comparable (nếu họ không, mỗi khi bạn muốn đã cố gắng và chèn một thành viên, bạn muốn đã được chào đón với một ClassCastException).

Để chính xác hơn, TreeSet là triển khai SortedSet.

Nếu bạn muốn có một .equals()/.hashCode() bộ tương thích, hãy sử dụng, ví dụ: HashSet.

Đối với hình minh họa, đây là những gì xảy ra với BigDecimal (được đăng cách đây vài giờ here):

final BigDecimal one = new BigDecimal("1"); 
final BigDecimal oneDotZero = new BigDecimal("1.0"); 

final Set<BigDecimal> hashSet = new HashSet<>(); 
// BigDecimal implements Comparable of itself, so we can use that 
final Set<BigDecimal> treeSet = new TreeSet<>(); 

hashSet.add(one); 
hashSet.add(oneDotZero); 
// hashSet's size is 2: one.equals(oneDotZero) == false 

treeSet.add(one); 
treeSet.add(oneDotZero); 
// treeSet's size is... 1! one.compareTo(oneDotZero) == 0 

Để trích dẫn javadoc cho Comparable, nó có nghĩa là BigDecimal 's .compareTo() là "không phù hợp với .equals() ".

** EDIT ** Như những gì OP muốn:

  • một Collection đó sẽ không chấp nhận tên trùng lặp;
  • chế độ xem được sắp xếp của số đó Collection sẽ sắp xếp theo id của người dùng.

Như đã đề cập ở trên, bạn không thể có một bộ sưu tập làm cả hai. Giải pháp:

  • cho lần đầu tiên, HashSet;
  • cho lần thứ hai, một bản sao của bộ đó được đặt thành ArrayList, sau đó sử dụng Collections.sort().

Điều này có nghĩa là .equals().hashCode() chỉ được thực hiện trên tên, trong khi tùy chỉnh Comparator sẽ hoạt động trên id. Các Comparator không có sự lựa chọn khác, nhưng để được tùy chỉnh vì nó là một so sánh mà không phải là bao gồm với .equals() trong mọi trường hợp.

Đối với mã được đề xuất, có sự cố.

Đầu tiên: Employee ghi đè .equals() nhưng không phải .hashCode(). Như vậy, Employee vi phạm hợp đồng .equals() (một phần trong đó là nếu hai đối tượng bằng nhau, chúng phải có cùng một mã băm). Hơn nữa, .hashCode() rất quan trọng đối với HashSet để hoạt động.Fix:

@Override 
public int hashCode() 
{ 
    return name == null ? 0 : name.hashCode(); 
} 

@Override 
public boolean equals(final Object obj) 
{ 
    if (obj == null) 
     return false; 
    if (this == obj) 
     return false; 
    if (!(obj instanceof Employee)) 
     return false; 
    final Employee other = (Employee) obj; 
    return name == null ? other.name == null 
     : name.equals(other.name); 
} 

Thứ hai: so sánh được bình đẳng như bị phá vỡ như Employee vì nó phá vỡ hợp đồng Comparator (đối với bất kỳ o1o2, o1.compareTo(o2) == - o2.compareTo(o1)). Fix:

public final class EmployeeComp 
    implements Comparator<Employee> 
{ 
    @Override 
    public int compare(final Employee o1, final Employee o2) 
    { 
     final int id1 = o1.getId(), id2 = o2.getId(); 
     if (id1 == id2) 
      return 0; 
     return id1 > id2 ? 1 : -1; 
    } 
} 

Sau đó, làm thế nào để có được một bản sao sắp xếp của tập:

// "set" contains the unique employees 
final List<Employee> sorted = new ArrayList<Employee>(set); 
Collections.sort(list, new EmployeeComp()); 

XONG.

+2

+1, tìm thấy tốt. Các câu trả lời mặc định chỉ làm việc trong 95% các câu hỏi;) – jlordo

+0

@fge Sau đó, nó không hoạt động vì tôi đã không thực hiện bình đẳng trong compareTo(), bởi vì tôi muốn cho phép các bản sao. Đối với một đơn đặt hàng của các đối tượng như – user1812379

+0

@ user1812379 '.compareTo()' được cho là thực hiện tổng số thứ tự, không bằng nhau – fge

3

Vấn đề của bạn là khái niệm.

Nếu bạn muốn có một bộ sưu tập sắp xếp các đối tượng độc đáo: TreeSet
Nếu bạn muốn có một bộ sưu tập được sắp xếp là khác nhau đối tượng có thể có giá trị so sánh tương tự cho các mục đích phân loại: PriorityQueue

Ngẫu nhiên, các phương pháp trong một PriorityList nhiều phù hợp với nhu cầu thông thường của trường hợp thứ hai so với các yêu cầu trên TreeSet. Tôi từng nghĩ về nó như những thiếu sót TreeSet. Ví dụ: để lấy mục đầu tiên ra khỏi bộ sưu tập.

Hy vọng rằng sẽ giúp :-)

Các vấn đề liên quan