java学习笔记(二十二)集合
来源:互联网 发布:淘宝客服网上人工服务 编辑:程序博客网 时间:2024/04/28 07:07
集合
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,我们就需要对这多个对象进行存储。而目前为止我们学习过的可以存储多个元素的东西是数组,但是呢,数组长度固定,不能适应变化的需求,所以,Java就提供了集合类供我们使用。
集合和数组的区别:
数组:1.长度固定2.可以存储基本类型,也可以存储引用类型3.存储元素类型一致集合:1.长度可变2.只可以存储引用类型3.可以存储多种类型
集合体系图:
首先先介绍一下Collection这个接口
是集合的顶层结构,定义了集合的共性功能。
它有一些成员方法是所有集合所共有的:
成员方法:(看到E我们先把它理解为Object即可)
A:添加功能 boolean add(Object obj):往集合中添加一个元素 boolean addAll(Collection c):往集合中添加多个元素 B:删除功能 void clear():清空所有元素 boolean remove(Object o):从集合中删除一个元素 boolean removeAll(Collection c):从集合中删除另一个集合的元素 C:判断功能 boolean contains(Object o):判断集合中是否包含指定的元素 boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素 boolean isEmpty():判断集合是否为空。 D:交集功能 boolean retainAll(Collection c) E:迭代器(集合特有的遍历方式) Iterator iterator() F:长度功能 int size():返回集合中元素的个数 G:集合转数组 Object[]toArray():把集合转成数组,然后遍历数组,其实就相当于遍历了集合。
public class CollectionDemo { public static void main(String[] args) {// A:添加功能// boolean add(Object obj):往集合中添加一个元素// boolean addAll(Collection c):往集合中添加多个元素 Collection<String> c1=new ArrayList<String>();//创建Collection集合 //向集合中添加元素 c1.add("人机交互"); c1.add("图像处理"); c1.add("微机原理"); //再创建一个集合对象 Collection<String> c2=new ArrayList<String>(); c2.add("c++"); c2.add("java"); //把集合c2的元素添加到c1中 c1.addAll(c2); /*B:删除功能 * void clear():清空所有元素 * boolean remove(Object o):从集合中删除一个元素 * boolean removeAll(Collection c):从集合中删除另一个集合的元素*/ c1.remove("c++"); //c1.removeAll(c2); //c1.clear(); /*C:判断功能 * boolean contains(Object o):判断集合中是否包含指定的元素 * boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素 * boolean isEmpty():判断集合是否为空。*/ //boolean contains = c1.contains("c++"); boolean contains = c1.containsAll(c2); System.out.println(contains); /*D:交集功能 * boolean retainAll(Collection c)*/ boolean retainAll = c1.retainAll(c2);//求出交集元素,并将没有交集的元素删除 System.out.println(retainAll); //遍历集合c1 Object[] arr = c1.toArray(); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } //遍历集合c2 Object[] arr1 = c2.toArray(); for (int i = 0; i < arr1.length; i++) { System.out.println(arr1[i]); } }}
迭代器: Iterator iterator(),用来遍历集合中的元素
成员方法: Object next():返回迭代的下一个元素,并移动指向的位置 boolean hasNext():判断是否有元素
迭代器是依赖于集合而存在的。所以,要想得到迭代器对象,必须先有集合对象。
迭代步骤: A:通过集合对象获取到迭代器对象 B:通过迭代器对象的hasNext()方法判断是否有元素 C:通过迭代器对象的next()方法获取元素
练习:创建狗对象(带参数),存储到集合,用迭代器进行遍历并打印对象的属性数据
分析:1。先写一个Dog类
2.然后在创建一个空的集合
3.创建Dog对象
4.向集合中添加Dog对象元素
5.使用while循环加迭代器进行遍历
Dog类:
public class Dog { private String name; private int age; private String color; public Dog(String name, int age, String color) { super(); this.name = name; this.age = age; this.color = color; } public Dog() { super(); // TODO Auto-generated constructor stub } 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; } public String getColor() { return color; } public void setColor(String color) { this.color = color; }}
然后写一个测试类:
public class CollectionDemo { public static void main(String[] args) { //创建狗对象 Dog d1 = new Dog("大黄",2,"黄色"); Dog d2 = new Dog("小黑",2,"黑色"); Dog d3 = new Dog("大花",2,"花色"); //创建集合对象 Collection c1=new ArrayList(); //集合中添加狗对象元素 c1.add(d1); c1.add(d2); c1.add(d3); //创建迭代器对象 Iterator it = c1.iterator(); //遍历 while(it.hasNext()){ Dog d=(Dog) it.next(); System.out.println(d.getName()+" "+d.getAge()+" "+d.getAge()); } }}
List接口:
(1)List集合的元素有序(存储和取出顺序一致),元素可重复
(2)List的特有功能:
A:添加功能 void add(int index,Object obj):在指定的位置添加元素 B:删除功能 Object remove(int index):通过指定的索引删除元素,并把删除的元素返回 C:获取功能 get(int index) 返回列表中指定位置的元素。 D:替换功能 Object set(int index,Object obj)
下面写一些简单的代码对这些功能进行测试:
public class ListDemo { public static void main(String[] args) { //创建List集合对象 List<String> list = new ArrayList<String>(); //给集合添加元素 list.add("李白"); list.add("杜甫"); list.add("王维"); //遍历集合 print(list); System.out.println("----------------------------"); //void add(int index,Object obj):在指定的位置添加元素 list.add(1, "白居易"); print(list); System.out.println("----------------------------"); //Object remove(int index):通过指定的索引删除元素,并把删除的元素返回 String remove = list.remove(1); print(list); System.out.println("--------------------------"); System.out.println(remove); System.out.println("-----------------------------"); //get(int index) 返回列表中指定位置的元素。 String str = list.get(0); System.out.println(str); System.out.println("----------------------"); //Object set(int index,Object obj) list.set(0, "苏轼"); print(list); } public static void print(List<String> p){ Iterator<String> it = p.iterator(); while(it.hasNext()){ System.out.println(it.next()); } }}
集合中还有一个集合工具类Collections类,可以实现List的倒序与洗牌与排序
List中元素顺序可以被洗牌Collections.shuffle(list) List中元素顺序可以被倒序Collections.reverse(list) Collections.sort(list)对List元素排序
public class CollectionsDemo { public static void main(String[] args) { //创建List集合 List list = new ArrayList(); //给集合中添加元素 list.add(2); list.add(8); list.add(1); list.add(3); //List中元素顺序可以被洗牌Collections.shuffle(list) //Collections.shuffle(list); //List中元素顺序可以被倒序Collections.reverse(list) //Collections.reverse(list); //Collections.sort(list)对List元素排序(字母数字分别进行测试) //如果是按字母是按照a-z的顺序进行排序 //Collections.sort(list); //如果是按照数字进行排序,按照从小到大的顺序进行排列 Collections.sort(list); //遍历集合 for (Object object : list) { System.out.println(object); } }}
LinkedList:list集合接口的实现类
LinkedList特有功能:
public void addFirst(E e)//向第一个位置添加元素 public void addLast(E e)//向最后一个位置添加元素 public E getFirst()//获取第一个元素 public E getLast()//获取最后一个元素 public E removeFirst()//移除第一个元素 public E removeLast()//移除最后一个元素
简单的进行测试:
public class LinkedListDemo { public static void main(String[] args) { //创建一个LinkedList的集合 LinkedList list = new LinkedList(); list.add("hello"); list.add("world"); list.add("java"); // public void addFirst(E e) // public void addLast(E e) //需求:在hello前面加上一个元素“c++” list.addFirst("c++"); list.addLast("js");// public E getFirst()// public E getLast()// Object first = list.getFirst();// Object last = list.getLast();// System.out.println(first);// System.out.println(last);// public E removeFirst()// public E removeLast() Object removeFirst = list.removeFirst(); Object removeLast = list.removeLast(); System.out.println(removeFirst); System.out.println(removeLast); System.out.println("---------------"); //遍历集合 for(Object obj:list){ System.out.println(obj); } }}
ArrayList与LinkedList的相同点与不同点
相同点:有顺序的,元素可以重复不同点:(1)ArrayList特点: 底层数据结构是数组,查询快,增删慢 线程不安全,效率高 (2)LinkedList特点: 底层数据结构是链表,查询慢,增删快 线程不安全,效率高
集合的遍历方式:
1.for(普通for)(list集合专有,因为有get()方法) 2.Iterator(迭代器) 3.foreach(增强for)
foreach的格式:
for(集合中的元素类型 变量名:集合名){ }
需求:用List集合存储3个汽车对象,然后遍历。(用三种方式进行遍历)
分析:
1.创建汽车集合
2.创建汽车对象
3.创建list集合对象
4.向集合中添加对象元素
5.遍历
Car类:
public class Car { private String brand; private int price; private String color; public Car() { super(); // TODO Auto-generated constructor stub } public Car(String brand, int price, String color) { super(); this.brand = brand; this.price = price; this.color = color; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getColor() { return color; } public void setColor(String color) { this.color = color; }}
public class ListDemo { public static void main(String[] args) { //创建汽车对象 Car c1 = new Car("大众",20000,"黑色"); Car c2 = new Car("奥迪",40000,"红色"); Car c3 = new Car("奔驰",60000,"白色"); //创建集合对象 List list =new ArrayList(); //集合中添加元素 list.add(c1); list.add(c2); list.add(c3); //使用迭代器遍历 Iterator it = list.iterator(); while(it.hasNext()){ Car c=(Car) it.next(); System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor()); } System.out.println("---------------------------"); //使用for循环遍历 for (int i = 0; i <list.size(); i++) { Car c=(Car) list.get(i); System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor()); } System.out.println("---------------------------"); //增强for循环 for(Object obj:list){ Car c=(Car) obj; System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor()); } }}
结果:
set集合中的hashset
HashSet 元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
如何保证元素的唯一性的呢?
通过分析源码,我们知道HashSet集合保证元素的唯一性和add()方法相关。
如何我们想深入的了解,就必须看add()方法的源码,看它的底层依赖什么内容?
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {...} 左边:e.hash == hash 比较对象的哈希值。 右边:((k = e.key) == key || key.equals(k)) 左边:(k = e.key) == key 比较对象的地址值。 右边:key.equals(k) 比较的是对象的内容是否相同。默认情况下比较的是地址值 结论: 底层数据结构是哈希表。 哈希表依赖两个方法:hashCode()和equals() 执行流程: 首先判断哈希值是否相同,如果不同,就直接添加到集合。 如果相同,继续执行equals(),看其返回值, 如果是false,就直接添加到集合。 如果是true,说明元素重复不添加。
所以我们在使用hashset集合时想要保住元素的唯一性,就必须重写hashCode()和equals()这两个方法。至于如何重写,eclipse提供了自动生成的方法
练习:创建一个HashSet集合,添加元素(学生对象元素),保证其唯一性。
Student类:在这个类中重写hashCode()和equals()这两个方法
public class Student { private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); // TODO Auto-generated constructor stub } 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; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } //重写hashCode(),equals()方法 @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }}
测试类:
public class HashSetDemo { public static void main(String[] args) { //创建集合 HashSet<Student> hs = new HashSet<Student>(); //创建学生对象 Student s1 = new Student("郭德纲", 50); Student s2 = new Student("刘德华", 55); Student s3 = new Student("张学友", 56); Student s4 = new Student("黎明", 57); Student s5 = new Student("郭德纲", 50); //给集合中添加元素 hs.add(s1); hs.add(s2); hs.add(s3); hs.add(s4); hs.add(s5); //遍历集合 for (Student student : hs) { System.out.println(student); } }}
通过分析发现:郭德纲这个对象只出现了一次,保证了元素的唯一性
TreeSet
首先看一下它的两个构造方法:
public TreeSet() //构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。 TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序
元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序,具体取决于使用的构造方法。
底层算法:二叉树
元素要求, 加入自定义JavaBean
对java中已有数据类型的存入:
1.如果是Integer类型的数据,按大小顺序存入 2.如果是String类型的数据,按首字母a-z的顺序存入
练习:创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24)
public class TreeSetDemo { public static void main(String[] args) { //创建一个TreeSet集合 TreeSet<Integer> ts = new TreeSet<Integer>(); //给集合中存储元素 //(20,18,23,22,17,24,19,18,24) ts.add(20); ts.add(18); ts.add(23); ts.add(22); ts.add(17); ts.add(24); ts.add(19); ts.add(18); ts.add(24); //遍历集合 for (Integer integer : ts) { System.out.print(integer+" "); } }}//结果:17 18 19 20 22 23 24
分析:TreeSet集合特点:
1.元素唯一 2.元素有序
那么在存入自定义对象元素时如何保证元素有序呢?分析Integer类和String类之后发现这两个类实现了一个Comparable接口,并重写comparaTo()方法,所以我们在存入自定义对象元素是也需要重写这个方法,就可以保证元素有序.当然还有另外一种方法,我们首先看一下第二种构造方法,它需要一个比较器实现类对象,那么我们可以用匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。
练习:创建集合存储Student类型的元素,并保证其有序性
方式一:
1.创建Student类并实现Comparable接口,并重写comparaTo()方法
2.创建学生对象
3.使用无参构造创建空TreeSet集合
4.添加学生元素
5.遍历
学生类中实现的compareto方法
public int compareTo(Student s) { //就是写的是元素的比较规则,由你自己去动手写出 //按照学生的年龄进行排序 /** * 两个对象进行比较: * s * this */ int num = this.age - s.age; //判断年龄是否相同,如果相同比较姓名 /** * 写这个比较规则的时候注意两点: * 1.他有主要条件,先按照主要条件进行排序 * 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较 */ int num2 = num==0?this.name.compareTo(s.name):num; return num2; }
测试类:
public class TreeSetDemo { public static void main(String[] args) { //创建TreeSet集合,存储自定义对象 TreeSet<Student> ts = new TreeSet<Student>(); //给集合中添加Student对象 Student s = new Student("guodegang", 50); Student s6 = new Student("liuyifei", 50); Student s2 = new Student("zhangxueyou", 55); Student s3 = new Student("amu", 45); Student s4 = new Student("tf-boys", 18); Student s5 = new Student("wangfeng", 49); ts.add(s); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); //遍历集合 for (Student student : ts) { System.out.println(student); } }}
方法二
1.创建Student类
2.创建学生对象
3.使用使用带选择器的有参构造创建空TreeSet集合
4.匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。
5.添加学生元素
6.遍历
public class TreeSetDemo { public static void main(String[] args) { //使用匿名内部类来进行改进 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { int num = s1.getAge() - s2.getAge(); int num2 = num==0?s1.getName().compareTo(s2.getName()):num; return num2; } }); //创建对象存入集合 Student s = new Student("guodegang", 50); Student s6 = new Student("liuyifei", 50); Student s2 = new Student("zhangxueyou", 55); Student s3 = new Student("amu", 45); Student s4 = new Student("tf-boys", 18); Student s5 = new Student("wangfeng", 49); ts.add(s); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); //遍历集合 for (Student student : ts) { System.out.println(student); } }}
两者结果完全相同
HashSet与TreeSet的相同点与不同点
相同点:
单列集合,元素不可重复
不同点:
1. 底层存储的数据结构不同 HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储2.存储时保证数据唯一性依据不同 HashSet是通过复写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的3.有序性不一样 HashSet无序,TreeSet有序
Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map接口中的方法概述(创建集合测试方法):
A:删除功能 void clear():移除集合中的所有键值对元素 V remove(Object key):根据键移除键值对元素,并返回值 B:判断功能 boolean containsKey(Object key):判断集合中是否包含指定的键 boolean containsValue(Object value):判断集合中是否包含指定的值 boolean isEmpty():判断集合是否为空 C:获取功能 Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象, 利用getKey(),getValue()取出键和值(理解即可) V get(Object key):根据键获取值 Set<K> keySet():获取所有的键 Collection<V> values():获取所有的值 D:添加功能 V put(K key,V value):集合添加键值对 E:长度功能 int size():键值对对数。
进行功能测试:
public class MapDemo { public static void main(String[] args) { //创建一个Map集合 //键是学号--值是姓名 Map<Integer,String> map = new HashMap<Integer,String>(); //V put(K key,V value):集合添加键值对 map.put(1, "周杰伦"); map.put(2, "郭德纲"); map.put(3, "刘德华"); map.put(4, "张学友"); //void clear():移除集合中的所有键值对元素 //map.clear(); //V remove(Object key):根据键移除键值对元素,并返回值 //String remove = map.remove(1); //System.out.println(remove); //boolean containsKey(Object key):判断集合中是否包含指定的键 //boolean containsKey = map.containsKey(2); //System.out.println(containsKey); //boolean containsValue(Object value):判断集合中是否包含指定的值 //boolean containsValue = map.containsValue("周杰伦"); //System.out.println(containsValue); //boolean isEmpty():判断集合是否为空 //System.out.println(map.isEmpty()); //int size():键值对对数。 //System.out.println(map.size()); //Collection<V> values():获取所有的值 /* Collection<String> values = map.values(); Iterator<String> it = values.iterator(); while (it.hasNext()) { System.out.println(it.next()); }*/ //Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象, //利用getKey(),getValue()取出键和值(理解即可) Set<Entry<Integer,String>> entrySet = map.entrySet(); for (Entry<Integer, String> entry : entrySet) { System.out.println(entry.getKey()+" "+entry.getValue()); } System.out.println("--------------------"); //Set<K> keySet():获取所有的键 Set<Integer> keys = map.keySet(); for (Integer key : keys) { //V get(Object key):根据键获取值 System.out.println(key+" "+map.get(key)); } }}
HashMap
元素顺序:元素顺序不可预测 底层算法:哈希算法 对键没有要求(仅仅相对于TreeMap来说)
public class HashMapDemo { public static void main(String[] args) { // 1.存入(String,String)主要讲解遍历方式,键:丈夫 值:妻子 HashMap<String, String> hm = new HashMap<String,String>(); //给键值对集合存入元素 hm.put("文章", "马伊琍"); hm.put("黄晓明", "baby"); hm.put("汪老师", "章子怡"); hm.put("周杰伦", "昆凌"); //hm.put("文章", "姚笛");,当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替 //遍历,通过建找值 Set<String> keys = hm.keySet(); for (String key : keys) { System.out.println(key+" "+hm.get(key)); } System.out.println("-------------"); //通过找到结婚证,来分别找到丈夫和妻子 Set<Entry<String,String>> entrySet = hm.entrySet(); for (Entry<String, String> entry : entrySet) { System.out.println(entry.getKey()+" "+entry.getValue()); } }}
Treemap
元素顺序:元素顺序与键的排序规则有关底层算法:Tree算法
.HashMap与TreeMap的相同点与不同点
相同点:主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。 不同点: 1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。 2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
- java学习笔记(二十二)集合
- JAVA学习笔记(二十二)- 集合HashMap与Hashtable
- java学习笔记(十二)----集合
- 学习笔记(二十二)
- java学习笔记(二十二)继承的进一步研究
- scala学习笔记(十二) 集合
- java学习笔记(十二)
- Java学习笔记(十二)
- Java学习笔记(十二)
- Java学习笔记(十二)
- java学习笔记(十二)
- Linux学习笔记(二十二)
- python 学习笔记(二十二)
- tensorflow学习笔记(二十二):Supervisor
- 信息安全工程师 学习笔记(二十二)
- java学习笔记十二
- 集合学习笔记(二)
- java并发编程(二十二)----(JUC集合)ConcurrentHashMap介绍
- bzoj1509: [NOI2003]逃学的小孩
- Android车牌识别与PDA
- 《Cracking the Coding Interview程序员面试金典》----从0到n中某个数字的个数
- 字符串的相关内容总结
- DockOne技术分享(十二):新浪是如何分析处理32亿条实时日志的?
- java学习笔记(二十二)集合
- 2440超详细uboot移植笔记(五)------设置时钟
- poj 1316 Self Numbers
- 30分钟LINQ教程
- POJ 3714 Raid(最近点对)
- FLUENT UDF中source的学习
- JVM学习(一)
- 欢迎使用CSDN-markdown编辑器
- HDOJ 2020 绝对值排序!