day15TreeSet,二叉树原理,比较器,泛型,自定义泛型
2013-05-23 11:13
302 查看
/* TreeSet,二叉树原理,比较器,泛型,自定义泛型 */ /* |--Set:元素是无序的(存入和取出的顺序不一致),元素不可重复 |--HashSet:底层数据结构是哈希表。线程是非同步的。 是如何保证元素的唯一性的呢?(依据) 判断是通过元素的两个方法,先判断hashCode,如果相同,再判断equals来完成 如果元素Hashcode一样,才会判断equals是否为真 如果元素的Hashcode不同,不会调用equals. 注意,对于判断元素是否存在,以及删除等操作,依赖hashCode和equals方法来完成 |--TreeSet:可以对Set集合中的元素进行排序。 底层数据结构是二叉树。 保证元素唯一性的依据 compareTo方法,相同return 0 ; 二叉树存:大的在右下,小的在左下。 取值:先取小的,再取大的 排序技巧:当compareTo()总是返回1:正序。就是和存入顺序一样了。 返回-1,逆序。 TreeSet排序的第一种方式。让元素自身具备可比性 元素需要实现Comparable接口,覆盖compareTo方法 这种方式就是元素的自然顺序。 TreeSet的第二种排序方式。比较器 当元素自身不具备比较性时,或者具备的比较性不是所需要的 这时就需要让集合具备比较性。 定义一个类,实现Comparator接口,覆盖compare方法。 在集合初始化时,传入这个类的对象,就有了比较方式。 TreeSet ts = new TreeSet(new Mycompare()); Set集合的功能和Collect是一致的, 哈希表存对象。 先比较哈希值,如果相同,再比较对象equals。 练习需求:往TreeSet集合中存储自定义对象学生 想按照学生的年龄进行排序。 comparable compareTo , comparator compare 记住。排序时,当主要条件相同时,按照次要条件再排序。 */ import java.util.*; class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Student("lisi02",22));//为什么存一个没事?存二个就出错? //向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。 ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi01",40));//如果年龄相同,那么存不进去?判断唯一性。 Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); //System.out.println(it.next()); } } } class Student implements Comparable//该接口强制让学生具备比较性 { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } public int compareTo(Object obj)//覆盖接口方法 { if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student)obj; System.out.println(this.name+".compareto."+s.name); if(this.age>s.age) return 1; if(this.age == s.age) //return 0;当年龄相同,再判断姓名。主副条件 { return this.name.compareTo(s.name);//String也实现了此接口 } return -1; } public String getName() { return name; } public int getAge() { return age; } } import java.util.*; /* TreeSet的第二种排序方式。 当元素自身不具备比较性时,或者具备的比较性不是所需要的 这时就需要让集合自身具备比较性。 构造函数:在集合初始化时,就有了比较方式。 当二种都存在时,以比较器为主(好)。 比较器类:定义一个类,实现Comparator接口,覆盖compare方法。 我们发现,当我们定义一个学生类时,要有自己的hashCode,equals,compareTo方法, 当然还有toString方法。 */ class TreeSetDemo2 { public static void main(String[] args) { TreeSet ts = new TreeSet(new Mycompare());//以比较器为主 ts.add(new Student("lisi02",22));//没有比较器时,为什么存一个没事?存二个就出错? //向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。 ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi01",40));//如果年龄相同,那么存不进去?Set是无序,元素不重复。 Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); //System.out.println(it.next()); } } } class Mycompare implements Comparator//比较器方式 { public int compare(Object o1,Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int num = s1.getName().compareTo(s2.getName());//按名字排序 if (num==0)//名字相同,再比较年龄 { return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); } return num; } } class Student implements Comparable//该接口强制让学生具备比较性 { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } public int compareTo(Object obj) { if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student)obj; //System.out.println(this.name+".compareto."+s.name); if(this.age>s.age) return 1; if(this.age == s.age) //return 0;当年龄相同,再判断姓名。 { return this.name.compareTo(s.name);//String 也实现了此接口 } return -1; } public String getName() { return name; } public int getAge() { return age; } } /* 练习:按照字符串长度排序 字符串本身具备比较性。但这个排序方式不是我们想要的 */ import java.util.*; class TreeSetTest { public static void main(String[] args) { TreeSet ts = new TreeSet(new StrLenComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("z"); ts.add("hahaha"); Iterator it = ts.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } class StrLenComparator implements Comparator { public int compare(Object o1,Object o2) { String s1 = (String)o1; String s2 = (String)o2; /* if(s1.length()>s2.length()) return 1; if(s1.length()==s2.length()) return 0; return -1; *///为什么不相接用int比较?那不是对象,没有compareTo方法。 int num = new Integer(s.length()).compareTo(new Integer(s2.length())); if(num ==0) { return s1.compareTo(s2); } return num; } } /* 泛型:jdk1.5版本以后出现的新特性,用于解决安全问题, 是一个类型安全机制。 好处: 1.把运行时出现的ClassCastException问题放到编译时. 让程序员解决问题,减少安全问题。 2.避免了强制转换的麻烦。 泛型格式:通过<>来定义要操作的引用数据类型 在使用java提供的对象时,什么时候写泛型呢? 在集合框架中很常见。 只要有<>就要定义泛型。 其实<>就是用来接受类型的。 当使用集合时,将集合中要存储的数据类型作为参数 传递到<>中就可以了。 类似数组一样。 装入时候明确要装入的<类型>。 ArrayList<String> al = new ArrayList<String>(); */ class GenericDemo { public static void main(String[] args) { ArrayList<String> al = new ArrayList<String>(); al.add("abc01"); al.add("abc0001"); al.add("abc014"); //al.add(4);问题所在。编译可以通过,运行出问题。 Iterator<String> it = al.iterator(); while(it.hasNext()) { String s = it.next();//2避免了强制转换的麻烦。 System.out.println(s+":"+s.length()); } } } //------下面是泛型一个例子。字符串长度排序。 import java.util.*; class GenericDemo2 { public static void main(String[] args) { TreeSet<String> ts = new TreeSet<String>(new StrLenComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("z"); ts.add("hahaha"); Iterator<String> it = ts.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } class StrLenComparator implements Comparator<String> { public int compare(String o1,String o2)//当类上加上<String>,此处不是Object了 { int num = new Integer(o1.length()).compareTo(new Integer(o2.length())); if(num == 0) { return o1.compareTo(o2); } return num; } } /* 自定义泛型类 我们能不能在自己定义的类中使用泛型来完成程序设计呢? 什么时候使用泛型类: 当类中要操作的引用数据类型不确定的时候, 早期定义Object来完成扩展。现在定义泛型来完成扩展。 只能是引用的,基本数据类型定义不了, 基本数据类型比如说char类型, 本来就是char了,就不能再用泛型规范了。 泛型方法: 泛型除了可以定义在类上,还可以定义在方法上。 泛型类定义的泛型在整个类中有效。如果被方法使用, 那么如果泛型类的对象已经明确操作的具体类型后,所 有要操作的类型就已经固定了。 class Tool { private Worker w; public void setWorker(Worker w) { this.w = w; } public Worker getWorker() { return w; } }第一次 */ /* class Worker { } class Tool { private Object obj; public void setObject(Object obj) { this.obj = obj; } public Object getObject() { return obj; } }第二次 class Student { } class GenericDemo3 { public static void main(String[] args) { Tool t = new Tool(); t.setObject(new Student()); //不小心传了学生,编译通过,运行出错。 //这时自己明确传什么,拿什么。 Worker w = (Worker)t.getObject(); } } */ //以上是早期做法,是可以的,得有强转。 //对象都是后过来的,泛型之前用object //避免一个类要一个工具类操作 //我要操作对象,什么类型不确定。 //由对方来指定要操作什么类型的对象 class Utils<QQ>//泛型类 { private QQ q; public void setObject(QQ q) { this.q = q; } public QQ getObject() { return q; } } class Student { } class GenericDemo3 { public static void main(String[] args) { /* Tool t = new Tool(); t.setObject(new Student()); //不小心传了学生,编译通过,运行出错。 //这时自己明确传什么,拿什么。 Worker w = (Worker)t.getObject(); */ Utils<Worker> u = new Utils<Worker>();//泛型 u.setObject(new Worker()); Worker w = u.getObject();//可以不用强转,传入其他的就失败。 } } /*泛型方法*/ class GenericDemo4 { public static void main(String[] args) { /* Demo<Integer> d = new Demo<Integer>(); d.show(new Integer(4)); d.print(9); 定义在类上时 */ Demo d = new Demo(); d.show("haah"); d.show(new Integer(4)); d.print("heihei"); } } class Demo { public <T> void show(T t)//<T>定义在方法上,<T>只在方法中有效 { System.out.println("show:"+t); } public <Q> void print(Q q)//这里写<T>也可以 { System.out.println("print:"+q); } } /* class Demo<T>//泛型定义在类上 { public void show(T t) { System.out.println("show:"+t); } public void print(T t) { System.out.println("print:"+t); } //以前要明确操作类型,现在可以这样写,传什么都行。 //泛型类的局限性:当new一个对象时,已经定义类型了。 //Demo<Integer> d = new Demo<Integer>(); //泛型类定义的泛型在整个类中有效。如果被方法使用, //那么如果泛型类的对象已经明确操作的具体类型后,所 //有要操作的类型就已经固定了。 //为了让不同方法可以操作不同类型,而且类型还不确定。 //那么可以将泛型定义在方法上。public <T> void print(Q q) 泛型类和方法可以同时定义。 } */ /*特殊之处: 当类有静态方法时,不可以访问在类上定义的泛型。 如果静态方法操作的引用数据类型不确定, 可以将泛型定义在方法上。因为静态方法先加载。 public static <W> void method(W w) {//注意泛型方法书写格式,<W>在void前,返回类型前。 System.out.println("method" + w); } */ /* 泛型接口:如果类不能确定自己要传什么,也可以定义泛型 */ interface Inter<T> { void show(T t); } /* class InterImpl implements Inter<String> { public void show(String s) { System.out.println("show"+s); } }//第一种 */ //后来我自己也不知道自己要传什么类型, //子类也不知道,由调用者来指定 class InterImpl<T> implements Inter<T> { public void show(T t) { System.out.println("show:"+t); } } class GenericDemo5 { public static void main(String args[]) { //InterImpl i = new InterImpl(); //i.show("haha"); InterImpl<Integer> i = new InterImpl<Integer>(); i.show(4); //由调用者自己指定Integer } } /*import java.util.*; <T>具体类型。<?>占位符,通配符。 <?>不明确类型,iterator时不能打印it.next().length(). ArrayList<Person> al = new ArrayList<Student>(); 这是不允许的。左右二边要一致。泛型没有继承关系。 泛型的限定: 1.?extends E:可以接收E类型或者E的子类型。上限 2.?super E:可以接收E类型或者E的父类型。下限。 */ class GenericDemo6 { }
相关文章推荐
- [javase]自定义泛型比较器 排序
- 黑马程序员------Java的泛型(原理应用、自定义泛型)
- 泛型第四课,自定义实现迭代器、深入迭代器、迭代器原理,面向对象
- 算法:comparable比较器的排序原理实现(二叉树中序排序)
- 关于MapReduce中自定义带比较key类、比较器类(二)——初学者从源码查看其原理
- 利用二叉树彻底弄懂[汉诺塔]递归原理
- SpringBoot之@EnableAutoConfiguration原理及自定义扩展
- java 中泛型的原理以及应用场景
- Java记录 -74- 自定义泛型
- C#自定义泛型
- struts2结果集原理和自定义结果集 如果result标签中写了其他内容该怎么写跳转页面
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- Android 自定义View原理
- TreeSet自定义比较器实现Comparator接口,覆盖Compare方法
- 自定义比较器JAVA和C#版本
- 浅谈JavaScript--Array数组sort()排序方法与自定义比较器的使用
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- 自定义的泛型类和泛型约束
- Android 自定义进度条ColorfulProgressBar,原理简单、效果很棒
- 【自定义标签开发】02-自定义标签运行原理