本节内容
1.掌握集合框架接口
2.掌握常用集合类的使用
ArrayList
LinkedList
HashSet
TreeSet
HashMap
HashTable
TreeMap
迭代器:Iterator
一、为什么要使用集合。
我们在前面学习的能狗存储数据的:变量 、数组、对象这些都可以帮我们存储数据,但是我们知道,变量只能存储一个值、数组可以帮我们存储很多值,但是数组的长度是固定的,如果我们要存储我们都不知道有多个值的数据,那么我们学过的知识就不能帮我们实现了,所以我们使用集合就能帮我们实现。
集合是用来存储对象的。集合只能存储对象。而且集合的长度是不定的。
Java中的集合框架结构图:
Java中的集合框架已经很完善了我们需要做的是:学会如何使用Java中的集合框架来帮我们完成我们需要做的事。。。。。。
从上图可以看出:在Java中主要有2中集合:
collection集合(接口): LIst(接口)、Set(接口)
Map集合(接口):
Iterator迭代器(接口):专门用来迭代(遍历)collection集合的。
List集合的结构:
List是一个有序的collection集合接口此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
List集合接口的特点是:有下标,允许元素重复。通过下标来控制集合。
ArrayList类,LinkedList类,Vector类,Stack类
ArrayList类:
这个集合类,是我们最常用的一个集合类,ArrayList的底层实现是动态数组,我们知道数组的存储结构是线性存储,所有ArrayList集合的特点:查询速度快,增删改速度慢,线程不同步,容量的增长比例为自身的50%
package com.xk; import java.util.ArrayList; import java.util.List; /* *作者:吴志龙 *日期:2018年8月1日 */ public class ArrayListDemo { public static void main(String[] args) { //创建ArrayList集合 List list = new ArrayList(); //向上转型方式 ArrayList lists = new ArrayList(); //往集合中添加数据 list.add("a");//这种添加按照下标顺序添加 list.add(0, "b");//按照下标位置添加 lists.addAll(list);//把一个集合添加到另一个集合中添加到末尾 lists.addAll(0, list);//把一个集合添加到另一个集合中的指定位置 System.out.println(lists.size());//获取集合的长度 System.out.println(lists.get(1));//通过下标来获取元素的值 lists.set(1, "c");//用来修改某个位置上的元素 System.out.println(lists.get(1)); System.out.println(lists.remove("a"));//通过元素值来进行删除 System.out.println(lists.remove(1));//通过元素下标来进行删除 System.out.println(lists.contains("a"));//集合是否包含这个元素 lists.clear();//清空集合 System.out.println(lists.size()); } }
遍历集合:
使用传统方式:循环
package com.xk; import java.util.ArrayList; import java.util.List; /* *作者:吴志龙 *日期:2018年8月1日 */ public class ArrayListDemo { public static void main(String[] args) { //创建ArrayList集合 List list = new ArrayList(); //向上转型方式 list.add("a"); list.add("b"); list.add("c"); list.add("d"); //for循环遍历 for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } //for...each循环遍历 for(Object n:list){ System.out.println(n); } } }
使用迭代器遍历
package com.xk; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /* *作者:吴志龙 *日期:2018年8月1日 */ public class ArrayListDemo { public static void main(String[] args) { //创建ArrayList集合 List list = new ArrayList(); //向上转型方式 list.add("a"); list.add("b"); list.add("c"); list.add("d"); //使用迭代器遍历 Iterator<String> it= list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }
练习:
学生管理系统练习
学生信息包括 : 学号 姓名 年龄 家乡
打印欢迎语句
打印对应的功能 , 并接收用户的输入
1.查看学生信息
如果系统没有学生信息 则给出对应的提示
如果系统中有学生信息, 则按照指定的格式打印学生信息
2.添加学生信息
从键盘录入学生的信息 组成对象 添加到集合中
根据学号去重,只有没重复的学号才能添加到集合中
3.修改学生信息
根据学号找到学生进行修改
如果没有学号则给出对应的提示
如果找到学号则继续收集新信息, 使用新信息修改原来的元素
4.删除学生信息
根据学号删除学生
如果没有指定学号则给出指定的提示
如果有学号则删除指定的元素
5.退出学生信息管理系统
提示退出
并结束程序
LinkedList集合
LinkedList集合底层是一个双向链表结构,特点是增、删、改 速度快,查询速度慢。线程不同步。
LinkedList的操作与ArrayList集合的操作基本一致,与ArrayList相比多了几个方法:
package com.xk; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /* *作者:吴志龙 *日期:2018年8月1日 */ public class ArrayListDemo { public static void main(String[] args) { //创建ArrayList集合 LinkedList list = new LinkedList(); //向上转型方式 list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.addFirst("f");// 将指定元素插入此列表的开头。 list.addLast("g");//将指定元素添加到此列表的结尾 System.out.println(list.getFirst());//返回此列表的第一个元素 System.out.println(list.getLast());//返回此列表的最后一个元素 list.offer("h");//将指定元素添加到此列表的末尾(最后一个元素)。 System.out.println(list.getLast()); list.offerFirst("start");// 在此列表的开头插入指定的元素 list.offerLast("end");//在此列表末尾插入指定的元素 System.out.println(list.peek());//获取此列表的头一个元素 System.out.println(list.peekFirst());//获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。 System.out.println(list.peekLast());//获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null System.out.println(list.poll());//获取并移除此列表的头(第一个元素) System.out.println("----------------"); for(Object str:list){ System.out.println(str); } System.out.println(list.pollFirst());//获取并移除此列表的第一个元素;如果此列表为空,则返回 null。 System.out.println(list.pollLast());//获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。 System.out.println(list.pop());//移除并返回次列表的第一个元素 list.push("strat开始");//,将该元素插入此列表的开头 System.out.println(list.remove()); //获取并移除此列表的头(第一个元素)。 System.out.println(list.remove(1));// 移除此列表中指定位置处的元素 System.out.println(list.remove("a"));//从此列表中移除首次出现的指定元素(如果存在)。 System.out.println(list.removeFirst());//移除并返回此列表的第一个元素。 System.out.println(list.removeLast());// 移除并返回此列表的最后一个元素。 } }
Vector类:
Vector:底层采用的数据结构是数组结构。早期版本中使用的一个容器,基于线程同步。容量的增长比例为自身的100%。现被ArrayList替代。
Set集合结构:
特点: 元素没有顺序(无序)。不允许元素重复
HashSet类、
特征:允许null元素存在,并且只能存在一个,线程不同步(线程不安全)。
HashSet的操作
package com.xk; import java.util.HashSet; /* *作者:吴志龙 *日期:2018年8月2日 */ public class HashSetDemo { public static void main(String[] args) { //创建HashSet集合 HashSet hashset = new HashSet(); hashset.add("a");//添加元素 hashset.add("a");//重复元素不会添加 System.out.println(hashset.size());//集合的大小 System.out.println(hashset.contains("a"));//判断集合是否包含这个元素 System.out.println(hashset.isEmpty());//判断集合是否有元素 System.out.println(hashset.remove("a"));//删除元素 } }
TreeSet类
特征:是一种排序集合,底层是红黑树
TreeSet的排序分两种类型,一种是自然排序,另一种是定制排序。
操作:
package com.xk; import java.util.TreeSet; /* *作者:吴志龙 *日期:2018年8月2日 */ public class TreeSetDemo { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add("b");// 添加元素 treeSet.add("a"); System.out.println(treeSet.size());// 集合的长度 System.out.println(treeSet.ceiling("c")); // 返回此 set // 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 // null。 System.out.println(treeSet.first());// 返回此 set 中当前第一个(最低)元素 System.out.println(treeSet.last());// 返回此 set 中当前最后一个(最高)元素。 System.out.println(treeSet.floor("b"));// 返回此 set // 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 // null。 System.out.println(treeSet.pollFirst());//获取并移除第一个(最低)元素;如果此 set 为空,则返回 null。 System.out.println(treeSet.pollLast());//获取并移除最后一个(最高)元素;如果此 set 为空,则返回 null。 System.out.println(treeSet.remove("a"));//将指定的元素从 set 中移除(如果该元素存在于此 set 中)。 } }
TreeSet集合会对元素进行添加时排序
自然排序: 指的是对包装类型,以及String类型的数据拍自动排序。不需要我们手动排序
因为所有的包装类以及String类都实现了Comparable接口
所以TreeSet集合直接可以添加:包装类类型,以及String类型的数据
如果现在我们要添加自定义的类的对象数据。那么这个时候TreeSet就没有办法对对象进行排序了,所以添加就会失败。
package com.xk; /* *作者:吴志龙 *日期:2018年8月2日 */ public class Student { private String name; private int age; /** * @return the name */ public String getName() { return name; } /** * @return the age */ public int getAge() { return age; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @param age the age to set */ public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); // TODO Auto-generated constructor stub } }
package com.xk; import java.util.TreeSet; /* *作者:吴志龙 *日期:2018年8月2日 */ public class TreeSetDemo { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); Student stu = new Student("小明", 10); Student stu1 = new Student("小王", 12); treeSet.add(stu); treeSet.add(stu1); } }
Exception in thread "main" java.lang.ClassCastException: com.xk.Student cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at com.xk.TreeSetDemo.main(TreeSetDemo.java:18)
所以我们在添加之前先要排序:
自然排序:让我们需要排序的类去实现:Comparable接口来进行排序,使用compareTo()方法类排序
package com.xk; /* *作者:吴志龙 *日期:2018年8月2日 */ public class Student implements Comparable<Student>{ private String name; private int age; /** * @return the name */ public String getName() { return name; } /** * @return the age */ public int getAge() { return age; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @param age the age to set */ public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); // TODO Auto-generated constructor stub } @Override public int compareTo(Student o) { // TODO Auto-generated method stub return this.name.compareTo(o.getName()); } }
定制排序:关联一个对象:Comparator对象:需要去扩展一个Comparator接口来排序:
package com.xk; /* *作者:吴志龙 *日期:2018年8月2日 */ public class Student { private String name; private int age; /** * @return the name */ public String getName() { return name; } /** * @return the age */ public int getAge() { return age; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @param age the age to set */ public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); // TODO Auto-generated constructor stub } }
package com.xk; /* *作者:吴志龙 *日期:2018年8月2日 */ import java.util.Comparator; public class ComparatorSort implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { // TODO Auto-generated method stub return o1.getName().compareTo(o2.getName()); } }
package com.xk; import java.util.TreeSet; /* *作者:吴志龙 *日期:2018年8月2日 */ public class TreeSetDemo { public static void main(String[] args) { TreeSet treeSet = new TreeSet(new ComparatorSort()); Student stu = new Student("小明", 10); Student stu1 = new Student("小王", 12); treeSet.add(stu); treeSet.add(stu1); System.out.println(treeSet.size()); } }
迭代器:
什么是迭代器:
在Java中,有很多的数据容器,对于这些的操作有很多的共性。Java采用了迭代器来为各种容器提供了公共的操作接口。这样使得对容器的遍历操作与其具体的底层实现相隔离,达到解耦的效果。
迭代器可以遍历容器中的数据。
在集合中:我们的迭代器是用来专门迭代collection集合的。那么也就是:List接口下的集合与Set接口下的集合都可以使用迭代器进行遍历。
泛型:
我们的集合存储的都是对象,类型是:Object 那么在遍历的时候也都是 Object类型,但是我们存储的不一定是Object我们存储的都是一些引用类型,那么我们遍历出的也应该都是引用类型,但是我们取出的都是Object类型,这样我们就需要进行数据类型的转换。非常不方便。。。。。。。
其实我们一般都使用集合来存储同一类型的对象。这样就方便我们进行遍历,但是这样也需要进行数据类型的转换。。。如何才能不进行类型之间的转换呢??????
泛型的定义:
泛型是在Javajdk1.5引入的,引入泛型是为了在代码编译期间进行数据类型的检测,看数据类型是否非法的。还有就是可以帮我们实现,一段代码可以被不同的数据类型的对象类使用。达到代码的重复使用。
使用泛型的好处:
1.代码编译时严格的进行数据类型的检测
2.消除绝大多数的类型转换。
package com.xk; import java.util.ArrayList; /* *作者:吴志龙 *日期:2018年8月2日 */ public class Demo { public static void main(String[] args) { //没有使用泛型的集合 ArrayList list =new ArrayList(); list.add("a"); list.add("b"); list.add(10); //String str= list.get(1)这句代码编译不通过, //list.get(1)取出的是Object类型而我们使用String接收所以报错 //所以我们需要进行数据类型转换 String str=(String)list.get(1); //使用泛型 ArrayList<String> lists = new ArrayList<String>(); lists.add("a"); lists.add("b"); //这句代码报错 我们需要的是String类型的数据, //而存储了一个Integer的类型的数据 //所以说:可以在编译期间可以严格的检查数据类型。 lists.add(10); String str1 = lists.get(1);//不需要进行数据类型的转换 } }
定义泛型:
package com.xk; /* *作者:吴志龙 *日期:2018年8月2日 */ public class Emp<T> {//在定义类的时候使用<T>给一个代表泛型的标识 private T e_id; public Emp(T e_id) { super(); this.e_id = e_id; } public static void main(String[] args) { //当在使用类的时候:需要什么类型传入一个类型那么这个时候e_id的类型就固定了 Emp<String> emp =new Emp<String>("10"); } }
Map结构的集合类
特点:Map接口下的集合类都是映射集合 通过 Map<K,V> K
- 此映射所维护的键的类型V
- 映射值的类型
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
没有顺序,无序集合,没有下标
HashMap类,
底层是哈希表结构
是一个无序集合
键和值可以为null(注意:最多只允许一条记录的键为null,不允许多条记录的值为null)
线程不安全,效率高
操作:
package com.xk; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /* *作者:吴志龙 *日期:2018年8月2日 */ public class HashMapDemo { public static void main(String[] args) { //创建Hashmap集合 HashMap<String, String> hashMap = new HashMap<String, String>(); //添加 hashMap.put("001", "小明"); //修改:当键与集合中的键重复是添加操作就是修改操作 hashMap.put("001", "小王"); System.out.println(hashMap.size());//集合的长度 System.out.println(hashMap.containsKey("001"));//判断集合中是否包含指定的键 System.out.println(hashMap.containsValue("小王"));//判断集合中是否包含指定的值 Set<Map.Entry<String, String>> set= hashMap.entrySet();//将一个map集合返回为一个set集合 System.out.println(hashMap.get("001"));//通过键类获取映射的值 Set<String> setmap = hashMap.keySet();//将map集合的键全部返回一个set集合 Collection<String> collmap = hashMap.values();//将map集合的所有值返回为一个collection集合 System.out.println(hashMap.remove("001"));//通过 键来删除map中的一个元素 //遍历map集合 for(String key:setmap){ System.out.println(hashMap.get(key)); } for(Map.Entry<String, String> map:set){ map.getKey();//获取键key map.getValue();//获取值 value } //借助set集合使用迭代器 Iterator<String> it = setmap.iterator(); while (it.hasNext()) { String key= it.next(); System.out.println(hashMap.get(key)); } } }
Hashtable类、
底层是哈希表
键和值不能为null
无序
线程安全,效率低
操作与HashMap基本一致
TreeMap类
底层是二叉树
有序:(根据元素的 Key 进行排序,基于元素的固有顺序)
线程不安全