【TreeSet】的应用及【泛型】高级应用总结

来源:互联网 发布:男生礼物 知乎 编辑:程序博客网 时间:2024/05/18 02:19

一、【基本定义和特点】

TreeSet::这个集合就是为了实现该集合中元素是自然数排序,具有无序性,和不可重复性的特点!

我们来验证一下:

<span style="font-size:18px;"><span style="font-size:18px;">import java.util.*;class TreeSetDemo1 {public static void main(String[] args) {TreeSet ts=new TreeSet();ts.add("abcd");ts.add("bcd");ts.add("accd");ts.add("bdd");ts.add("bdd");ts.add("Acd");//迭代取出Iterator i=ts.iterator();while (i.hasNext()){sop(i.next());}/*执行的结果:Acdabcdaccdbcdbdd可以看出存入的顺序和取出的顺序是无序性,ts.add("bdd")添加了两次,取出只有一个,即是无重复性的反应,OK*/}public static void sop(Object obj){System.out.println(obj);}}</span></span>
因为TreeSet集合是为了实现该集合中元素是自然数排序
这时候应该想到在String类中也有个int compareTo(String str)的方法,
此方法是为了让两个字符串进行自然数排序,返回int类型:负数,正数,和0

二、【TreeSet集合中添加自定义的类】

不用问,肯定知道,都是实现了一个comparable的接口去调用自身的int compareTo(Object obj)

为什么会这样呢?
我们用练习说明:
自定一个学生类,把该学生类添加到TreeSet集合中后,通过年龄去排序出来定义基本的简单类吧:学生类中只有基本的name和age属性为例,最终通过年龄的自然数去排序出来

<span style="font-size:18px;"><span style="font-size:18px;">/*其实:TreeSet的底层数据结构是二叉树comparareTo()方法,返回值是0,是说明元素是相同的……直接删除,不再存入其中【重点】当排序是,主要条件相同时,一定判断一下次要条件*/</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">import java.util.*;//学生类class Student implements Comparable //强制让学生类具备比较性{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}    //去重写接口中compareTo方法,因为这时是先按照年龄去排序的public int compareTo(Object obj){//第一步,按照年龄去排序//第二步,如果年龄相同的情况,再具体判断学生类中的姓名属性去排序,//这时候就交给原来String类中compareTo的方法去自动排序即可//所以://判断添加的类是不是都是学生类,不是就用抛出异常的方式提醒!if (!(obj instanceof Student))throw new RuntimeException("添加的不是学生类对象");//把添加的对象缩小到Student的具体实例话类上进行年龄的判断Student stu=(Student)obj;//按照具体需求去进行if (this.age>stu.age)return 1;if (this.age==stu.age){return this.name.compareTo(stu.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}class  TreeSetAddObject2{public static void main(String[] args) {TreeSet ts=new TreeSet();//把学生实例化对象加入其中ts.add(new Student("wangming",28));ts.add(new Student("wangming",20));ts.add(new Student("wangming",20));ts.add(new Student("zhijie",26));ts.add(new Student("zhiainan",26));ts.add(new Student("yanghua",23));ts.add(new Student("wankez",30));Iterator i=ts.iterator();//迭代的方式取出去遍历就OKwhile (i.hasNext()){Student stu=(Student)i.next();//打印在Student对象在TreeSet集合内部的排序情况sop(stu.getName()+","+stu.getAge());}}public static void sop(Object obj){System.out.println(obj);}}</span></span>
最终的总结:
【默认排序】第一种方式:让元素自身具备比较性;元素需要实现Comparable接口,覆盖compareTo()方法,这种方式的排序也可以说是自然排序,或者是默认排序!
当加入自定的类在TreeSet中,要根据具体的需求去重写实现Comparable接口的方法
compareTo的方法,依次让TreeSet集合的内部去按照需求内容就行排序就行!


三、【比较器的定义】

<span style="font-size:18px;"><span style="font-size:18px;">/*TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的,那样,就需要让集合自身具备比较性这样的话,就在集合才在初始化时就具备比较性!在api文档中查到想让集合自身具有比较性,那样就让要定义一个【比较器】,将比较器对象作为参数传递给TreeSet集合的构造函数中*/import java.util.*;//学生类class Student implements Comparable //强制让学生类具备比较性{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}    //去重写接口中compareTo方法,因为这时是先按照年龄去排序的public int compareTo(Object obj){//第一步,按照年龄去排序//第二步,如果年龄相同的情况,再具体判断学生类中的姓名属性去排序,//这时候就交给原来String类中compareTo的方法去自动排序即可//所以://判断添加的类是不是都是学生类,不是就用抛出异常的方式提醒!if (!(obj instanceof Student))throw new RuntimeException("添加的不是学生类对象");//把添加的对象缩小到Student的具体实例话类上进行年龄的判断Student stu=(Student)obj;//按照具体需求去进行if (this.age>stu.age)return 1;if (this.age==stu.age){return this.name.compareTo(stu.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}class  TreeSetAddObjectSecond3{public static void main(String[] args) {TreeSet ts=new TreeSet(new Mycomparator());//把学生实例化对象加入其中ts.add(new Student("wangming",28));ts.add(new Student("wangming",28));ts.add(new Student("wangming",20));ts.add(new Student("zhijie",26));ts.add(new Student("zhiainan",26));ts.add(new Student("yanghua",23));ts.add(new Student("wankez",30));Iterator i=ts.iterator();//迭代的方式取出去遍历就OKwhile (i.hasNext()){Student stu=(Student)i.next();//打印在Student对象在TreeSet集合内部的排序情况sop(stu.getName()+","+stu.getAge());}} public static void sop(Object obj){System.out.println(obj);}}//自定义比较器class Mycomparator implements Comparator{public int compare(Object o1,Object o2){Student s1=(Student)o1;Student s2=(Student)o2;if (!((s1 instanceof Student) && (s2 instanceof Student)))throw new RuntimeException("注意:要比较的对象不是学生类对象");//这时候,如果对象中两个同学的名字是一样的,那样就需要进一步判断年龄了//所以,这时候就需要对年龄进一步做出判断才行!/*if (kid==0){//对年龄进行判断:if (s1.getAge() > s2.getAge()){return 1;}if (s1.getAge() == s2.getAge()){return 0;}return -1;}return kid;*///做完这根kid的判断之后,发现实际上有另外一种方法,那就是用基本数据类型类去判断更便捷int kid=s1.getName().compareTo(s2.getName());if (kid == 0){return new Integer(s1.getAge()).compareTo(s2.getAge());}return kid;}}</span></span>
四、【泛型的应用】

<span style="font-size:18px;"><span style="font-size:18px;">/*下面用泛型的思想来做按照字符串长度的排序【泛型】定义:在JDK1.5之后:为了提高安全性,所以在定义集合的时候,就必须指定存入集合中元素的类型【格式】将要接受的类型写在“<>”中【好处】1.避免在运行的时候才出现ClassCastException(类型不能转换异常),提前在编译时就能进行提示2.避免强制转换的问题出现,让程序看起来简单明了*/import java.util.*;class GenericityDemo5{public static void main(String[] args) {//在定义集合时就要指定类型,类型写在“<>”中,这里我接受的是字符串类型TreeSet<String> ts=new TreeSet<String>(new MyGenerComparator());ts.add("sjfklasjfs");ts.add("afadfa");ts.add("fasfaewfa");ts.add("asfadsfassfds");ts.add("asfadsfas");//在定义迭代器时,也必须标注才行,这样免得在//while中还要强制转换类型,简化了代码Iterator<String> i=ts.iterator();while (i.hasNext()){//Stirng s=(String)i.next();因为有泛型,就不用这句话,不需要强制转换了sop(i.next());}}public static void sop(Object obj){System.out.println(obj);}}//一样的原理,在定义比较器时,实现的接口Comparator也要指定接受类型class MyGenerComparator implements Comparator<String>{//所以当覆盖方法的时候,就直接用接受到的String类型就行public int compare(String s1,String s2){int num=(new Integer(s1.length())).compareTo (new Integer(s2.length()));if (num==0){return s1.compareTo(s2);}return num;}}</span></span>
泛型的具体事例分析:

<span style="font-size:18px;"><span style="font-size:18px;">/*当不知道需要引用的数据类型是什么时,就需要自定义一个工具类来完成一个万能的自动转换下面以学生和工人类为例:当不知道是接受谁时,这是就可以用泛型的思想来完成*///定义工人类class Worker{}//定义学生类class Student{}//定义一个自己的工具,实现接受后,智能转换的过程//SuperUtil是自己定义的需要接受的引用对象而已class MyUtil<SuperUtil>{private SuperUtil su;//set,get方法很简单,不再介绍了public void setObject(SuperUtil su){this.su=su;}public SuperUtil getObject(){return su;}}class MyGenericity6 {public static void main(String[] args) {//这时指定传入的是如果是Student的类,那么他会自动进行转换,很方便//即便是出错了,也会在编译时报出错误!MyUtil<Student> my=new MyUtil<Student>();my.setObject(new Student());//所以以下就不用进行手动强转了Student s=my.getObject();}}//下面是看一下,没有泛型之前的做法://用的都是Object的基础类接受的引用对象,接受之后,需要自己做对应的强转才能正常使用!//定义工人类/*class Worker{}//定义学生类class Student{}class MyUtil{private Object obj;//set,get方法很简单public void setObject(Object obj){this.obj=obj;}public Object getObject(){return obj;}}class MyGenericity {public static void main(String[] args) {MyUtil my=new MyUtil();my.setObject(new Student());//需要进行手动强转了,否则报错Student s=(Student)my.getObject();}}*/</span></span>

五、【泛型可以应用到类上或者方法上】

<span style="font-size:18px;"><span style="font-size:18px;">/*【泛型应用在方法中的情况】在开发的过程中,还有一种情况,那就是当一个类被确定是,但是其方法中的引用对象是不确定的,这时候也可以用到泛型来定义,在同一个方法中操作不同的引用对象*///实例:class Demo{//定义一个在展示方法中去输出引用对象的简单方法public <T> void showMethod(T t){System.out.println(t);}//定义一个在打印方法中去输出引用对象的简单方法public <Z> void printMethod(Z z){System.out.println(z);}}class MethodGenericity7{public static void main(String[] args) {//在类中不再指定要传入的引用对象Demo d=new Demo();d.showMethod("wangwang");d.showMethod(new Double(89.767));d.printMethod("nihaoma!");d.printMethod(new Integer(99));/*输出结果:wangwang89.767nihaoma!99//这种就是应用同一个方法也能输出不同引用对象的实例*/}}</span></span>

请看实例:

<span style="font-size:18px;"><span style="font-size:18px;">/*之前是把泛型应用到类上或者方法上的例子,同样,泛型能够同时应用到类上和方法上但是需要注意的是:static的方法应用泛型格式上有点不一样!下面以例子具体说明:*/class Demo<T>{//方法show定义的泛型和类上定义的是同一个引用对象,所以在void前面不用再写<T>了public void show(T t){System.out.println(t);}//这是定义了和类不一样的泛型public <Z> void print(Z z){System.out.println(z);}//同理:static方法是永远都不能定义和类一样的泛型引用对象的,即是不能访问类上的泛型对象//当静态方法上访问的对象也不能确定时,定义在static方法就行!public static <X> void staticShow(X x){System.out.println(x);}}class MethodGenerTest8 {public static void main(String[] args) {Demo<String> d=new Demo<String>();d.show("the same with Demo class");//d.show(new Integer(99));//报错,因为该方法的泛型和类一样,是String类型//虽然类中指定了相应的Stirng类型,但是print方法却是可以和类一样,也可以不一样的d.print("the same with Demo class"); //可以跟类泛型一样d.print(new Integer(99)); //可以和类泛型不一样//静态方法的泛型实例d.staticShow("static method");d.staticShow(new Integer(99)); }}/*【总结:】1.泛型可以定义在类上,方法上(静态的方法不能访问类定义的泛型)2.多个方法中(除static方法外)的泛型可以和类泛型一样,也可以不一样!*/</span></span>
六、【泛型应用到接口上的具体分析】

<span style="font-size:18px;"><span style="font-size:18px;">/*那么泛型可以定义在接口上面吗?看实例分析:*///定义一个接口,接口中有一个抽象的方法interface Inter<T>{void show(T t);}//实现该接口的类class InterImpl<T> implements Inter<T>{//覆盖接口中的方法,应该保持泛型和接口一样public void show(T t){System.out.println(t);}//再定义一个和接口中的泛型不一样的方法public <Z> void print(Z z){System.out.println(z);}}class  InterfaceGeneriDemo9{public static void main(String[] args) {//指定该接口的实现类泛型是String类型InterImpl<String> i=new InterImpl<String>();i.show("wangwang");//i.show(new Integer(99));//这样就是错误的,因为show方法定义的是和接口一样的类型i.print(new Integer(99));}}//【总结】泛型是可以用在接口上的</span></span>

七、【泛型的限定】

/*泛型的限定!【限定的种类】1.?这是一个通配符号,可以理解是占位符2.? extends E(上限定):可以接受E类型,或者是E的子类型3.? super E(下限定):可以接受E类型,或者E的父类型*/import java.util.*;//以下第一个程序是自定义一个泛型的方法去迭代取出元素/*class GeneriXianding10{public static void main(String[] args) {ArrayList<String> ss=new ArrayList<String>();ss.add("wangalkjg");ss.add("wasdf");ss.add("wandf");ss.add("wang");ArrayList<Integer> si=new ArrayList<Integer>();si.add(new Integer(89));si.add(new Integer(9));si.add(new Integer(5));si.add(new Integer(2));showCollection(ss);showCollection(si);}public static void sop(Object obj){System.out.println(obj);}//因为都有通过迭代取出的方法,所以定义一个迭代方法的泛型实例就可以取出元素public static void showCollection(ArrayList<?> al){Iterator<?> i=al.iterator();while (i.hasNext()){sop(i.next());}}}*/class Person{private String name;Person(String name){this.name=name;}public String getName(){return name;}}class Student extends Person{Student(String name){super(name);}}class GeneriXianding10{public static void main(String[] args) {ArrayList<Person> al=new ArrayList<Person>();al.add(new Person("wangke"));al.add(new Person("wan"));al.add(new Person("wgke"));//showCollection(al);ArrayList<Student> als=new ArrayList<Student>();als.add(new Student("wangke----1"));als.add(new Student("wan----2"));als.add(new Student("wgke----3"));showCollection(als);//这句话相当于:ArrayList<Person> al=new ArrayList<Student>();//左边是人的总类,而在右边只是人的一个子类(一个实例而已),所以两边类型不匹配//必然报错}public static void sop(Object obj){System.out.println(obj);}//Person写为?也可以实现(所有类型的打印),但是我们需要只是打印Person或者Person的子类//这时候就需要用到 //? extends Person(上限定) 或者 ? super Student(下限定) //只需要把showCollection方法中的Person改为? extends Person就行public static void showCollection(ArrayList<? extends Person> a){Iterator<? extends Person> i=a.iterator();while (i.hasNext()){sop(i.next().getName());}}}

八、【泛型高级应用总结】

/*写一个比较器的泛型实例,最后还是用通用的迭代方法显示出来:*/import java.util.*;//定义了一个父类,人类class Person{private String name;Person(String name){this.name=name;}public String getName(){return name;}}//定义了一个子类学生类class Student extends Person{Student(String name){super(name);}}//定义了一个子类工人类class Worker extends Person{Worker(String name){super(name);}}class BiJiaoQi11{public static void main(String[] args) {//把学生类添加到TreeSet集合中TreeSet<Student> tss=new TreeSet<Student>(new MyComp());tss.add(new Student("abc--1"));tss.add(new Student("abc--2"));tss.add(new Student("abc--3"));tss.add(new Student("abc--4"));//把工人类添加到TreeSet集合中TreeSet<Worker> tsw=new TreeSet<Worker>(new MyComp());tsw.add(new Worker("abc--001"));tsw.add(new Worker("abc--002"));tsw.add(new Worker("abc--003"));tsw.add(new Worker("abc--004"));//调用通用的迭代方式显示不同的类showIter(tss);showIter(tsw);}public static void sop(Object obj){System.out.println(obj);}//定义了一个通用的迭代取出函数//取出的对象是Person的所有子类型public static void showIter(TreeSet<? extends Person> ts){Iterator<? extends Person> it=ts.iterator();while (it.hasNext()){sop(it.next().getName());}}}/*这里很重要:如果Person改写成Student的话,只能比较Student类如果Person改写成Worder的话,只能比较Worder类但是传入的是父类,就意味着可以比较父类的所有子类了【温馨提示】传入的是子类,那就只比较相应的子类,传入的是父类,那就可以比较父类其下的所有子类这就是其 ? super E (下限的具体体现)*/class MyComp implements Comparator<Person>{public int compare(Person p1,Person p2){return p2.getName().compareTo(p1.getName());}}

                                             
0 0