集合
1.类集关系图
2.集合框架概述
1、集合类的出现:面向对象语言对事物的体现的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
2、数组与集合的异同:数组和集合同是容器,数组既能存储基本数据类型,也能存储对象,集合只能存储对象,数组的长度是固定的,集合的长度是可变的,数组内存储的对象类型在创建时就已经确定了,而集合可以存储多种不同类对象。
3、集合类中有众多的子类对象,它们作为容器对数据的存储方式都不同,这种方式叫做数据结构。
3.集合运用场景
List: ArrayList和LinkedList
ArrayList:底层实现原理是数组,LinkedList:链表 数组遍历快,LinkedList增删元素块:
遍历的需求比增删除多,添加元素只是在末尾添加
遍历集合中的元素比较多
set:HashSet TreeSet LinkedHashSet
需要保证集合中的元素是唯一性,就用ser集合:
一批消息给用户,避免一次发送重复的内容,使用set集合?
保证添加的用户不能有重复,使用HashSet添加删除查询··TreeSet排序,后期数据库中可以把数据有序的输出
order by(数据库排序)
HashSet:一个没有重复元素的集合(去除重复元素)
LinkedHashSet和TreeSet:用作于算法题
Map:HashMap,linkedHashMp TreeMap
工作只要存储key-valueL选用HashMap
ConcurrentHashMap:挺多的,用作于本地缓冲:不想每次都需要网路请求数据,在本地做本地缓存文件,监听数据的变量,如果数据变动
对于的值给更新
LinkedHashMap和Treemap在开发中用的不多,当做刷算法题
一、Collection集合类(单值存储)
2.ArrayList
1.对于增加删除慢,查找快。
2.ArrayLisr<Integer> date = new ArrarList();
·泛型的类型必须是包装类
//arrayList.ensureCapacity(14);//指定数组长度
arrayList.trimToSize();//将此 ArrayList实例的容量调整为列表的当前大小
arrayList.add('A');
arrayList.add("B");
arrayList.add(9);
arrayList.add("哈哈");
arrayList.add('A');
arrayList.add("B");
arrayList.add(9);
arrayList.add('A');
arrayList.add("B");
arrayList.add(9);
arrayList.add("哈哈");
arrayList.add('A');
arrayList.add("B");
arrayList.add(9);
//arrayList.removeAll(arrayList);//移除arrayList这个集合中所有元素
// arrayList.clear();//清除数组中所有元素
arrayList.clone();
for (Object arr:arrayList){
System.out.print(arr+" ");
}
System.out.println(arrayList.contains("B"));//查找数组中是否包含“B”;
System.out.println(arrayList.indexOf(9));//查找数据在数组中第一个出现的位置,如果没有则返回-1
System.out.println(arrayList.isEmpty());//数组为空返回true,反之为false
System.out.println(arrayList.iterator().next());
System.out.println(arrayList.lastIndexOf("哈哈"));//最后一次出现的位置
System.out.println(arrayList.listIterator(9));//返回当前迭代器(地址)
System.out.println(arrayList.listIterator(10).next());//返回当前迭代器地址对应的元素值
Object[] sc=arrayList.toArray();//以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
for (Object ac:sc){
System.out.print(ac+" ");//变为了数组
}
System.out.println();
System.out.println(arrayList.subList(2,10));//输出[9, 哈哈, A, B, 9, A, B, 9]
}
3.Vector(使用方法和ArrayList相差不多,具体看API文档)
4.LinkedList
使用的是双向链表结构,对于增删快,查找满
LinkedList<Integer> date=new LinkedList<>();
date.add(1);
date.add(2);
date.add(3);
//date.addFirst(3);//放在第一个
System.out.println(date);
Integer i= date.removeFirst();//取出第一个
System.out.println(i);
//压栈
date.push(100);
date.push(200);
//弹栈
Integer ii=date.pop();
System.out.println(ii);//先进后出
}
}
5.Iterator和ListIterator
5.1迭代器
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
调用方法,得到的迭代器行为类似指针的对象,(迭代器是抽象的)
例子:
ArrayList<Integer> date=new ArrayList<>();
date.add(1);
date.add(2);
date.add(3);
date.add(4);
//输出集合的内容可以不用循环遍历,用迭代器
// Iterator<Integer> integer=date.iterator();//获得date的地址
// while (integer.hasNext()==true){//判断integer是否有下一个数据
// System.out.println(integer.next());//如果判断有下一个数据,就直接输出下一个数据。
// //需要注意的是,指针最开始指的是第一个数的上面位置,它的下一个数据就是第一个数据
// }
// integer.remove();//将迭代器新返回的元素删除(先进后出)
// System.out.println("["+date.size()+"]");
// System.out.println("------------------");
// for (int i = 0; i < date.size(); i++) {
// System.out.println(date.get(i));
// }
ListIterator<Integer> iterator=date.listIterator();
iterator.add(100);//添加在1的前面;
iterator.next();
iterator.next();
iterator.set(200);//指针向下移两次,把2变成200
iterator.previous();
iterator.previous();
iterator.previous();//向上移动迭代器三次才能遍历全部数据
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
6.forEach
6.1作用
1,增强For循环
2,只能用于迭代数组,或集合(Collection)
6.2语法
语法:
for(数据类型 变量名:集合或数组名){}
二.set(不保证顺序)
set集合是使用Map集合的 键 来存储的数据,值是后台使用的统一值、
保证集合中元素的唯一性
Hashset:一般用于增加删除查询
TreeSet:一般用于排序
2.1Hashset
2.1.1请简述 HashSet 去除重复元素的原理
A:HashSet底层数据结构是哈希表(是一个元素为链表的数组)
B:哈希表底层依赖两个方法:hashCode()和equals()
执行顺序:
首先比较哈希值是否相同
相同:继续执行equals()方法
返回true:元素重复了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合
C:元素唯一性由hashCode()和equals()保证的,二者缺一不可
1-hashSet属于set的子类,是属于set的实现类
2-hashSet是散列存放,所以不能按正常的顺序输出,并且不能存储相同的值。
HashSet<String> hashSet=new HashSet<>();
hashSet.add("床前明月光");
hashSet.add("疑是地上霜");
hashSet.add("举头望明月");
hashSet.add("低头思故乡");
Iterator<String> iterator=hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());//散装输出,即不按照顺序输出
}
结果:
举头望明月
床前明月光
疑是地上霜
低头思故乡
2.3TreeSet
1-是利用有序的二叉树存储(有序的存放)
例子:
//存储有序是根据数据的顺序,而不是你存入的顺序
TreeSet<String> date=new TreeSet<>();
date.add("B");
date.add("C");
date.add("A");
date.add("D");
for (String s:date){
System.out.println(s);
}
输出:A B C D
2-此类的iterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时间修改集合,除了自己的remove方法之外,迭代器将抛出ConcurrentModificationException异常(一般都是安全失败的)除了特殊声明外的。
2.3.1Comparable
如果TreeSet存入的是系统不能比较的内容,这时候我们就需要用该类来实现comparable接口,然后重写comparable的抽象方法,以此来比较输入的类容
注意:如果存入一样大的数据,就不会存储
如: TreeSet<Person> date = new TreeSet<>();
Person p1 = new Person("张三",12);
Person p2 = new Person("李四",19);
date.add(p1);
date.add(p2);
for (Person p:date){
System.out.println(p.toString());
}
}
}
class Person implements Comparable<Person>{//必须实现Comparable接口,然后自己在抽象方法重写比较内容
private String name;
private int age;
@Override
public int compareTo(Person o) {//第一次的值直接传入,第二次的值和第一次比较在传入
//this 与 o比较
//返回值:正数this大、负数this小、0相等
if (this.age>o.age){
return 1;
}else if (this.age<o.age){
return -1;
}else {
return 0;
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
2.3.2简述 Comparable 和 Comparator 两个接口的区别
Comparable和Comparator都是用来实现集合中元素的比较、排序的。
Comparable是在集合内部定义的方法实现的排序,位于java.lang下。
Comparator是在集合外部实现的排序,位于java.util>下。Comparable是一个对象本身就已经支持自比较所需要实现的接口,如String、Integer自己就实现了Comparable接口,可完成比较大小操作。自定义类要在加入list容器中后能够排序,也可以实现Comparable接口,在用Collections类的sort方法排序时若不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparatorl类体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。总而言之Comparable是自已完成比较,Comparator是外部程序实现比较。
三、Map
Map集合存储的是一个个的 键值对 的数据
Map集合的 键 不能重复,一个键对应一个值
Map<K V>泛型指定一个键的类型,一个值得类型
Map集合存入数据遍历输出的方法:
首先用 KeySet 取出键值、它属于Set类型,然后遍历Key,然后用 get(Object Key)获取值
Map集合存入数据:
Put(K key,V value) 如果存储数据时,key已经有对应的值,那么新值替换旧值,然后返回旧值,如果没有对应的值,则返回null
1.HashCode(Object)
-计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
-Java对象的eqauls方法和hashCode方法是这样规定的:
1、相等(相同)的对象必须具有相等的哈希码(或者散列码)。
原因 :
想象一下,假如两个Java对象A和B,A和B相等(eqauls结果为true),但A和B的哈希码不同,则A和B存入HashMap时的哈希码计算得到的HashMap内部数组位置索引可能不同,那么A和B很有可能允许同时存入HashMap,显然相等/相同的元素是不允许同时存入HashMap,HashMap不允许存放重复元素。
2、如果两个对象的hashCode相同,它们并不一定相同。
原因:
也就是说,不同对象的hashCode可能相同;假如两个Java对象A和B,A和B不相等(eqauls结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置建立一个链接表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。
2.HashMap
1.HashMap概述:
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
2.HashMap的数据结构:
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。首先,HashMap类的属性中定义了Entry类型的数组。Entry类实现java.ultil.Map.Entry接口,同时每一对key和value是作为Entry类的属性被包装在Entry的类中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rnHtfgjO-1594040160846)(D:\kaikeba\任务卡提交作业\第四章核心类库训练\集合(4-3)\0611-尹智辉-集合-2020-7-5\图片\哈希表)]
散列因子是指(负载因子):当75%哈希桶的被装了数据时,哈希桶就会进行二倍扩容
3.HashMap代码实现
//hashMap(顺序)/Hashtable(和HashMap执行顺序不同,倒叙)/ConcurrentHashMap
//TreeMap
//LinkedHashMap
//以上用法一样
HashMap<Integer,String> date=new HashMap<>();
date.put(1,"A");
date.put(2,"B");
date.put(3,"C");
date.put(4,"D");
String key=date.get(1);
System.out.println(key);//输出A
Set<Integer> set=date.keySet();//取出键,转成set集合
for (Integer in:set){
System.out.println(in+"->"+date.get(in));
}
Collection<String> values=date.values();//变为Collection集合
for(String value: values){
System.out.println(value);//只有值
}
3.哈希值
哈希值就是文件的身份证,不过比身份证还严格。他是根据文件大小,时间,类型,创作着,机器等计算出来的,很容易就会发生变化,谁也不能预料下一个号码是多少,也没有更改他的软件。
注意:所以不能存在键的位置,键是获取哈希值的位置,当你把自定义对象内容存在键时就不易更改了,除非你存在其他地方
四、Java中 List、Set、Map 之间的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rrm0u5Af-1594040160848)(D:\kaikeba\任务卡提交作业\第四章核心类库训练\集合(4-3)\0611-尹智辉-集合-2020-7-5\图片\区别.png)]
1.list(列表)
List的元素以线性方式存储,可以存放重复对象,List主要有以下两个实现类:
ArrayList : 长度可变的数组,可以对元素进行随机的访问,向ArrayList中插入与删除元素的速度慢。 JDK8 中ArrayList扩容的实现是通过grow()方法里使用语句newCapacity = oldCapacity + (oldCapacity >> 1)(即1.5倍扩容)计算容量,然后调用Arrays.copyof()方法进行对原数组进行复制。
LinkedList: 采用链表数据结构,插入和删除速度快,但访问速度慢。
2.Set(集合)
Set中的对象不按特定(HashCode)的方式排序,并且没有重复对象,Set主要有以下两个实现类:
HashSet: HashSet按照哈希算法来存取集合中的对象,存取速度比较快。当HashSet中的元素个数超过数组大小*loadFactor(默认值为0.75)时,就会进行近似两倍扩容(newCapacity = (oldCapacity << 1) + 1)。
TreeSet :TreeSet实现了SortedSet接口,能够对集合中的对象进行排序。
3.Map(映射)
Map是一种把键对象和值对象映射的集合,它的每一个元素都包含一个键对象和值对象。 Map主要有以下两个实现类:
HashMap:HashMap基于散列表实现,其插入和查询<K,V>的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。
LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得<K,V>的顺序是其插入次序,或者是最近最少使用(LRU)的次序。
TreeMap:TreeMap基于红黑树实现。查看<K,V>时,它们会被排序。TreeMap是唯一的带有subMap()方法的Map,subMap()可以返回一个子树。
4.存储特点
一丶存放
List存放元素是有序,可重复
Set存放元素无序,不可重复
Map元素键值对形式存放,键无序不可重复,值可重复
二丶取出
List取出元素for循环,foreach循环,Iterator迭代器迭代
Set取出元素foreach循环,Iterator迭代器迭代
Map取出元素需转换为Set,然后进行Iterator迭代器迭代,或转换为Entry对象进行Iterator迭代器迭代
散列表实现,其插入和查询<K,V>的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。
LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得<K,V>的顺序是其插入次序,或者是最近最少使用(LRU)的次序。
TreeMap:TreeMap基于红黑树实现。查看<K,V>时,它们会被排序。TreeMap是唯一的带有subMap()方法的Map,subMap()可以返回一个子树。
## 4.存储特点
一丶存放
List存放元素是有序,可重复
Set存放元素无序,不可重复
Map元素键值对形式存放,键无序不可重复,值可重复
二丶取出
List取出元素for循环,foreach循环,Iterator迭代器迭代
Set取出元素foreach循环,Iterator迭代器迭代
Map取出元素需转换为Set,然后进行Iterator迭代器迭代,或转换为Entry对象进行Iterator迭代器迭代