Java基础<十一>--->集合之List、Set

来源:互联网 发布:ubuntu 删除文件夹 编辑:程序博客网 时间:2024/06/10 17:17

第一 集合框架的概述

一、概述:

1、简述:所谓集合就是为了方便操作多个对象,对对象进行存储的一种容器。

2、集合和数组的区别:数组虽然可以存储对象,但是长度是固定的;集合长度是可变的,数组中能存储基本数据类型,集合只能存储对象。

3、集合只用于存储对象,集合长度可变,集合可以存储不同类型的对象。

4、数据结构:由于每种容器对数据的存储方式都各不相同,所以出现了不同的容器,且每种容器都有自己特有的数据结构。
二、集合体系图:


三、List、Set集合的共性方法:

从上图可以看出List和Set的父类是Collection,所以Collection所具备的方法就是他们所共有的共性方法

Collection定义了集合框架的共性功能。

1、添加  add(e);添加一个元素        addAll(collection);添加一组collection中所有元素

2、删除  remove(e);删除一条元素       removeAll(collection);删除一组collection中所有元素clear();清空集合
3、判断。contains(e);是否包含某个元素 isEmpty();判空
4、获取 iterator();迭代器,通过迭代的方式获取集合中的每个元素,简单的说就是遍历集合。size();集合的大小,也就是获取集合中的元素个数。
5、获取交集。 retainAll();
6、集合变数组。 toArray();

import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;public class CollectionDemo {public static void main(String[] args) {ArrayList<String> arrList = new ArrayList<String>();arrList.add("java01");arrList.add("java02");arrList.add("java03");arrList.add("java04");get_method(arrList);c_method(arrList);}private static void get_method(Collection<String> c){print(c);/*Iterator<String> it = c.iterator();while(it.hasNext()){print(it.next());}*///for循环的方式在内存中稍优于while,因为for循环中的局部变量随着for循环的消亡而消亡for(Iterator<String> itr=c.iterator(); itr.hasNext(); ){print(itr.next());}}private static void c_method(Collection<String> c){//print(c);//c.remove("java04");//当清除的内容不存在时,返回原集合//ArrayList<String> arl = new ArrayList<String>();//arl.add("java01");//arl.add("java02");//c.removeAll(arl);//c.clear();//清空集合。//print(c);print(c.contains("java01"));//是否包含print(c.isEmpty());//判空print(c.size());//长度for(int x=0; x<c.toArray().length; x++){System.out.println("collection toarray: " + c.toArray()[x]);}}private static void print(Object obj){System.out.println(obj);}}

四、Collection接口包含的子类:
Collection接口包含最常用的子类是List与Set
List:元素是有序的,元素可重复,因该集合体系有索引
Set:元素是无序的,元素不可重复
五、迭代器:
因为每种容器的数据结构都不同,所以取出的细节也就不同,所以就把迭代器定义在容器的内部,方便于访问集合内部的元素。然而他们也有共性内容就是判断和取出,就对其进行了抽取就成了Iterator接口,就可以通过Iterator的判断取出方式就可以对元素取出。在迭代时next()最好只调用一次,因为集合中的元素是奇数次的话,就会发生异常,所以具有安全隐患。
注意:1、add方法的参数类型是Object。以便于接收任意类型对象。
           2、集合中存储的都是对象的引用(地址)

第二 List集合

一、概述:

1、常见的list集合有ArrayList、LinkedList以及Vector等

2、特点:元素是有序的元素可以重复,因为该集合体系有索引。

3、List集合中常见的子类说明:

1)ArrayList:底层数据结构是数组结构。特点,查询速度很快,但增删稍慢,线程不同步。

2)LinkedList:底层使用的是链表数据结构。特点,增删速度很快,查询稍慢,线程不同步。

3)Vector:底层是数组数据结构,线程同步,被ArrayList取代,因为它的效率低。

ArrayList和Vector初始化长度都是10,当超过时,arraylist每次增加5(节约空间),而vector每次增加10

二、List集合特有的方法:

注:凡是可以操作角标的方法都是该体系特有的方法。

增:add(index,element);在指定位置添加元素   addAll(index,Collection);在指定位置上添加一组元素

删:remove(int index)移除指定位置上的元素

改:set(int index,E element)修改指定位置上的元素

查:get(index)获取指定位置上的元素。subList(from,to)获取子list。listIterator其中提供取出数据时对数据操作一些特有方法。indexOf(obj):获取指定元素的位置

1、listIterator是List特有的迭代器,是Iterator子接口。在迭代时,不可通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModficationException异常。所以,在迭代时,只能用迭代器的方法操作,可Iterator方法是有限的,若想要其他操作如增删改写等,就需要使用子接口,即ListIterator,该接口只能通过List集合的listIerator方法获取。
2、在迭代时,循环中的next()调用一次,就要对hasNext判断一次,不可判断一次调用两次。
3、List集合判断元素是否相同,依据的是元素的equals方法,其中,contains和remove中就是调用的equals方法。
import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void method(){ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//在指定位置添加元素。al.add(1,"java09");//删除指定位置的元素。//al.remove(2);//修改元素。//al.set(2,"java007");//通过角标获取元素。sop("get(1):"+al.get(1));sop(al);//获取所有元素。有序的就可以用这样的取值方式for(int x=0; x<al.size(); x++){System.out.println("al("+x+")="+al.get(x));}Iterator it = al.iterator();while(it.hasNext()){sop("next:"+it.next());}//通过indexOf获取对象的位置。sop("index="+al.indexOf("java02"));List sub = al.subList(1,3);sop("sub="+sub);}public static void main(String[] args) {//演示列表迭代器。ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop(al);ListIterator li = al.listIterator();//sop("hasPrevious():"+li.hasPrevious());while(li.hasNext()){Object obj = li.next();if(obj.equals("java02"))//li.add("java009");li.set("java006");}while(li.hasPrevious()){sop("pre::"+li.previous());}//sop("hasNext():"+li.hasNext());//sop("hasPrevious():"+li.hasPrevious());sop(al);/*//在迭代过程中,准备添加或者删除元素。Iterator it = al.iterator();while(it.hasNext()){Object obj = it.next();if(obj.equals("java02"))//用迭代器取出元素的同时,用集合的方式在操作元素,这样的并发访问有安全隐患,容易抛出异常//al.add("java008");it.remove();//将java02的引用从集合中删除了。对象还在内存中,只是集合中没啦。sop("obj="+obj);}sop(al);*/}}

三、ArrayList:
/* 将自定义对象作为元素存到ArrayList集合中,并去除重复元素。 比如:存人对象。同姓名同年龄,视为同一个人。为重复元素。 思路: 1,对人描述,将数据封装进人对象。 2,定义容器,将人存入。 3,取出。 List集合判断元素是否相同,依据是元素的equals方法。 */public class GetSingleObject {public static void main(String[] args) {ArrayList<Per> list = new ArrayList<Per>();list.add(new Per("zhangsan01", 21));list.add(new Per("zhangsan02", 22));list.add(new Per("zhangsan03", 23));list.add(new Per("zhangsan03", 23));list.add(new Per("zhangsan04", 24));print("remove:" + list.remove(new Per("zhangsan03", 23)));// remove底层也调用了equals进行比较list = (ArrayList<Per>) singleElement(list);for (ListIterator<Per> it = list.listIterator(); it.hasNext();) {Per p = (Per) it.next();print(p.getName() + ":::" + p.getAge());}}public static List<Per> singleElement(ArrayList<Per> list) {// 定义一个临时容器ArrayList<Per> newList = new ArrayList<Per>();for (ListIterator<Per> it = list.listIterator(); it.hasNext();) {Object obj = it.next();if (!(newList.contains(obj))) {// contains底层调用equals方法进行比较newList.add((Per) obj);}}return newList;}private static void print(Object obj) {System.out.println(obj);}}class Per {private String name;// 定义姓名private int age;// 定义年龄Per(String name, int age) {this.name = name;this.age = age;}//重写equals方法,建立Per类自己的比较方式public boolean equals(Object obj) {if (!(obj instanceof Per)) {throw new RuntimeException("类型错误");}Per p = (Per) obj;return p.getName().equals(this.name) && p.getAge() == this.age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}

四、LinkList:
1、特有方法:
addFirst();    addLast();

getFirst();    getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

removeFirst();    removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException

在JDK1.6出现了替代方法。
offerFirst();
offerLast();

peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。

pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
import java.util.LinkedList;/* 使用LinkedList模拟一个堆栈或者队列数据结构。 堆栈:先进后出  如同一个杯子。 队列:先进先出 First in First out  FIFO 如同一个水管。 */public class LinkedTest {public static void main(String[] args) {Duilie dl = new Duilie();dl.myAdd("java001");dl.myAdd("java002");dl.myAdd("java003");dl.myAdd("java004");while(!dl.isNull()){System.out.println(dl.myGet());}}}class Duilie{private LinkedList<String> link = new LinkedList<String>();public void myAdd(String str){link.addFirst(str);}public String myGet(){return link.removeLast();//removefirst}public boolean isNull(){return link.isEmpty();}}

五、Vector:

枚举就是Vector特有的取出方式。发现枚举和迭代器很像。其实枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。枚举郁郁而终了。

第三 Set集合

一、概述:

Set集合元素是无序(存入和取出的顺序不一定一致,在哈希表中其实是按照hash值来存放的),元素不可以重复。

二、Set集合常用子类之一HashSet:

1、概述:HashSet底层数据结构是哈希表,线程不同步。

2、HashSet保证元素唯一性:

是通过元素的两个方法,hashCode和equals来完成。如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。(先比较哈希值,哈希值一样比较是否是同一个对象,如不是同一个对象就存放在同一位置,两个串起来,放在同一个位置上)

注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。(ArrayList只依赖equals)

public class HashSetDemo {public static void main(String[] args) {HashSet<Course_1> hs = new HashSet<Course_1>();hs.add(new Course_1("java01", 26));hs.add(new Course_1("java02", 24));hs.add(new Course_1("java03", 28));hs.add(new Course_1("java04", 20));hs.add(new Course_1("java04", 20));for (Iterator<Course_1> it = hs.iterator(); it.hasNext();) {Course_1 c = (Course_1) it.next();System.out.println(c.getName() + "::::" + c.getPrice());}}}/* * 课程类 */class Course_1 {private String name;private int price;Course_1(String name, int price) {this.name = name;this.price = price;}@Overridepublic int hashCode() {//System.out.println("hashcode......." + this.name);return this.name.hashCode() + price * 20;// *20为了尽量保证哈希值不同,减少比较equals方法}@Overridepublic boolean equals(Object obj) {if (!(obj instanceof Course_1)) {throw new RuntimeException();}Course_1 c = (Course_1) obj;System.out.println(this.name + "....equals..." + c.getName());return c.getName().equals(this.name) && c.getPrice() == this.price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}}

三、Set集合常用子类之二TreeSet:

1、概述:TreeSet可以对Set集合中的元素进行排序。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0.注意:当主要条件相同时还需要判断次要条件。

2、关于二叉树,见图说话:


二叉树的存储方式就像树叉一样,所以称为二叉树。它的特点就是把大的数放在右边,小的数放在左边,取值时会按照从小到大的顺序取值。如果数据较多,二叉树会自动折中,然后再去判断,如图中就会折中到第五个位置上。这样就大大提高了存取的效率。

3、保证元素唯一性的依据:
实现的compareTo方法的返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入。
4、排序的两种实现方式,让元素本身具备比较性和让容器具备比较性。

1)让元素本身具备比较性,有些元素本身就具备比较性如String和Integer,这是因为他们实现Comparable接口,这种排序方式也称为自然顺序排序。

import java.util.Iterator;import java.util.TreeSet;public class CV {public static void main(String[] args) {TreeSet<String> ts = new TreeSet<String>();ts.add("asddf");ts.add("kg");ts.add("h");ts.add("aqsdf");for(Iterator<String> it = ts.iterator(); it.hasNext();){System.out.println(it.next());}}}

当然上面这种方式是元素本身就具备比较性,但是要是没有具备比较性那么我们就必须自己去实现comparable接口去重写compareTo方法,自己建立需要的比较性。

/* * 往TreeSet集合中存储自定义对象学生。想按照学生的年龄进行排序。 * 因为TreeSet集合会调用到存入元素的比较性进行比较,所以如果没有比较性或者想实现自己特有的比较 * 性就需要实现comparable接口复写compareTo方法在其中实现自己特有的比较方式 */public class TreeSetDemo {public static void main(String[] args) {TreeSet<Student> ts = new TreeSet<Student>();ts.add(new Student("lisi01", 19));ts.add(new Student("lisi02", 15));ts.add(new Student("lisi03", 20));ts.add(new Student("lisi08", 30));ts.add(new Student("lisi08", 31));ts.add(new Student("lisi09", 31));for (Iterator<Student> it = ts.iterator(); it.hasNext();) {Student s = it.next();System.out.println(s.getName() + ":::" + s.getAge());}}}class Student implements Comparable<Student> {private String name;private int age;Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic int compareTo(Student o) {//return 1;//这种方式是TreeSet是怎么存入的就怎么取出//return -1;//这种方式是TreeSet是倒叙取出System.out.println(this.name + "..compareto.." + o.getName());if (this.age == o.getAge()) {return this.name.compareTo(o.getName());} else if (this.age > o.getAge()) {return 1;}return -1;}}


2)让容器具备比较性:当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。当两种排序都存在时,以比较器为主。实现方式:定义一个类,实现Comparator接口,覆盖compare方法。

/* * 需求:对字符串进行按长度排序 * 分析:字符串本身具备比较性,但是是按自然顺序进行的排序,所以需要对排序方式进行重新定义,所以需要让集合具备比较性 * 使用比较器Comparator */public class TestTreeSet {public static void main(String[] args) {TreeSet<ComString> ts = new TreeSet<ComString>(new Mycompare());ts.add(new ComString("asd"));ts.add(new ComString("df"));ts.add(new ComString("dk"));ts.add(new ComString("jkkggd"));ts.add(new ComString("sfsfssgds"));for (Iterator<ComString> it = ts.iterator(); it.hasNext();) {ComString cs = it.next();System.out.println(cs.getS());}}}class Mycompare implements Comparator<ComString> {@Overridepublic int compare(ComString o1, ComString o2) {int num = o1.getS().length() - o2.getS().length();if (num == 0) {return o1.getS().compareTo(o2.getS());}return num;}}class ComString {private String s;ComString(String s) {this.s = s;}public String getS() {return s;}public void setS(String s) {this.s = s;}}