这是用户定义对象的树集代码。
package com.java2novice.treeset;
import java.util.Comparator;
import java.util.TreeSet;
public class MyCompUserDefine {
public static void main(String a[]){
//By using name comparator (String comparison)
TreeSet<Empl> nameComp = new TreeSet<Empl>(new MyNameComp());
nameComp.add(new Empl("Ram",3000));
nameComp.add(new Empl("John",6000));
nameComp.add(new Empl("Crish",2000));
nameComp.add(new Empl("Tom",2400));
for(Empl e:nameComp){
System.out.println(e);
}
System.out.println("===========================");
//By using salary comparator (int comparison)
TreeSet<Empl> salComp = new TreeSet<Empl>(new MySalaryComp());
salComp.add(new Empl("Ram",3000));
salComp.add(new Empl("John",6000));
salComp.add(new Empl("Crish",2000));
salComp.add(new Empl("Tom",2400));
for(Empl e:salComp){
System.out.println(e);
}
}
}
class MyNameComp implements Comparator<Empl>{
@Override
public int compare(Empl e1, Empl e2) {
return e1.getName().compareTo(e2.getName());
}
}
class MySalaryComp implements Comparator<Empl>{
@Override
public int compare(Empl e1, Empl e2) {
if(e1.getSalary() > e2.getSalary()){
return 1;
} else {
return -1;
}
}
}
class Empl{
private String name;
private int salary;
public Empl(String n, int s){
this.name = n;
this.salary = s;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString(){
return "Name: "+this.name+"-- Salary: "+this.salary;
}
}
我的问题是当我调用MyNameComp()或MySalaryComp()时,我只是调用它的构造函数而不传递任何值。但是EMP1类的价值或对象是如何传递的?
答案 0 :(得分:1)
您创建的TreeSet
个对象负责使用实例化时传递的比较器。
TreeSet
如何关注你,因为它是一个实现细节。 TreeSet
只保证在必要时使用您提供的比较器。你不需要考虑它...但是只是为了它,我们来看看源代码(请注意,在使用API时,你不应该依赖任何类的实现细节,因为它们可以随意更改,你只能确定界面的明确部分!)
让我们从TreeSet
constructor that takes a Comparator
as an argument开始,这是您在提供的示例中创建TreeSet
个实例时所调用的内容
public More ...TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<E,Object>(comparator));
}
我们可以看到the constructor使用比较器来实例化TreeMap
调用另一个TreeSet
构造函数。此处创建的TreeMap
将用于存储TreeSet
。
让我们离开它而不检查TreeMap
内发生的事情。我们只需要知道TreeMap
实际存储的是项目。当我们看一下添加元素时会发生什么,这些知识会派上用场。
您使用TreeSet#add
method插入所有项目,TreeMap#put
使用调用构造函数时创建的相同地图。
public boolean More ...add(E e) {
return m.put(e, PRESENT)==null;
}
m
对象是构造函数中实例化的TreeMap
。由于我们知道它是TreeMap
并且使用了put
方法,因此我们可以看看它的作用。
此方法使用比较器,经过仔细检查,结果与在TreeMap
构造函数中创建TreeSet
时使用的比较器相同。
public V More ...put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
// TBD:
// 7: (coll) Adding null to an empty TreeSet should
// throw NullPointerException
//
// compare(key, key); // type check
root = new Entry<K,V>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<K,V>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
这有点复杂,你必须仔细阅读其余的实现,才能完全理解这里发生的事情,但是可以清楚地看到提供的比较器被使用了。
但是,这里的底线是,对您或您的代码作为集合API的客户端无关紧要。您应该只依赖于public
或protected
方法的Javadoc中明确说明的内容。
你可以看看TreeSet
Javadoc,看看内部是否发生了变化(虽然非常轻微)
您可以确定使用TreeMap
和提供的Comparator
的原因是因为它是TreeSet
API的一部分。引用{{3}}:
(
TreeSet
是)基于NavigableSet
的{{1}}实施。元素按照它们的自然顺序排序,或者在创建时创建时提供TreeMap
,具体取决于使用的构造函数。
改变这些事情会破坏合同。
答案 1 :(得分:0)
TreeSet保持其元素排序。如果您提供比较器,它会使用该自定义比较器(在您的情况下为MyNameComp()或MySalaryComp())来比较和排序它们。你不需要调用任何东西,TreeSet将在内部处理它。