集合框架总结(基础知识)

来源:互联网 发布:帝国cms api接口 编辑:程序博客网 时间:2024/04/28 00:15

集合框架总结

一、集合框架概述

1、集合的由来:

我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。

2、数组和集合的区别?

A:长度区别:数组的长度固定,集合长度可变
B:内容不同:数组存储的是同一种类型的元素,而集合可以存储不同类型的元素
C:元素的数据类型问题:数组可以存储基本数据类型,也可以存储引用数据类型,集合只能存储引用类型

根据存储元素的数据结构,有很多集合与之对应,我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。

3、集合的继承体系结构

请看下面的这张图:


集合体系理解:先看中间部分,超级类是collection,接口collection中有两个子接口,List和Set,Set:元素是无序的(取出和存入的顺序是不一致的),元素不可重复, Set集合的功能和Collection的功能是一样的  ,List中的元素是有序的,即有索引。List接口中有三个(一个图为画出)具体的类,ArrayList,LinkedList,Vector,ArrayList底层数据结构是基于数组的,LinkedList底层数据结构是基于链表的,Vector底层数据结构也是基于数组的,可以看到ArrayList和Vector的存储方式有重复,为什么呢?因为集合框架是从JDK1.2版本出现的,而Vector是从JDK1.0开始的,Vector是元老级别的,当然新版本的出现必须兼容老版本,所以有了新容器,Vector用的也就少了,其他两个容器选用哪一个,当然看需求,主要评估因素是集合增删查改的频繁程度,两个类除了拥有父类Collection中的方法外,也有自己的特性方法,不过大差不差。Set接口也有两个子类,HashSet和TreeSet,其中HashSet的底层数据结构是基于哈希表的,

TreeSet的底层数据结构是基于二叉树的。

二、集合类介绍

  现在我们对集合的顶层接口Collection的功能进行一下归纳

1、Collection的功能概述:

(1).添加功能

       boolean add(Object obj):添加一个元素
       boolean addAll(Collection c):添加一个集合的元素

(2).删除功能

void clear():移除所有元素
        boolean remove(Object o):移除一个元素
boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

(3).判断功能

boolean contains(Object o):判断集合中是否包含指定的元素
  boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
  boolean isEmpty():判断集合是否为空

(4):获取功能

Iterator<E> iterator()(重点)

(5).长度功能

int size():元素的个数
  面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?

(6).交集功能

boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

(7).把集合转换为数组

  Object[] toArray()

2、List的功能概述

(1).元素有序,可以重复

(2).注意事项:

对集合的操作方式有两种,第一种是集合自身具有的方法,第二种是用迭代器存放集合元素引用来操作集合,一个类同时具有两种操作方式,这就可能产生冲突。
代码演示如下:
String s=“java”;Iterator it=al.iterator();While(it.hasNext){   Object obj=it.next();   If(obj.equals(s))    {       al.add(“java01”);    }}

代码分析:
   当Iterator it=al.iterator();执行时,迭代器就已经知道集合中所有元素的引 用,当 al.add(“java01”);再次添加元素时,迭代器是不知道的,这就造成了两 者的不一致,JVM会抛出     ConcurrentModificationException异常。因为迭代器仅有三个方法,我想要用迭代器方式进行添加怎么办呢?因为迭代器的本身局限性,就诞生出它的一个小弟,特地针对List.这个小弟就是ListIterator,它不仅可以实现add()方法,还可以正向和逆向遍历。


3、ArrayList的功能概述

(1).对于增删改查,Collection中的共性方法

   方法说明:boolean add(Object obj);
             对于这个方法,是继承与Collection的,所以接收参数类型为Object类的比较合理,这个才可包容一切对象。

(2). 遍历用迭代器

     Student  stu=(Studeng)it.iterator();
     使用迭代器遍历对象时,必须进行强转,因为add()方法接收的是Object类,任何传入此方法中的类型都将得到提升,对象中的特性方法就不在具有,因此
想获取对象内部信息,就得强转,否则,多态编译失败。

 (3).去除重复元素

     boolean Contains(Object obj);
    方法原理:这个方法用来判断一个集合中是否包含特定对象,其底层依赖的是equals()方法,即通过对象的地址值比较两个对象是否相等,所以就要注意了,当你new 的
     对象用add()添加时,对象都不相等,所以就不能去除,对此,我们可以覆盖我们自定义对象中的equals方法,指定比较的对象成员属性,当有多个属性时,
先比主要的,在比次要的。

 (4).存储原理

   底层数据结构是数组,数组是固定长度的,但是集合长度是要求可以改变的,所以JAVA
   采用了一种可变长度数组机制,new ArrayList()首先构造一个初始容量为 10 的空列 
   表,之后若空间不够,就会new一个新的数组,长度以50%延长,也就是变成15,再把
   原来老数组中的元素copy进来,而Vector是以100%延长,所以ArrayList更节省空间
   这也是Vector被淘汰的一个原因。除此,Vector是同步的,所以在多线程操作增删查
   改的时候容易出现问题,而ArrayList是不同步的。

 (5).ArrayList、Vector与LinkedList的比较。

   从底层存储方式入手,ArrayList是基于数组的,LinkedList是基于链表的,所以对于ArrayList,查询速度很快,但是增删稍慢。线程不安全,效率高。
   对应的LinkedList增删速度很快,而查询速度稍慢,线程不安全,效率高。Vector底层数据结构是数组,查询快,增删慢。线程安全,效率低。这是选用容器的重要的衡量因素。

 (6).实例代码

 需求: 键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值

public class ArrayListDemo {public static void main(String[] args) {// 创建键盘录入数据对象Scanner sc = new Scanner(System.in);// 键盘录入多个数据,我们不知道多少个,所以用集合存储ArrayList<Integer> array = new ArrayList<Integer>();// 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了while (true) {System.out.println("请输入数据:");int number = sc.nextInt();if (number != 0) {array.add(number);} else {break;}}// 把集合转成数组// public <T> T[] toArray(T[] a)Integer[] i = new Integer[array.size()];// Integer[] ii = array.toArray(i);array.toArray(i);// System.out.println(i);// System.out.println(ii);// 对数组排序// public static void sort(Object[] a)Arrays.sort(i);// 获取该数组中的最大索引的值System.out.println("数组是:" + arrayToString(i) + "最大值是:"+ i[i.length - 1]);}public static String arrayToString(Integer[] i) {StringBuilder sb = new StringBuilder();sb.append("[");for (int x = 0; x < i.length; x++) {if (x == i.length - 1) {sb.append(i[x]);} else {sb.append(i[x]).append(", ");}}sb.append("]");return sb.toString();}}

4、Set的功能概述

  1.set特点

     元素无序(存入顺序与取出不一样),不可以重复(唯一性),其功能和collection 一样。

  2、理解的两个儿子 HashSet、TreeSet。

  2.1、HashSet的重要点介绍

    a.底层数据结构是哈希表,哈希表就是存放一堆哈希值的表,如果元素哈希值相等且内容不同,在同一位置往下顺延,如果不等则直接往后存储。当然如果哈希值相等,元素内容也一样,则就不能存进去。
    b.唯一性是如何保证的?
     HashSet的唯一性依赖两个它自动调用的方法,hashCode()和equals(),先比较对象的哈希值是否相等,如果相等,再调用equals(),如果值为true,就被踢出,不存入, 反之就存入。当然,       第一次调用hashCode()时返回的哈希值相等时,则再调用equals()。注意hashCode别写成hasCode。

    c.主要方法
     add(),clear(),contains(),size(),clone(),再加上迭代器的3个方法。contains()和remove()依赖的方法是hashCode和equals(),原理同上。
  

    d.示例代码
     需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。

public class HashSetDemo {public static void main(String[] args) {// 创建随机数对象Random r = new Random();// 创建一个Set集合HashSet<Integer> ts = new HashSet<Integer>();// 判断集合的长度是不是小于10while (ts.size() < 10) {int num = r.nextInt(20) + 1;ts.add(num);}// 遍历Set集合for (Integer i : ts) {System.out.println(i);}}}

 2.2、TreeSet的重要点介绍

 a.排序的第一种方式:
   底层数据结构是二叉排序树,所以TreeSet可以对添加的对象进行自然排序,所以这就 要求我们添加的元素具有比较性,想要元素具有比较性,那就得实现Comparable接口并覆盖其compareTo()方法,这个方法自动被调用,让对象强制具有比较性,如果不实现将会抛出 ClassCastException异常,JAVA中很多类都已经实现了Comparable接 口,比如String实现Comparable后的compareTo方法就按照字母顺序来排序,但是  当我们自定义对象时,那就必须实现Comparable接口了。 

 b.排序的第二种方式:

  排序依据:如果元素不具有比较性或者具备的比较性不是所需要的时,可以使集合自身 具有比较性,在集合初始化时就具有了比较方式,所以这需要参与构造函数,定义比较  器,将比较器的对象传给TreeSet的构造函数。  备注:当两种排序方式都具备时,以比较器的方法为准
 c.比较器代码演示:
class Mycomp implements Comparator{public int compare(Object o1, Object o2) {String s1=(String)o1;String s2=(String)o2;int num=s1.length()-s2.length();if(num==0){num=s1.compareTo(s2);}return num;}}TreeSet ts=new TreeSet(new  Mycomp());
d.实例代码
需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
备注:学生类在此省去

public class TreeSetDemo {public static void main(String[] args) {// 创建一个TreeSet集合TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {// 总分从高到低int num = s2.getSum() - s1.getSum();// 总分相同的不一定语文相同int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;// 总分相同的不一定数序相同int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;// 总分相同的不一定英语相同int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;// 姓名还不一定相同呢int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()): num4;return num5;}});System.out.println("学生信息录入开始");// 键盘录入5个学生信息for (int x = 1; x <= 5; x++) {Scanner sc = new Scanner(System.in);System.out.println("请输入第" + x + "个学生的姓名:");String name = sc.nextLine();System.out.println("请输入第" + x + "个学生的语文成绩:");String chineseString = sc.nextLine();System.out.println("请输入第" + x + "个学生的数学成绩:");String mathString = sc.nextLine();System.out.println("请输入第" + x + "个学生的英语成绩:");String englishString = sc.nextLine();// 把数据封装到学生对象中Student s = new Student();s.setName(name);s.setChinese(Integer.parseInt(chineseString));s.setMath(Integer.parseInt(mathString));s.setEnglish(Integer.parseInt(englishString));// 把学生对象添加到集合ts.add(s);}System.out.println("学生信息录入完毕");System.out.println("学习信息从高到低排序如下:");System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");// 遍历集合for (Student s : ts) {System.out.println(s.getName() + "\t" + s.getChinese() + "\t"+ s.getMath() + "\t" + s.getEnglish());}}}

5、Map的功能概述

(1).public interface Map<K,V>

此集合存入的是关系,一对一对的,键值对应将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。


(2).主要方法介绍:

   V put(K key ,V value)
   添加元素对,如果是基于哈希表结构的,新值会覆盖旧值,并返回旧值
   V remove ( Object key )
   通过键,返回值,并从集合中移除
   V get (Object key )
   通过键,获取值,可以看出这有局限,每次只能取一个值
   boolean containsKey( Object key )
   通过键,判断是否包含值
   Clooection <V> values()
   取出集合中所有的值,存进Collection之中


(3).Map集合最重要的两个方法,即取出方法。

   
a、第一种:set<K>  Keyset()从JDK文档看到,Map集合并没有迭代器,因为迭代器针对的是单例集合,而Map是一个双例集合,那么它的元素对是怎样被取出的呢?所以JAVA就想到了前者转化成后者,此时。
我们可以通过下面两个之中的任何一个方法。
set<K>  Keyset()
返回Map集合的所有键,并存入到set集合中,再用迭代器的方法遍历集合, 同时用V V get(Object key),得到集合里面的值。 
代码演示:

Map<String,String> m=new HashMap<String,String>();m.put("1", "zhangsan1");。。。。。。Set<String> keySet=m.keySet();//对键值集合进行遍历for(Iterator<String> it=keySet.iterator();it.hasNext();){String str=it.next();System.out.print(str+"   ");String s=m.get(str);System.out.println(s);}
b、第二种:set<map.Entry<K,V>> entrySet ()
把Map集合中的映射关系存入到set集合之中,对于这种映射关系,我们可以把它哦也看成一种数据类型,而这个类型就是map.Entry,只是这种数据类型很猛,保存的是数据关系。而对set所呈现的仍是一个类型。
代码演示:

Map<String,String> m=new HashMap<String,String>();m.put("1", "zhangsan1");。。。。。。set<map.Entry<String,String>> =map.entrySet();Iterator<map.Entry<String,String>> it =m.itraror();while(it.hasNext()){   <map.Entry<String,String>> me=it.next();   String s1=me.getKey();   String s2=me.getValue();   … … … … …}

(4)HashMap嵌套HashMap

一所大学有多个学院,一个学院有多个专业,专业实体类包括两个属性,专业名称,该专业的学费,示例代码如下

public class HashMapDemo {public static void main(String[] args) {// 创建学校集合对象HashMap<String, HashMap<String, Integer>> universityMap = new HashMap<String, HashMap<String, Integer>>();// 创建软件学院集合对象HashMap<String, Integer> softCollegeMap = new HashMap<String, Integer>();// 添加元素softCollegeMap.put("软件工程", 10000);softCollegeMap.put("信息与计算科学",5000);// 把基础班添加到大集合universityMap.put("softCollegeMap", softCollegeMap);// 创建外语学院集合对象HashMap<String, Integer> foreignMap = new HashMap<String, Integer>();// 添加元素foreignMap.put("英语", 4500);foreignMap.put("日语", 4500);// 把外语学院添加到大集合universityMap.put("foreignMap", foreignMap);//遍历集合Set<String> universitySet = universityMap.keySet();for(String universitySetMapKey : universitySet){System.out.println(universitySetMapKey);HashMap<String, Integer> universityMapValue = universityMap.get(universitySetMapKey);Set<String> universityMapValueMapValueSet = universityMapValue.keySet();for(String universityValueKey : universityMapValueMapValueSet){Integer czbkMapValueValue = universityMapValue.get(universityValueKey);System.out.println("\t"+universityValueKey+"---"+czbkMapValueValue);}}}}

6、Hashtable简单示例

public class HashtableDemo {public static void main(String[] args) {// HashMap<String, String> hm = new HashMap<String, String>();Hashtable<String, String> hm = new Hashtable<String, String>();hm.put("it001", "hello");// hm.put(null, "world"); //NullPointerException// hm.put("java", null); // NullPointerExceptionSystem.out.println(hm);}}
最后:花费了一天的时间将集合的内容简单的回顾了一下,集合在JAVA编程中的作用之大无可厚非,无论是写服务端的项目还是Android端的项目,集合都一直陪伴着我们,所以集合的体系结构一定要熟悉,在什么情况下选用什么集合要清楚,好啦,今晚就到这里。




0 0
原创粉丝点击