Java基础之集合知识点总结一

来源:互联网 发布:linux系统dd命令 编辑:程序博客网 时间:2024/04/30 17:23


集合是用于存储对象的一个工具。集合和数组的特点:  相同点       集合和数组都一个容器。  不同点:       集合:           1,可以存储对象,只能存储对象。           2,集合的长度的是可变的。       数组:           1,可以存储对象,也可以存储基本数据类型值。           2,数组长度的是固定的。注意:CollectionDemo.java 使用了未经检查或不安全的操作。注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。Java编译器认为该成存在安全隐患。友情提示。但并不是编译失败,所以可以不用理会。其实是因为类型的原因导致的,等到了泛型技术学完,就没有该提示了。
例子1:Collection集合中的几个常用的方法。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Collection;public class CollectionDemo {public static void main(String[] args) {Collection coll = new ArrayList();  //创建一个集合对象,也就是一个容器coll.add("abc1");coll.add("abc2");coll.add("abc3");  //添加集合元素//简单的获取集合中所有的元素,直接将集合元素打印到控制台上System.out.println("集合元素:"+coll);//删除集合元素/*boolean b = coll.remove("abc2");System.out.println("b="+b);System.out.println("删除后集合元素:"+coll);*///获取集合的长度//int size = coll.size();//System.out.println("size="+size);//清除集合中的所有元素//coll.clear();//System.out.println("清除集合中的所有元素:"+coll);//判断集合是否为空//boolean b = coll.isEmpty();  //其实内部依据的是size()方法,如果size()=0,就返回true//System.out.println("b="+b);//判断集合中是否包含一个元素boolean b = coll.contains("abc1");System.out.println("b="+b);}}
例子2:深入了解Collection集合对象的一些方法。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Collection;public class CollectionDemo2 {public static void main(String[] args) {Collection coll = new ArrayList();  //创建一个集合对象,也就是一个容器coll.add("abc1");coll.add("abc2");coll.add("abc5");  //添加集合元素//简单的获取集合中所有的元素,直接将集合元素打印到控制台上System.out.println("集合元素:"+coll);Collection coll2 = new ArrayList();coll2.add("abc3");coll2.add("abc2");coll2.add("abc1");coll2.add("abc4");Collection coll3 = new ArrayList();coll3.add("abc7");coll3.add("abc8");//添加一堆元素//coll.addAll(coll2);  //将coll2中的元素添加到coll集合中。//System.out.println("添加后的集合元素:"+coll);//判断一堆元素是否存在//boolean b = coll.containsAll(coll3);//System.out.println("b="+b);//删除一堆元素//boolean c = coll.removeAll(coll3);  //removeAll会将coll中包含的和coll3相同的元素删除。//System.out.println("c="+c);//System.out.println("删除后的集合元素"+coll);//获取两个集合的交集//retainAll()会将coll和coll2中相同的元素保留在coll中//所以coll中存储的就是交集的元素。当coll集合中的元素发生变化时//retainAll()方法返回true.当coll集合中的元素本身就是交集的元素,//不发生变化,那么返回false.boolean b = coll.retainAll(coll2);System.out.println("b="+b);System.out.println("交集元素"+coll);}}
集合容器都具备取出方式,取出方式并不是一个方法,因为一个方法不足以完成取出,取出是有多个功能而完成,为了方便使用,就将这些功能封装成了对象。该对象在描述时,这些功能会直接使用到具体集合中的数据和集合特点,所以这个取出元素的描述类,就定义在集合内部,也就是一个内部类。因为这个类在直接访问集合中的数据,所以定义在类的内部,根据集合自身的数据结构的特点,将具体的方法都定义完成后,需要将对象对外提供出去,让用户使用,所以就暴露了一个方法,来完成对内部类的访问。为了提高扩展性,发现只要是容器就具备取出功能,但是数据结构不同,取出的具体实现一样,这时为了扩展,就抽取出了一个接口。这个接口就是Iterator。所以每个对象都有返回该Iterator接口的实例。总结    1.  集合容器都具有取出方式。    2.  容器的取出方式都符合一个规则。    3.  每个容器本身都具有自身的数据结构,但是取出的规则都一致。例子说明:机器手臂-取出布娃娃。
例子3:Collection集合中对元素的获取方法。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;/** * Collection集合中对元素的获取方法。 * @author wl-pc*/public class IteratorDemo {public static void main(String[] args) {       Collection coll = new ArrayList();       coll.add("abc1");       coll.add("abc2");       coll.add("abc3");       //只要是Collection集合体系,迭代器就是通用的取出方式。       //Iterator it = coll.iterator();       //while(it.hasNext()){       //System.out.println(it.next());       //}       for (Iterator it = coll.iterator();it.hasNext();) {   System.out.println(it.next());   }}}
例子4:自定义Person对象,定义姓名和年龄,将对象存储进集合中,并取出其姓名或者年龄。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;/** * 练习:自定义Person对象,定义姓名和年龄, * 将对象存储进集合中,并取出其姓名或者年龄。 * @author wl-pc*//** *先要对对象进行描述。 */class Person{private String name;private int age;Person(String name,int age) {this.name=name;this.age=age;}public String getName(){return name;}public int getAge(){return age;}}//add(Object obj)   //可以接收任意类型的对象,但是任意类型的对象被提升为Object//所以在取出元素时,取出来的也是Object.public class CollectionTest {public static void main(String[] args) {//创建一个集合Collection coll = new ArrayList(); //集合中存储的都是集合的引用coll.add(new Person("张三", 24));coll.add(new Person("李四", 34));coll.add(new Person("王五", 44));Iterator it = coll.iterator();  //获取迭代器后,迭代器中持有也是对象的引用。while(it.hasNext()){//在进行迭代使用时,next()方法在循环中,建议只定义一次,定义多时,会导致数据错误。//当next()方法没有获取到的元素时,会发生NoSuchElementException异常。Object object = it.next();Person p = (Person)object;System.out.println(p.getName()+"-----"+p.getAge());}}}
例子5:演示List集合中常见的共性方法
package cn.itheima.day11;import java.util.ArrayList;import java.util.List;/** * Collection *    |--List:该容器的元素是有序的(即存储的顺序和取出的顺序) *            该集合中的元素都是有索引的(也就是角标),该集合可以存储重复的元素。 *    |--Set* List集合中常见的共性方法。 *   1.添加元素。 *   2.删除元素。 *   3.修改元素。 *   4.获取元素。*/public class ListDemo {public static void main(String[] args) {List list = new ArrayList();list.add("abc1");list.add("abc2");list.add("abc3");System.out.println("原集合元素:"+list);//添加功能,在指定的位置插入元素//list.add(1,"haha");  //在1索引处插入元素haha,其他元素依次顺延。//System.out.println("插入后元素:"+list);//按照指定索引删除元素,会返回被删除的元素。//System.out.println("remove(1)"+list.remove(1));//按照指定位置的元素进行修改,会返回被返回的元素。//System.out.println("set(0,wang)"+list.set(0, "wang"));//System.out.println(list);//获取索引元素指定的元素//System.out.println("get(1):"+list.get(1));//通过元素获取到第一次出现的位置//System.out.println("indexOf(abc2):"+list.indexOf("abc2"));//根据头尾角标获取子列表//List newList = list.subList(0, 2); //全取list.subList(0,list.size());//System.out.println("自定义的列表:"+newList);//通过List的特有方式,获取集合中的元素。for(int x=0;x<list.size();x++){System.out.println(list.get(x));}}}
例子6:在迭代集合元素的同时,操作集合元素。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class ListIteratorDemo {public static void main(String[] args) {List list = new ArrayList();list.add("abc1");list.add("abc2");list.add("abc3");list.add("abc4");//这时候有需求,当it.next满足了某些条件,做出一些操作(比如:增加新元素,删除元素)Iterator it = list.iterator();while(it.hasNext()){String s = (String)it.next();if(s.equals("abc2"))//it.remove();list.add("haha");  //会抛出并发修改异常:java.util.ConcurrentModificationExceptionSystem.out.println("s="+s);}System.out.println(list);}}
在进行迭代过程中,如果出现了迭代器和容器同时对元素进行操作的情况很容易引发ConcurrentModificationException并发修改异常.解决方法:要么使用集合的方法操作元素,要么使用迭代器的方法操作元素。不要同时使用。很遗憾的是 迭代器Iterator中只有三个操作,判断hasNext,获取next,删除remove。想要其他的操作时,比如添加,这个迭代器就不可以使用了。这时怎么办呢?注意:对于List集合。有一个新的迭代方式。 就是ListIterator 列表迭代器。ListIterator本身也是Iterator的子接口。并提供了更多的迭代过程中的操作。在迭代过程中,如果需要增删改查元素的操作,需要列表迭代器。但是注意:该迭代器,只能用于List集合。
例子7:演示一下ListIterator列表迭代器的使用方法。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.ListIterator;public class ListIteratorDemo2 {public static void main(String[] args) {List list = new ArrayList();list.add("abc1");list.add("abc2");list.add("abc3");list.add("abc4");//这时候有需求,当it.next满足了某些条件,做出一些操作(比如:增加新元素,删除元素)ListIterator lit = list.listIterator();  //ListIterator列表迭代器,可以有增,删,改,查等操作。while(lit.hasNext()){String s = (String)lit.next();if(s.equals("abc2"))//lit.add("haha");  //添加    lit.set("qq");    //修改System.out.println("s="+s);}boolean b = lit.hasPrevious();  //hasPrevious()有没有前一个集合元素,hasNext()有没有后一个集合元素System.out.println("b="+b);System.out.println(list);}}
List:有序,可重复,有索引。(面试重点)      |--ArrayList:底层数据结构是数组结构。线程不安全的。所以ArrayList的出现替代了Vector.但是查询的速度很快,增删慢.     |--Vector:底层数据结构是数组结构。jdk1.0版本。线程安全的。无论增删还是查询都非常慢。     |--LinkedList:底层是链表数据结构。线程不安全的,同时对元算的增删操作效率很高 可变长度的数组:    ArrayList内部封装了一个默认长度为10的数组。当超出长度时,集合内部会自动生成一个新的数组。将原数组中的元素复制到新数组中,在将新元素添加到新数组。那么,新数组到底多长呢?    一般:ArrayList 50%延长,Vector100%延长。LinkedList的特有方法    1)addFirst();         addLast();在jdk1.6以后。         offerFirst();         offerLast();替代     2)获取元素,集合的长度不改变。如果集合中没有元素,那么该方法会发生异常NoSuchElementException         getFirst():         getLast();在jdk1.6以后。         peekFirst();         peekLast();替代          如果集合元素没有,该方法不会抛出异常,而是返回null。    3)获取元素(指的是删除元素后,元素返回回来显示),但是该元素会被删除出集合,集合的长度会改变。如果集合中没有元素,那么该方法会发生异常NoSuchElementException         removeFirst():         removeLast(); 在jdk1.6以后。         pollFirst();         pollLast();替代         如果集合元素没有,该方法不会抛出异常,而是返回null。
例子8:LinkedList对象的常见方法举例。
package cn.itheima.day11;import java.util.LinkedList;public class LinkedListDemo {public static void main(String[] args) {LinkedList link =new LinkedList();link.addFirst("abc1");link.addFirst("abc2");link.offerFirst("abc3");link.offerFirst("abc4");  //打印abc4  abc3  abc2  abc1//要是用addLast()添加以上的元素时,打印的就是abc1  abc2  abc3  abc4System.out.println(link);//System.out.println("头部元素="+link.getFirst());//System.out.println("尾部元素="+link.getLast());System.out.println("头部元素="+link.peekFirst());System.out.println("尾部元素="+link.peekLast());//System.out.println("删除头部元素="+link.removeFirst());//System.out.println("删除后的头部元素="+link.getFirst());System.out.println("删除头部元素="+link.pollFirst());System.out.println("删除后的头部元素="+link.peekFirst());                //取出元素的方法while(!link.isEmpty()){System.out.println(link.removeFirst());}}}
      Vector中提供了一个独特的取出方式,就是枚举Enumeration。此接口Enumeration的功能与 Iterator 接口的功能是重复的,Enumeration的名称和方法的名称过程,书写很麻烦。所以被Iterator所取代。
例子9: Vector中独特的取出方式实例演示。
package cn.itheima.day11;import java.util.Enumeration;import java.util.Vector;public class VectorDemo {public static void main(String[] args) {        Vector v = new Vector();        v.addElement("abc1");        v.addElement("abc2");        v.addElement("abc3");        v.addElement("abc4");        Enumeration en = v.elements();        while(en.hasMoreElements()){        System.out.println(en.nextElement());        }}}
例子10. 去除ArrayList集合中的重复元素。最好该元素还是自定义的。比如Person,如果同姓名,同年龄视为相同元素。
package cn.itheima.day11;import java.util.ArrayList;import java.util.Iterator;/** * 练习1:去除ArrayList集合中的重复元素。最好该元素还是自定义的。 *           比如Person,如果同姓名,同年龄视为相同元素。 * @author wl-pc *思路:1.定义一个新的ArrayList容器,用于存储不同的元素 *     2.遍历已有的ArrayList,将遍历到的元素存储到新的集合中。 *     3.在把遍历到的元素的存入到新的集合中时,这时要判断该元素 *       是否在新的集合中,如果新集合中存在,则不存入,如果新集合 *       中没有,则存入元素。注意:判断是否存在可以通过contains方法完成 *     4.循环结束,新集合中存储的就是不同的元素。 */class Person1{private String name;private int age;public Person1(String name, int age) {super();this.name = name;this.age = age;}/** * 必须建立Person对象比较是否相同的自定义对象的方式, * 所以不能再使用Object中的equals()方法,而是需要覆盖该方法, * 建立自身的比较相同的依据。 * 标记同姓名,同年龄为相同的对象。 * @return */public boolean equals(Object obj){if(this==obj){return true;}if(!(obj instanceof Person1)){  //instanceof 判断obj是否是Person1的数据类型。return false;}Person1 p = (Person1)obj;return this.name.equals(p.name) && this.age==p.age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return name +"--" + age ;}}public class ListTest {public static ArrayList getSingleElement(ArrayList al){ArrayList newList = new ArrayList();Iterator it = al.iterator();while(it.hasNext()){Object obj = it.next();if(!newList.contains(obj)){   //contains()方法底层依赖的是元素的equals()方法,来判断元素相同                              //Person的equals()方法是从Object中继承而来的,而Object中的equals()方法它比较的是地址值,              //而在new Person()时,每次new一个Person就会有一个新的地址值      newList.add(obj);}}return newList;}public static void main(String[] args) {ArrayList al = new ArrayList();al.add(new Person1("abc3", 23));al.add(new Person1("abc1", 21));//al.add(new Person1("abc3", 23));al.add(new Person1("abc2", 22));//al.add(new Person1("abc1", 21));//al.add(new Person1("abc2", 22));/*al.add("abc1");al.add("abc3");al.add("abc2");al.add("abc3");al.add("abc1");al.add("abc2");*//*ArrayList判断元素是否相同,底层依据的是元素的equals方法。无论是contains,还是remove都会去使用equals判断元素是否相同。所以在往ArrayList集合存储自定义元素时,最好建立该元素特有的判断对象是否相同的依据。也就是需要覆盖equals方法。*/System.out.println(al);//al = getSingleElement(al);//System.out.println(al);boolean b = al.remove(new Person1("abc2", 22));System.out.println(b);System.out.println(al);}}

例子11. 使用LinkedList模拟一个堆栈或者队列数据结构。
                  堆栈结构:先进后出。First In Last Out  FILO                  队列结构:先进先出。First In First Out FIFO 应该定义一个对象,内部使用的LinkedList。 对外提供添加获取的功能,可以完成对应的结构效果。

package cn.itheima.day11;import java.util.LinkedList;/** * 使用LinkedList模拟一个堆栈或者队列的数据结构。 * 特点:堆栈结构:先进后出 *      队列结构:先进先出 * @author wl-pc */class DuiLie{   private LinkedList link;   public DuiLie() {link = new LinkedList();   }   public void add(Object obj){   link.addFirst(obj);   }   public Object get(){  // return link.removeFirst();  //堆栈   return link.removeLast();  //队列   }   public boolean isNull(){   return link.isEmpty();   }}public class ListTest2 {public static void main(String[] args) {         DuiLie dl = new DuiLie();         dl.add("abc1");         dl.add("abc2");         dl.add("abc3");         dl.add("abc4"); while(!dl.isNull()){  System.out.println(dl.get()); }}}

例子12.将字符串中的数值进行排序,生成一个新的字符串原字符串为“90 -1 23 0 8 14”   思路:       1,先要把数值取出。       2,存储到int数组中。       3,对int数组排序。       4,将int数组变成字符串。
package cn.itheima.day11;/** * 例子12.将字符串中的数值进行排序,生成一个新的字符串                 原字符串为“90 -1 23 0 8 14”   思路:1,先要把数值取出。2,存储到int数组中。3,对int数组排序。4,将int数组变成字符串。 */class Tool {// 对数值或字符串进行排序的功能。public static String sortNumberString(String str, String reg) {          String[] arr = splitString(str, reg);          int[] temp = stringToIntArray(arr);          sortArray(temp);          return toString(temp, reg);}// 1.将字符串进行切割,先把数值取出来private static String[] splitString(String str, String reg) {return str.split(reg);}// 2.将字符串数组String[]转成int[]数组。private static int[] stringToIntArray(String[] arr) {int[] temp = new int[arr.length];for (int x = 0; x < arr.length; x++) {temp[x] = Integer.parseInt(arr[x]);}return temp;}// 3.对int数组进行排序private static void sortArray(int[] arr) {// Arrays.sort(arr);for (int x = 0; x < arr.length - 1; x++) {for (int y = x+1; y < arr.length; y++) {if (arr[x] > arr[y]) {int temp = arr[x];arr[x] = arr[y];arr[y] = temp;}}}}// 4.将int数组变成字符串private static String toString(int[] arr, String reg) {StringBuilder sb = new StringBuilder();for (int x = 0; x < arr.length; x++) {if (x != arr.length - 1) {sb.append(arr[x] + reg);} else {sb.append(arr[x]);}}return sb.toString();}}public class Test {public static void main(String[] args) {          String s =Tool.sortNumberString("90 -1 23 0 8 14"," ");          System.out.println(s);}}
例子13,以下是一个多线程的运行实例,要求写出这个线程运行的过程。
package cn.itheima.day11;class MyThread extends Thread{public void run(){try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {}System.out.println("MyThread running");}}public class ThreadTest {public static void main(String[] args) {MyThread t = new MyThread();t.run();t.start();System.out.println("Thread Test");}}  //要求写出运行过程。                                                        /*   当JVM运行ThreadTest类时,就启动了一个主线程,那么主线程执行的代码都在main方法中。     第一条语句:MyThread t = new MyThread();主线程创建了一个线程对象。     第二句:t.run();调用了该对象的run()方法,注意这时,只有一个主线程,这时主线程就到了run方法中行, 当执行到了sleep方法时,主线程会睡眠3秒,这时的程序是没有任何执行。CUP是不处理的当3秒结束后,主线程重新获取执行资格,并获取到执行权后,执行输出语句,打印MyThread running     第三句:t.start();开启了一个线程,这时该线程就多了一个执行路径,该线程要执行的代码都在run()方法中。这一开启就有了两种情况:   情况一:      主线程执行完t.start()方法后,还持有执行权,继续向下执行,将输出语句打印Thread Test,这时主线程结束。这时就只剩下一个线程了Thread-0,它就可以获取执行权,开始执行run()方法,当执行到sleep()时,睡眠3秒,这时程序是不会被运行的,当3秒后,该线程获取执行权,继续执行输出语句,打印MyThread running,该线程Thread-0结束。程序结束。   情况二:          当主线程执行完t.start()方法后,开启一个新的线程Thread-0,这时该线程就具备了执行资格,有可能同时获取到了执行权,那么这时主线程就处于临时阻塞状态,也就是主线程具备着执行资格,但是还没有执行权,Thread-0就到了run()方法中执行,执行到sleep()睡眠3秒,这时Thread-0即释放了执行权,又释放了执行资格,这时,主线程就有机会获取到执行权,并执行main()方法中的输出语句,打印 Thread Test,主线程结束,当Thread-0在3秒后,恢复到临时阻塞状态,就具备了执行资格就有机会获取执行权,然后执行输出语句,打印MyThread running,然后程序结束。   */
Collection     |--List:有序(存储的顺序和取出的顺序一致。)元素可以重复,元素都有索引。           |--ArrayList:           |--LinkedList:     |--Set:无序,不可以重复元素。Set接口的方法和Collection中的方法一致。Set接口取出元素的方法只有迭代器。           |--HashSet:底层数据结构是哈希表。哈希表这种结构,其实就是对哈希值的存储。而且每一个对象都有自己的哈希值。因为Object类中的有一个方法hashCode方法。如何保证元素唯一性的呢?通过判断元素的hashCode方法,和equals方法完成的。当hashCode值相同是,会在判断一次euqals方法的返回值是否为true。如果hashCode值不相同,就确定元素的哈希表中的位置,就不用在判断equals了。哈希表中有一个桶结构。每一个桶都有一个哈希值,当哈希值相同,但是equals为false是,这些元素都存放一个桶里。           |--TreeSet:可以对Set集合中的元素进行排序。数据结构是二叉树数据结构。这种结构,可以提高排序性能。它又是如何保证元素唯一性的呢?            是根据比较方法的返回值确定的。只要返回的是0.就代表元素重复。
例子14:HashSet集合类的使用演示。
package cn.itheima.day12;import java.util.HashSet;import java.util.Iterator;public class HashSetDemo {public static void main(String[] args) {HashSet hs = new HashSet();hs.add("abc2");hs.add("abc1");hs.add("abc3");hs.add("abc1");hs.add("abc3");hs.add("abc2");System.out.println("size:"+hs.size());Iterator it = hs.iterator();while(it.hasNext()){System.out.println(it.next());}}}
HashSet集合是如何保证元素唯一性的?    HashSet集合保证元素唯一性,依赖的是元素的hashCode方法和euqals方法。当元素的哈希值不同时,元素都有自己的独立位置。不需要在判断元素的equals方法,当元素的哈希值相同时,这时元素在哈希表中位置相同,这时就需要再判断一次元素的内容是否相同。就需要调用元素的equals方法进行一次比较。如果equals返回是true。那么视为两个元素为重复元素。只储存一个。如果返回是false,那么这两个元素不是重复元素,会存储在同一个哈希值上。为了建立自定义对象判断元素是否重复的依据。需要覆盖hashCode方法,和equals方法。而且最好依据对象的特有条件来建立hashcode和euqals的实现。
例子15.HashSet中存储自定义的对象,如果姓名和年龄都相同就视为相同对象。就不进行存储了。
package cn.itheima.day12;import java.util.HashSet;import java.util.Iterator;public class HashSetDemo2 {public static void main(String[] args) {//往HashSet集合中存储自定义的对象。HashSet hs = new HashSet();hs.add(new Person("lisi1", 21));hs.add(new Person("lisi6", 26));hs.add(new Person("lisi3", 23));hs.add(new Person("lisi6", 26));hs.add(new Person("lisi5", 25));Iterator it = hs.iterator();while(it.hasNext()){Person p = (Person)it.next();System.out.println(p.getName()+"------"+p.getAge());}}}//这时要求:如果姓名和年龄都相同就视为相同对象。就不进行存储了。class Person{private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}//复写hashCode()方法public int hashCode(){System.out.println(this+"-----hashCode");final int NUMBER = 3; return name.hashCode() + age*NUMBER;//return 1;}//复写equals()方法public boolean equals(Object obj){System.out.println(this+"---equals----"+obj);if(this == obj)return true;if(!(obj instanceof Person))return false;Person p = (Person)obj;return this.name.equals(p.name) && this.age==p.age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return name+"----"+age;}}
总结细节特点:    ArrayList:判断包含,以及删除,都是依据元素的equals方法。    HashSet:判断包含,以及删除,都是依据元素的hashCode方法。当hashCode值相同时,在判断一次equals方法。
例子16.HashSet的remove()方法的使用方法,即特点。
package cn.itheima.day12;import java.util.HashSet;public class HashSetDemo3 {public static void main(String[] args) {//往HashSet集合中存储自定义的对象。HashSet hs = new HashSet();hs.add(new Person1("lisi1", 21));//hs.add(new Person("lisi6", 26));//hs.add(new Person("lisi3", 23));hs.add(new Person1("lisi6", 26));hs.add(new Person1("lisi1", 21));hs.add(new Person1("lisi3", 23));hs.add(new Person1("lisi5", 25));System.out.println("---------------");System.out.println("contains:"+hs.contains(new Person1("lisi6",26)));System.out.println("remove:"+hs.remove(new Person1("lisi1", 21))); System.out.println(hs);}}//这时要求:如果姓名和年龄都相同就视为相同对象。就不进行存储了。class Person1{private String name;private int age;public Person1(String name, int age) {this.name = name;this.age = age;}//复写hashCode()方法public int hashCode(){System.out.println(this+"-----hashCode");final int NUMBER = 3; return name.hashCode() + age*NUMBER;//return 1;}//复写equals()方法public boolean equals(Object obj){System.out.println(this+"---equals----"+obj);if(this == obj)return true;if(!(obj instanceof Person1))return false;Person1 p = (Person1)obj;return this.name.equals(p.name) && this.age==p.age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return name+"----"+age;}}
treeset集合使用于给元素进行排序的那么自定义元素本身不具备比较性,treeset集合是无法对元素进行排序的。所以,在自定义对象时,需要对象具备一个扩展功能,用于比较的,而java已经提供了接口,可以让实现它的对象具备比较性。那么自定义类,要想要被treeset排序,就需要实现Comparable接口。以具备比较功能。比较的时候,要注意,主要条件和次要条件。如果主要条件相同,一定要比较次要条件。
例子17.自定义对象Person,想要对人对象按照年龄的从小到大排序。
package cn.itheima.day12;import java.util.TreeSet;public class TreeSetDemo2 {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Person2("lisi1", 21));ts.add(new Person2("lisi3", 23));ts.add(new Person2("lisi4", 24));ts.add(new Person2("lisi2", 22));ts.add(new Person2("lisi6", 26));ts.add(new Person2("lisi2", 23));System.out.println(ts);}}//这时要求:如果姓名和年龄都相同就视为相同对象。就不进行存储了。class Person2 implements Comparable{private String name;private int age;public Person2(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return name+"----"+age;}@Overridepublic int compareTo(Object obj) {Person2 p = (Person2)obj;//写法一(按面向对象的方式):先比较主要条件,如果主要条件相同时在比较次要条件。//compareTo()按字典的顺序比较两个字符串。int num  =new Integer(this.age).compareTo(new Integer(p.age));return num==0?this.name.compareTo(p.name):num;//写法二:/** * int num = this.age - p.age; * return num==0?this.name.compareTo(p.name):num; *///return 1;}}
当treeset集合中存储的元素不具备比较功能。或者具备的比较功能不是所需要的。例如:Person对象中的自然排序是按照年龄排序。现在需求:但是现在需求是想按姓名排序。改源代码这种方式想都不要想。有这种想法就是犯罪。该如何解决这个问题?既然元素具备的比较方式不满足应用。这时,可以让集合自身具备比较性。需要集合一初始化就具备比较功能。因为要在添加元素前具备。就需要在构造函数进行初始化。只要将一个实现了Comparator接口的子类对象作为参数传递给TreeSet集合的构造函数即可。这样该集合就具备了比较功能。建议使用第二种排序方式。
例子18,定义使用比较器来按照姓名进行对Person排序。
package cn.itheima.day12;import java.util.Comparator;import java.util.TreeSet;public class TreeSetDemo3 {public static void main(String[] args) {TreeSet ts = new  TreeSet(new CompareByName());ts.add(new Person3("lisi1", 21));ts.add(new Person3("lisi3", 23));ts.add(new Person3("lisi4", 24));ts.add(new Person3("lisi2", 22));ts.add(new Person3("lisi6", 26));System.out.println(ts);}}//自定义一个比较器class CompareByName implements Comparator{@Overridepublic int compare(Object o1, Object o2) {Person3 p1 = (Person3)o1;Person3 p2 = (Person3)o2;int num = p1.getName().compareTo(p2.getName());return num==0?p1.getAge()-p2.getAge():num;}}class Person3{private String name;private int age;public Person3(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return name+"----"+age;}}
总结:TreeSet排序方式有两种。      1,让元素自身具备比较性。其实是让元素实现Comparable接口,覆盖compareTo方法,此方法有一个参数。这称为元素的自然排序。      2,当元素自身不具备比较性,或者元素具备的比较性不是所需要的,可以让集合自身具备比较性。定义一个比较器:其实就是定义一个类,实现Comparator接口。覆盖compare方法,此方法有两个参数。将Comparator接口的子类对象作为参数传递给TreeSet的构造函数。当元素自身具备比较性,同时TreeSet集合也具备比较器,这时以比较器为主.到了这里,一般在描述一个对象时,如果该对象封装了具体的数据,会出现很多这样的对象比如:员工,学生对象等.这时就需要进行容器的存储.那么描述该类对象时,一定要复写几个方法.       1,hashCode()       2,equals()       3,toString()前三个方法如果不定义,本身对象中就有,但是,是继承于Object中的,而Object的排序都是按照自身的地址值,是不合适的,所以对象要定义依赖对象自身特征的条件判断。建立自己的特点。       4,最好实现Comparable接口让该类具备自然排序功能。       5.自身的构造函数。建立对象自身判断是否相同的依据,同时让对象具备基本的比较性。
例子19,对字符串进行长度排序,使用TreeSet.
package cn.itheima.day12;import java.util.Comparator;import java.util.Iterator;import java.util.TreeSet;/** * 对字符串进行长度排序,使用TreeSet. * @author wl-pc *  思路: 字符串都是对象,可以存储到集合中。 *        还要对字符串排序,所以选择TreeSet集合。 *         *   注意:字符串本身就具有自然排序,但是是按照字典的顺序。 *        但是,和所需要求不符,这时,就只能使用比较器排序。 */public class TreeSetTest {public static void main(String[] args) {         TreeSet ts = new TreeSet(new CompareByLen());         ts.add("abc");         ts.add("z");         ts.add("na");         ts.add("cccpd");         ts.add("sdssdfs");         ts.add("bca");         Iterator it = ts.iterator();         while(it.hasNext()){        System.out.println(it.next());          }}}//定义一个按照字符串长度排序的比较器。class CompareByLen implements Comparator{@Overridepublic int compare(Object o1, Object o2) {String s1 = (String)o1;String s2 = (String)o2;//方法一//int num = s1.length() - s2.length();//return num==0?s1.compareTo(s2):num;//方法二int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));return num==0?s1.compareTo(s2):num;}}






0 1
原创粉丝点击