一.
接下来讲解set中的常用子类treeset,演示一下treeset的特点。
集合讲述到这里,谈论的都是不同集合内部的数据结构。
这里必须采用迭代器输出,输出的结果是无序的。看到的存进去和取出来的是不一致的,但是取出来的结果有些规律,按照字符的首字母排序来输出。
这个我们不称之为有序,是有指定顺序,按照元素的字典顺序排列。
看下treeset的特点,
既然我们往里面存了一些字符串了,输出的时候,也按照字典的顺序排列完了。下面就要存储一些自定义对象。
结果显示错误,(按照之前的写法出错),类型转换异常。
第19行,wangwu出现了错误。如果只保留zhangsan那一行,结果没有问题。保留两行还是出错,
treeset集合干嘛的?给元素排序用的,排序就必然意味着比较。只存一个对象,不用比较。存两个对象就要比较。
保留两行的时候,比不了,因为这个person类没有比较功能。有人说写了equals,这里需要的是比较,而不是判断相同。比较是要分大小的,情况不是两种,是三种的。
我们现在看一下,java.lang.Comparable到底是什么。
读了上面的截图,有什么感受?person正常描述人这类事物,该有什么描述什么。描述完了以后,我现在要把person放到treeset集合中进行排序。你觉得person
是不是应该在已具备的基本功能之外,要具备一个扩展功能就是比较(为什么不是treeset集合掌握这个功能呢?)。这个比较怎么来呢?它本身已经被定义在congparable接口当中,如果你想让人具备比较性,只要对人进行一个功能扩展,让其实现comparable接口,就具备了比较功能。
人需要进行比较,因此要实现comparable(在eclipse中大小写都可以,名字太长的可以采用out+斜线)
要先继承后实现,不写继承object也行。person类中覆盖了Comparable接口中的copareTo方法。这里返回的是int,对象比较返回的是什么结果?不要说成-1,那其实是负数,数字随时可以变化的。
现在回过来看原先的例子,输入五个元素,看下图,结果没有错误。
输出只有一个,但是没有报错。我们将wangwu换到第一个添加位置,结果只输出wangwu。先存的是wangwu,当存储zhangsan的时候,它和wangwu一比,返回的是0,返回0意味着这两个元素相同,而treeset集合是set集合的一个子类,它们都有一个共性特点,叫做保证元素的唯一性。
treeset和hashcode,equals有关系么?一点关系都没有,例子开始时,就有hashcode和equals两个方法,输出也是报错,也没行。
treeset集合根本就不看hashcode和equals,而正因为写了一个compareto方法,并返回了0,它就视为下面的元素和wangwu相同。所以treeset集合判断元素唯一性的方式特别简单,就是根据.....
因为结构不一样,和其它容器全不一样,treeset就看比较结果,只要是0,就按相同算。
有人说,不能这么算,得写一些具体的,意思是说,上面解决异常的操作太粗糙了。没有用到对象自身的一些特性,直接compareto得到0,现在想要精细一些。
把person存到treeset中,没有说要按照什么明确的需求排,这就是问题。
人这个类既有姓名,又有年龄,按照什么方式排序没有明确过,这是问题。现在,我们开始明确,以person对象的年龄按照从小到大来进行排序。也就是说我们要将这个要求写在person的compareto方法里。要是返回0,那么所有元素都相同,那肯定是不行的。
我们先要转换对象类型,有人说这里需要进行判断。这里就不用了,以后会进行统一的改观。现在先简化地写一下,判断肯定是需要地。凡是类型强转,尤其是引用数据类型之前,一定要先加健壮性判断(instanceof),否则会发生classcast异常。下面就是将person类中的compareto方法进行复写的结果。
按照年龄比较的结果来存储数据到集合中。最终显示是可以的,这是分布在两个class文件中的代码,treeset应该还有其它的限制条件,不仅仅是目前compareto方法中的比较年龄。
我们看输出的结果是从小到大的,如何将其调整为从大到小。将return中的-1和1调换一下。还有另一种方法,将this和p调换一下。后期有一种对顺序进行逆转的动作,源码中return中的-1和1,以及<和>都是很难改变的,但是this和p是引用变量,方法修改。
排完序后,对程序进行修改,将其中的两个自定义对象的年龄设置成一样的。
结果中zhouqi不在了,wangwu还在。原因是什么?在compareto方法的定义中,zhouqi和wangwu的年龄既不大于,也不小于,是等于。那么这两个元素就是一样的,是同一个对象,这样zhouqi就被取消了。
有人说这个判断少一步,当年龄判断相同的时候,应该再判断一次姓名。
注意,我们在写这个比较动作的时候,我们通常依据的条件都不唯一,叫做有可能有主要条件的同时,还存在着次要条件。叫做如果主要条件相同,继续按照次要的条件继续进行比较。
有的条件不唯一,那就继续写(说的都是compareto方法体中的定义)。如果年龄排不了了,那就按照姓名排。姓名是字符串,字符串本身具备着compareto的方法,
它的这个方法也来自与comparable接口。只要对象想要进行比较,就实现这个comparable接口(统一接口)。
但是这两种写法不太好,换种简单的写法。
修改完之后,wangwu和zhouqi都出现了,并且wangwu排在前面。
上面讲述的就是treeset可以对元素进行排序的操作。为什么刚才往里面存储字符串就可以排序呢?因为字符串本身就实现了comparable。