我们查看treeset的构造器的时候,发现TreeSet的构造器除了那种无参构造器之外,还提供了另外四种。其中TreeSet(Comparator<E>)可以传比较器。
public interface Comparator<T> {
int compare(T o1, T o2);
Comparator是一个接口,他有一个方法叫compare,我们可以在他的compare方法指定他的一个排序规则。
我们在设计代码过程中用到的compareTo方法的源码如下所示:
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
就是把value值取出来,然后进行循环比较,如果发现不相等,就返回c1-c2,然后谁的ACCIS码值大,就返回大于0的值,否则返回小于0的值。然后根据返回的值进行排序。
我们设计代码如下所示:
package com.rgf.set;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
//2.我们希望添加的元素按照字符串大小来排序
//3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//调用String的compareTo方法,进行字符串大小比较
return ((String)o1).compareTo((String)o2);
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
System.out.println("treeSet="+treeSet);
}
}
运行界面如下所示:
这种排序是从大到小排,我们也可以将他拍成从小到大排:
return ((String)o2).compareTo((String)o1);
运行之后如下所示:
我们下来进行源码的分析:
我们在 TreeSet treeSet = new TreeSet(new Comparator() {代码处进行断点的设置:
我们点击Force Step进入之后,在退出来。
我们可以通过f9直接跳出来,我们也可以进去后再退出来,我们进行如下所示:
这个构造器接收了一个comparator,这个接口的实现对象。
public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); }
我们继续进去如下所示:他把这个对象传给了如下所示:
这个comparator(比较器)传给了底层的TreeMap,
我们继续进行下一步,我们进入了add方法:
我们继续进行下一步:
我们再次进入了TreeMap里面了,进入了TreeMap里面的put方法。
我们继续进行下一步:
//我们将comparator赋给了cpr,comparator为我们传进去的comparator。 Comparator<? super K> cpr = comparator; //在调用treeSet.add("tom"),在底层会执行到 if (cpr != null) {//是有比较器的,比较器不为空。cpr,就是我们的匿名内部类(对象) do { parent = t; //动态绑定到我们的匿名内部类(对象)compare方法 cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else //如果相等,即返回0,这个key就没有加入 return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") 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<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; }
我们继续进行下一步之后,确实进入到如下所示:
我们进行设计重复值如下所示:
package com.rgf.set;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
//2.我们希望添加的元素按照字符串大小来排序
//3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
TreeSet treeSet = new TreeSet(new Comparator() {
//实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
@Override
public int compare(Object o1, Object o2) {
//调用String的compareTo方法,进行字符串大小比较
return ((String)o2).compareTo((String)o1);
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
treeSet.add("a");
System.out.println("treeSet="+treeSet);
//1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
}
}
我们运行界面如下所示:
我们发现运行结果里面没有重复值a,我们进行debug,如下所示:
我们进入add方法:
在进入put方法:
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
//比较器赋值给cpr.
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();
@SuppressWarnings("unchecked")
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<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
再次继续之后,我们发现退出来了:
所以相同的值是没有进去的。
如果我们修改按照长度大小排序:
我们修改代码如下所示:
//按照长度大小排序:
return ((String)o2).length()-((String)o1).length();
运行界面如下所示:
如果长度大小从小到大,代码修改如下所示:
//按照长度大小排序:
return ((String)o1).length()-((String)o2).length();
运行界面如下所示:
我们在添加如如下代码的时候,添加不进去:
package com.rgf.set;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
//2.我们希望添加的元素按照字符串大小来排序
//3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
TreeSet treeSet = new TreeSet(new Comparator() {
//实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
@Override
public int compare(Object o1, Object o2) {
//调用String的compareTo方法,进行字符串大小比较
//按照长度大小排序:
return ((String)o1).length()-((String)o2).length();
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
treeSet.add("rgf");//加入不进去。相同长度会覆盖前面的。一个大小
//我们所设置的规则为长度相等就是相同的元素。
//这里不进行替换,这相当于是key,key不允许重复,
//重新了comparetor,所以他的长度就是key,已经有一个key是3了所以加不进去。
System.out.println("treeSet="+treeSet);
//1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
}
}
运行界面如下所示:
我们将规则进行改变后,如下所示:
package com.rgf.set;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//1.当我们使用无参构造器,创建TreeSet时,仍然是无序的。
//2.我们希望添加的元素按照字符串大小来排序
//3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
//并指定排序规则
TreeSet treeSet = new TreeSet(new Comparator() {
//实现了把匿名对象传给了TreeSet的底层TreeMap的Comparator的一个属性。
@Override
public int compare(Object o1, Object o2) {
//调用String的compareTo方法,进行字符串大小比较
//按照长度大小排序:
return ((String)o2).compareTo((String)o1);
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
treeSet.add("rgf");//加入不进去。相同长度会覆盖前面的。一个大小
//我们所设置的规则为长度相等就是相同的元素。
//这里不进行替换,这相当于是key,key不允许重复,
//重新了comparetor,所以他的长度就是key,已经有一个key是3了所以加不进去。
System.out.println("treeSet="+treeSet);
//1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator。
}
}
运行界面如下所示:
我们发现成功添加了进去。