第七天:单例集合Collection List Set
复习集合之前聊一下数组跟集合进行一个对比
数组:可以看成一个容器,用来存储数据的。(在内存中开辟了一块连续的内存空间)
特点:
1.长度固定
2.存储的数据类型固定,存储同种类型的数据,能存储基本数据类型也可以存储引用数据类型。
3.数组有默认值
集合:也是用来存储数据的容器(也在内存中开辟了一块空间)
集合(容器):用来存和取数据,通过存和取数据的方式不一样,可以把集合进行细分。
为什么要有集合?
因为数组的长度是固定的,不可变的。而集合的长度是不固定的,可变的,使用起来更加的灵活。
集合的特点:
1.长度是可变的。
2.只能存储对象
3.没有默认值
集合只是一种只能存储对象并且长度可变的容器的总称而已,这类容器通过存和取的方式不一样就能进行细分。
1.单例集合(collection)
collection集合(父接口)下面有list接口和set接口,list下面分为ArrayList类(实现类)和linkList类,Set下面分为HshSet类(实现类),TreeSet类。
注意:我们学习的时候是从体系结构的最顶层接口学习的,使用的是它的具体的实现类。
List的特点:
1.有序(存和取数据的顺序是一致的)
2.有索引
3.元素可以重复
set的特点:
1.无序的(存和取数据的顺序是不一致的) 2.无索引
3.元素不可以重复
1.1collection常用的方法:
boolean add(Object e): 向集合中添加元素
boolean addAll(Collection e): 向集合中添加元素
void clear():清空集合中所有元素
boolean contains(Object o):判断集合中是否包含某个元素
boolean isEmpty():判断集合中的元素是否为空
boolean remove(Object o):根据元素的内容来删除某个元素
例子:
/* boolean add(Object e): 向集合中添加元素 boolean addAll(Collection e): 向集合中添加元素 void clear():清空集合中所有元素 boolean contains(Object o):判断集合中是否包含某个元素 boolean isEmpty():判断集合中的元素是否为空 boolean remove(Object o):根据元素的内容来删除某个元素 int size():获取集合的长度 Object[] toArray():能够将集合转换成数组并把集合中的元素存储到数组中*/ //创建collection对象 多态:父类的引用指向子类的对象 Collection c=new ArrayList(); //调用父类collection里面的方法,但是具体实现是在子类ArrayList中 //1 boolean add(Object e): 向集合中添加元素 // c.add(1);//这里有一个自动装箱的过程 包装类 c.add("zhangsan"); c.add("lisi"); c.add("wangwu"); c.add("wangwu"); //可以重复 为什么ArrayList集合添加数据时可以重复?因为add()的返回值永远为true System.out.println(c);//存和取的顺序是一致的 输出结果:[zhangsan, lisi, wangwu] //创建集合 Collection c=new ArrayList(); //往集合里面添加数据 c.add("张三"); c.add("李四"); c.add("王五"); // method1(c); // Object[] toArray():能够将集合转换成数组并把集合中的元素存储到数组中 Object[] arr = c.toArray(); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); } } private static void method1(Collection c) { Collection c1=new ArrayList(); // boolean addAll(Collection e): 向集合中添加元素 相当于复制集合 c1.addAll(c); System.out.println(c1); // void clear():清空集合中所有元素 // c.clear(); [] 空 // boolean contains(Object o):判断集合中是否包含某个元素 System.out.println(c.contains("赵六"));//false System.out.println(c.contains("李四"));//true // boolean isEmpty():判断集合中的元素是否为空 System.out.println(c.isEmpty());//false // boolean remove(Object o):根据元素的内容来删除某个元素 System.out.println("是否删除成功:"+c.remove("张三"));//true System.out.println(c); // int size():获取集合的长度 System.out.println(c.size()); }
1.2迭代器
用来遍历集合的工具
java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。
Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
集合中把这种取元素的方式描述在Iterator接口中。Iterator接口的常用方法如下
hasNext()方法:判断集合中是否有元素可以迭代
next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。
remove():删除当前正在获取的元素
例子:
package com.swlz.collection; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class CollectionDemo4 { public static void main(String[] args) { //创建集合对象 List c=new ArrayList(); //添加数据 c.add("张三"); c.add("李四"); c.add("王五"); c.add("赵六"); c.add("钱七"); //为了解决使用Colletion 集合迭代器发生的并发修改异常问题,我们要使用List集合的迭代器 /*ListIterator<E> listIterator() 返回此列表元素的列表迭代器(按适当顺序)。 */ ListIterator lit = c.listIterator(); //遍历集合 while(lit.hasNext()){ String s1=(String)lit.next(); if(s1.equals("钱七")){ //使用List集合的迭代器可以解决 添加元素的并发修改异常 //删除的并发修改异常也能解决,但是只能删除条件本身 lit.add("隔壁老王"); // lit.remove();//删除钱七 } } System.out.println(c); } }
1.3 foreach:遍历集合的
//Foreach增强for---底层是collection集合中的迭代器Iterator,
// 所以不能对集合中的元素个数发生改变,我们一般是用于直接去遍历集合的
语法格式
foreach(对象数据类型 对象:集合名字){
循环体
}
面试题:ArrayList和LinkedList区别?
1.ArrayList的底层是数组,查询快,增删慢
2.LinkedLIst的底层是链表,查询慢,增删快
List集合常用方法
void add(int index, E element) :将元素添加到index索引位置上
E get(int index) :根据index索引获取元素
E remove(int index) :根据index索引删除元素
E set(int index, E element):将index索引位置的的元素设置为element
例子:
package com.swlz.collection; import java.util.ArrayList; import java.util.List; public class ListDemo1 { public static void main(String[] args) { /* void add(int index, E element) :将元素添加到index索引位置上 E get(int index) :根据index索引获取元素 E remove(int index) :根据index索引删除元素 E set(int index, E element):将index索引位置的的元素设置为element 修改*/ List list=new ArrayList(); //将元素添加到index索引位置上 list.add("詹"); list.add("李"); list.add("彭"); System.out.println(list); // E get(int index) :根据index索引获取元素 System.out.println(list.get(0)); System.out.println(list.get(1)); System.out.println(list.get(2)); // E remove(int index) :根据index索引删除元素 list.remove(0); System.out.println(list); //E set(int index, E element):将index索引位置的的元素设置为element 修改 list.set(0,"张三");//把索引为0的元素改为张三 } }
1.4LinkedList集合常用方法
LinkedList底层使用的是链表结构,因此增删快,查询相对ArrayList较慢
void addFirst(E e) :向链表的头部添加元素
void addLast(E e):向链表的尾部添加元素
E getFirst():获取链头的元素,不删除元素
E getLast():获取链尾的元素,不删除元素
E removeFirst():返回链头的元素并删除链头的元素
E removeLast():返回链尾的元素并删除链尾的元素
1.代码
import java.util.LinkedList;
/*
* List的常用子类:
* ArrayList
* 底层是数组结构,查询快,增删慢
* LinkedList
* 底层结构是链表,查询慢,增删快
*
* 如何选择使用不同的集合?
* 如果查询多,增删少,则使用ArrayList
* 如果查询少,增删多,则使用LinkedList
* 如果你不知道使用什么,则使用ArrayList
*
* LinkedList的特有功能:
* void addFirst(E e)
* void addLast(E e)
E getFirst()
E getLast()
E removeFirst()
E removeLast()
*/
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("hello");
list.add("world");
//void addFirst(E e) :将元素添加到索引为0的位置
//void addLast(E e) :将元素添加到索引为size()-1的位置
list.addFirst("java");
list.addLast("android");
//E getFirst() :获取索引为0的元素
//E getLast() :获取索引为size()-1的元素
//System.out.println(list.getFirst());
//System.out.println(list.getLast());
//E removeFirst() :删除索引为0的元素并返回
//E removeLast() :删除索引为size()-1的元素并返回
System.out.println(list.removeFirst());
System.out.println(list.removeLast());
System.out.println(list);
}
}
1.5 Collections工具类
Collections工具类---是专门用来操作List集合的工具类 什么叫工具类?---工具类里面封装了很多的方法,提供给对应的数据使用, 工具类中的方法一般都是静态的,方便通过类名直接调用 例子: pakage com.swlz.collection; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class CollectionsDemo1 { public static void main(String[] args) { //Collections工具类---是专门用来操作List集合的工具类 //什么叫工具类?---工具类里面封装了很多的方法,提供给对应的数据使用, // 工具类中的方法一般都是静态的,方便通过类名直接调用 /* static int binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列(复制集合) * static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素 //static void reverse(List list) :反转 * //static void shuffle(List list):傻否,随机置换 * //static void sort(List<T> list) :按照列表中元素的自然顺序进行排序 * //static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换*/ List list=new ArrayList(); list.add(5); list.add(3); list.add(7); list.add(2); list.add(9); int i = Collections.binarySearch(list, 7);//使用二分查找法查找指定元素在指定列表的索引位置 System.out.println(i);//index是2 } }
1.6 set集合(接口)
特点:
1.数据(元素)存入集合的顺序和取出集合的顺序不一致(无序的)
2.没有索引
3.存入集合的元素不能重复
set集合元素为什么不可以重复?
因为set集合是map的put方法,而put方法的实际原理是putval()中比较了我们对象的哈希值。
HashSet集合(底层是哈希表)
HashSet集合的使用
1案例:
public class HashSetDemo2 {
public static void main(String[] args) {
//创建集合对象
HashSet<Student> hs = new HashSet<Student>();
//创建元素对象
Student s = new Student("zhangsan",18);
Student s2 = new Student("lisi",19);
Student s3 = new Student("lisi",19);
//添加元素对象
hs.add(s);
hs.add(s2);
hs.add(s3);
//遍历集合对象
for (Student student : hs) {
System.out.println(student);
1.6.1HashSet唯一性原理
规则:新添加到HashSet集合的元素都会与集合中已有的元素一一比较
首先比较哈希值(每个元素都会调用hashCode()产生一个哈希值)如果新添加的元素与集合中已有的元素的哈希值都不同,新添加的元素存入集合如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要调用equals(Object obj)比较如果equals(Object obj)方法返回true,说明新添加的元素与集合中已有的某个元素的属性值相同,那么新添加的元素不存入集合,如果equals(Object obj)方法返回false, 说明新添加的元素与集合中已有的元素的属性值都不同, 那么新添加的元素存入集合
/*
* 使用HashSet存储自定义对象并遍历
* 通过查看源码发现:
* HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
* 如果hash值不一样,则直接添加新的元素
* 如果hash值一样,比较地址值或者使用equals方法进行比较
* 比较结果一样,则认为是重复不添加
* 所有的比较结果都不一样则添加
*/
public class HashSetDemo2 {
public static void main(String[] args) {
//创建集合对象
HashSet<Student> hs = new HashSet<Student>();
//创建元素对象
Student s = new Student("zhangsan",18);
Student s2 = new Student("lisi",19);
Student s3 = new Student("lisi",19);
//添加元素对象
hs.add(s);
hs.add(s2);
hs.add(s3);
//遍历集合对象
for (Student student : hs) {
System.out.println(student);
}
}
}
class Student {
String name;
int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
//System.out.println("-------------------");
Student s = (Student)obj;//向下转型,可以获取子类特有成员
//比较年龄是否相等,如果不等则返回false
if(this.age != s.age) {
return false;
}
//比较姓名是否相等,如果不等则返回false
if(!this.name.equals(s.name)) {
return false;
}
//默认返回true,说明两个学生是相等的
return true;
}
@Override
public int hashCode() {
return 1;
}
}
总结:hashcode方法的优化:
因为当对象的哈希值不一样时,对象可以直接存储到集合中,不需要去调用equals()
但是有需要做到去重,有时也需要去调用equals()比较对象的内容
如此当把哈希值全部设为一致时,会多次去调用equals()比较对象的内容,
而方法的调用会消化时间,降低程序的执行效率。
所以需要优化hashcode方法
把字段的哈希值当作对象的哈希值。当两个对象中的内容不一致时,那么字段的哈希值肯定不一样,所以可以直接存储对象,不需要去调用equals(),当两个对象的内容一致时,那么字段的哈希值是一样的,需要去调用一次equals()方法比较内容进行去重。这样就可以减少equals()方法的调用。
1.hashCode方法优化:
如果让hashCode()方法返回一个固定值,那么每个新添加的元素都要调用equals(Object obj)方法比较,那么效率较低
只需要让不同属性的值的元素产生不同的哈希值,那么就可以不再调用equals方法比较提高效率
1.7 TreeSet(底层是树)
TreeSet特点:可以对Set集合中的元素进行排序。
今日学习感受:今日学习集合中的单例集合,必须去理解的自己一定要去理解,然后里面方法很多,需要自己多去敲一遍,多敲,把核心的方法掌握,要有一个印象。学习的路上不要断断续续,一定要坚持。最后一句话:坚持就是胜利!
如果看到这篇博客的小伙伴,对你们有帮助,烦请点个赞。