一. TreeSet 元素之间是有序的
1 package com.sort; 2 3 import java.util.Set; 4 import java.util.TreeSet; 5 6 public class TestTreeSet { 7 8 /** 9 * 10 * @param args 11 */ 12 public static void main(String[] args){ 13 Set set = new TreeSet(); 14 set.add(null); 15 set.add("1"); 16 set.add("2"); 17 set.add("3"); 18 set.add(new Dog(1,"aa")); 19 set.add(new Dog(2,"bb")); 20 set.add(new Dog(3,"cc")); 21 System.out.println(set); 22 23 } 24 }
此段代码报错, 原因是TreeSet是有序的, 会对他们的自然顺序进行排序, 由于第14行加进去的是null, 而15行加进去的是"1", null 和 "1"无法进行比较, 所以编译器报错.
同理, 在第15~17行, 和第18~20行中, 字符串和对象又不能进行比较, 所以编译器又报错.
现在注释掉, 如下代码:
package com.sort; import java.util.Set; import java.util.TreeSet; public class TestTreeSet { /** * * @param args */ public static void main(String[] args){ Set set = new TreeSet(); //set.add(null); set.add("1"); set.add("2"); set.add("3"); //set.add(new Dog(1,"aa")); //set.add(new Dog(2,"bb")); //set.add(new Dog(3,"cc")); System.out.println(set); } }
运行结果:
[1, 2, 3]
我们把加入顺序改一下
set.add("2"); set.add("3"); set.add("1");
结果还是:
[1, 2, 3]
由此可见, TreeSet会对加入的元素进行排序后输出, 比较的机理是对字符串的ASCALL码进行比较!
我们再来看下面的代码:
package com.sort; import java.util.Set; import java.util.TreeSet; public class TestTreeSet { public static void main(String[] args){ Set set = new TreeSet(); //set.add(null); //set.add("2"); //set.add("3"); //set.add("1"); set.add(new Dog(1,"aa")); set.add(new Dog(2,"bb")); set.add(new Dog(3,"cc")); System.out.println(set); } }
这里面无法编译成功, 说明Dog这个对象无法进行排序, 那么, 有个问题, String也是一个类, 那么它的对象 "1""2""3"怎么可以进行排序比较呢?
查看String的源码:
可以看出有个 java.lang.Comparable 实现了这个接口.
我们查看文档: 对于Comparable这个接口实现类的一些说明, 有如下说明:
public interface Comparable<T> 此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
方法是:
compareTo int compareTo(T o) 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
为了能对Dog这个对象进行比较, 要在Dog类中实现Compare接口的方法, Compare的方法是CompareTo
补充知识点: java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。 用法: result = object instanceof class 参数: Result:布尔类型。 Object:必选项。任意对象表达式。 Class:必选项。任意已定义的对象类。 说明: 如果 object 是 class 的一个实例,则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例,或者 object 是 null,则返回 false。
在Dog.java 类中, 代码如下:
package com.sort; public class Dog implements Comparable { int dogid; String dogName; public Dog(int dogid, String dogName) { this.dogid = dogid; this.dogName = dogName; } public int compareTo(Object obj){ if (obj == null){ return -1; //对象是空的,那么就排在前面 }else{ //如果obj是Dog的一个实例(对象) if (obj instanceof Dog){ //虽然obj是Dog的一个实例, 但是obj是定义为一个Object对象,所以强制转换成Dog类 Dog tempDog = (Dog) obj;//强制转换 if (this.dogid == tempDog.dogid){ return 0; }else if (this.dogid < tempDog.dogid){ return -1; }else { return 1; } } } return 0; } }
运行结果:
[com.sort.Dog@659e0bfd, com.sort.Dog@2a139a55, com.sort.Dog@15db9742]
看不出哪个是哪个, 那么, 重写一下toString方法:
package com.sort; public class Dog implements Comparable { int dogid; String dogName; public Dog(int dogid, String dogName) { this.dogid = dogid; this.dogName = dogName; } @Override public String toString() { return super.toString() + "[id = "+ dogid + dogName + "]"; } public int compareTo(Object obj){ if (obj == null){ return -1; //对象是空的,那么就排在前面 }else{ //如果obj是Dog的一个实例(对象) if (obj instanceof Dog){ //虽然obj是Dog的一个实例, 但是obj是定义为一个Object对象,所以强制转换成Dog类 Dog tempDog = (Dog) obj;//强制转换 if (this.dogid == tempDog.dogid){ return 0; }else if (this.dogid < tempDog.dogid){ return -1; }else { return 1; } } } return 0; } }
运行结果:
[com.sort.Dog@659e0bfd[id = 1aa], com.sort.Dog@2a139a55[id = 2bb], com.sort.Dog@15db9742[id = 3cc]]
改变一下顺序, 打印出来的结果相同.
再来看一下 TreeSet 的一个性质, 看如下代码:
1 package com.sort; 2 3 import java.util.Iterator; 4 import java.util.Set; 5 import java.util.TreeSet; 6 7 public class TestTreeSet { 8 9 public static void main(String[] args){ 10 11 //TestTreeSet.onemathod(); 12 TestTreeSet.twomathod(); 13 } 14 15 private static void twomathod() { 16 TreeSet treeset = new TreeSet(); 17 treeset.add("4"); 18 treeset.add("2"); 19 treeset.add("1"); 20 treeset.add("3"); 21 treeset.add("1"); 22 //System.out.println(treeset); 23 Iterator iterator = treeset.iterator();//迭代器 24 while(iterator.hasNext()){ 25 System.out.print(iterator.next() + " "); 26 } 27 } 28 29 private static void onemathod() { 30 Set set = new TreeSet(); 31 //set.add(null); 32 //set.add("2"); 33 //set.add("3"); 34 //set.add("1"); 35 set.add(new Dog(1,"aa")); 36 set.add(new Dog(2,"bb")); 37 set.add(new Dog(3,"cc")); 38 System.out.println(set); 39 } 40 }
看到第16到21行, 其中有两个1, 但是结果是:
1 2 3 4
因为TreeSet继承与Set, 所以它也有Set的这个性质.
二. TreeMap
TreeMap.put("键值", "值");
package com.sort; import java.util.TreeMap; public class TestTreeMap { public static void main(String[] args){ TreeMap treemap = new TreeMap(); treemap.put("1", "我"); treemap.put("3", "的学生"); treemap.put("2", "是福建师范大学"); System.out.println(treemap); } }
运行结果:
{1=我, 2=是福建师范大学, 3=的学生}
同样的, 只能进行相同类型的比较, 不能在键值中比较 整型 和 字符型.
总结:
TreeSet的特点: 只能加入相同的对象类型。
加入的对象必须实现Comparable接口。
不是线程安全的集合类
TreeMap的特点:键只能是相同的对象类型。
加入的键对象必须实现Comparable接口。
不是线程安全的集合类。
下面来说明一下, 使用TreeSet, 顺序都是从 小到大的ASCALL 码进行排序, 可否让它按照其他顺序进行排序呢? 有一种方法, 就是对Comparable 的实现方法进行重写, 但是这样不是有效的方法, 所以, 我们可以用Comparator来实现这个方法.
在文档中查看Comparator接口
public interface Comparator<T> 强行对某个对象 collection 进行整体排序 的比较函数。
再看看它的方法:
方法摘要 int compare(T o1, T o2) 比较用来排序的两个参数。 boolean equals(Object obj) 指示某个其他对象是否“等于”此 Comparator。
根据文档中的这些说明, 我们可以进行代码的编写来实现那个从大到小的编程:
新建一个类来实现Comparator接口的compare方法
StringComparator.java
package com.sort; import java.util.Comparator; //重新建立一个类, 来实现Comparator这个接口 public class StringCompartor implements Comparator { public int compare(Object obj1, Object obj2){ String str1 = (String)obj1; String str2 = (String)obj2; //因为是逆序, 所以只要返回正序的compareTo的相反值就可以 return -(str1.compareTo(str2)); } }
Main函数:
package com.sort; import java.util.TreeSet; public class TestTreeSet2 { public static void main(String[] args){ /* TreeSet的构造方法摘要 TreeSet() 构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。 TreeSet(Collection<? extends E> c) 构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。 TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。 TreeSet(SortedSet<E> s) 构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet。 */ StringCompartor stringcomparator = new StringCompartor(); TreeSet treeset = new TreeSet(stringcomparator);//TreeSet构造方法的第三个 treeset.add("2"); treeset.add("1"); treeset.add("3"); System.out.println(treeset); } }
运行结果:
[3, 2, 1]
总结:
Comparable:内部比较器
内部比较器,当对象加入有序的集合。
Comparator:外部比较器
外部比较器:当改变内部已经排好序的对象。或者原先的对象没有Comparable。