目录
Collection接口的Iterator(迭代器)遍历元素
有关集合的体系图
Iterable 可迭代
Collection 集合
Vector 向量
Collection 接口的讲解
1)Collection实现的子类可以存放多个元素,每个元素可以是Object
2)Collection实现的子类,有些可以存放相同的元素,有些不能存放相同的元素
List可以存放相同的元素,Set不可以存放相同的元素
3)Collection实现的子类,有些是有序的(List),有些是无序的(Set)
4)Collection没有直接实现的子类,是通过他的子接口List来实现的
接口的常用实现方法(增删改查)
package practice2;
import java.util.ArrayList;
import java.util.List;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList<>();
//1.add:添加单个元素 addAll:添加所选集合元素
list.add("hlk");
list.add(123);
list.add(true);
System.out.println(list);// [hlk, 123, true]
List list1 = new ArrayList();
list1.add("nihao");
list1.add(12);
list.addAll(list1);
System.out.println(list);//[hlk, 123, true, nihao, 12]
// 2.remove: 删除指定元素,可以选择序号。也可以选择指定的内容 removeAll删除所选集合的元素
list.remove(0);
System.out.println(list);// [123, true, nihao, 12]
list.removeAll(list1);
System.out.println(list);//[123, true]
//3.contains:查找元素是否存在 containAll:查看集合里面有没有所选的集合
System.out.println(list.contains(123));//true
System.out.println(list.containsAll(list1));//false
//4.size:获取元素的个数
System.out.println(list.size());//2
//5.isEmpty:判断是否为空
System.out.println(list.isEmpty());//false
//6.clear 清空所有的元素
list.clear();
System.out.println(list);//[]
}
}
Collection接口的Iterator(迭代器)遍历元素
1)Iterator对象成为迭代器,主要用于遍历Collection集合中的元素
2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
3)参考Iterator的结构图
在调用Iterator.next方法的前面必须调用iterator.hasnext()进行检测,如果不调用会出现异常
4)Iterator仅用于遍历集合,Iterator本身并不存放对象
Iterator迭代器的代码实现(快捷键itit)
package practice2;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(new Book("西游记",13));
collection.add(new Book("红楼梦",14));
collection.add(new Book("三国演义",15));
collection.add(new Book("水浒传",16));
//1.先得到col对应的迭代器
Iterator iterator = collection.iterator();
//2.使用while循环遍历
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
//Book{name='西游记', price=13.0}
//Book{name='红楼梦', price=14.0}
//Book{name='三国演义', price=15.0}
//Book{name='水浒传', price=16.0}
}
//3.退出while循环后,这时iterator迭代器,指向最后的元素,然后会报错
//4.如果希望再次遍历,需要重置我们的迭代器
iterator = collection.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
//Book{name='西游记', price=13.0}
//Book{name='红楼梦', price=14.0}
//Book{name='三国演义', price=15.0}
//Book{name='水浒传', price=16.0}
}
}
}
class Book{
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
用增强for循环遍历元素(可以用于集合也可用于数组)
使用增强for循环也可以做到像迭代器那样的遍历元素
1)使用增强for,在collection集合
2)使用增强for,底层仍然是迭代器
3)增强for可以理解成就是简化版本的 迭代器遍历
4)快捷键方式 I
代码实现展示
package practice2;
import java.util.ArrayList;
import java.util.Collection;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(new Book("西游记",13));
collection.add(new Book("红楼梦",14));
collection.add(new Book("三国演义",15));
collection.add(new Book("水浒传",16));
for(Object obj : collection){
System.out.println(obj);
}
int[] nums = {1,2,3,4,5};
for(int i : nums){
System.out.println(i);
}
}
}
有关list接口特点和常用语法
特点
1)list集合类中元素有序(即添加顺序和取出顺序一致),且可重复
2)List集合中的每个元素都有其对应的顺序索引,即支持索引,从零开始
3)JDK API中list接口的实现类,常用的有Arraylist,LinkList,Vector
用代码展示
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//1:list集合类中元素有序(即添加顺序和取出顺序一致),且可重复
List list = new ArrayList();
list.add(123);
list.add("xiMing");
list.add("hlk");
System.out.println(list);//[123, xiMing, hlk]
//2:List集合中的每个元素都有其对应的顺序索引,即支持索引,从零开始
System.out.println(list.get(1));//xiMing
}
}
常用语法
package practice2;
import java.util.ArrayList;
import java.util.List;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
//1:void add(int index, Object ele):在index位置插入ele元素
//如果没有写那么默认加入在最后一个
list.add(1,"hsp");
System.out.println(list);//[张三丰, hsp, 贾宝玉]
//2:void addAll(int index, Collection eles):从index位置开始将eles中的所有元素位置加进来
List list1 = new ArrayList();
list1.add(123);
list1.add("nb");
list.addAll(1,list1);
System.out.println(list);// [张三丰, 123, nb, hsp, 贾宝玉]
//3:Object get(int index ):返回指定index位置的元素
System.out.println(list.get(1));// 123
list.add(123);
//4:int indexOf(Object obj):返回obj在当前集合中首次出现的位置
//5:int lastIndexOf(Object obj):返回obj在当前集合中出现的最后位置
System.out.println(list.indexOf("nb"));//2
System.out.println(list.lastIndexOf(123));//5
//6:remove移除第几个或者具体的元素
list.remove("nb");
list.remove(1);
System.out.println(list);// [张三丰, hsp, 贾宝玉, 123]
//7:Object set(int index , Object ele) 相当于替换掉所选中的元素
list.set(3,12345);
System.out.println(list);// [张三丰, hsp, 贾宝玉, 12345]
//8.List subList(int fromIndex, int toIndex)返回从fromIndex到toIndex位置的子集合,前闭后开
list.subList(0,2);//实际返回的就是0和1号元素
System.out.println(list.subList(0,2));
}
}
list的三种遍历方式
1)迭代器
2)增强for
3)普通for、
package practice2;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//list接口的实现子类Vector LinkedList
List list = new ArrayList();
list.add(123);
list.add(123);
list.add(123);
//1.遍历
// 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
//2.增强for循环
for (Object o : list) {
System.out.println(o);
}
//3.使用普通for
for (int i = 0; i < list.size() ;i++) {
System.out.println(list.get(i));
}
}
}
有关ArrayList底层结构和源码分析
注意事项
1)ArrayList可以加入null,并且多个
2)ArrayList是由数组来实现数据存储的
3)ArrayList基本等同于Vector,除了ArrayList是线程不安全,在多线程的时候用Vector
源码分析
1)ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData (用的Object 所以所有的元素都可以放)
transient表示瞬间的,短暂的,表示改属性不会被序列号
2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
有关Vector底层结构和源码分析
基本介绍
1)定义类的说明
2)Vector底层也是一个对象数组,protected Object[] elementData
3)Vector是线程同步的,即线程安全,Vector类的操作方法都有synchronized
4)在开发中需要线程同步安全是,考虑使用Vector
源码分析
Vector和ArrayList的比较
有关LinkList底层结构
LinkList的全面说明
1)LinkList底层实现饿了双向链表和双端队列的特点
2)可以添加任意元素(元素可以重复),包括null
3)线程不安全,没有实现线程同步
LinkedList的底层操作机制
1)LinkedList底层维护了一个双向链表
2)LinkedList中维护了两个属性first和last分别指向 首节点和尾节点
3)每个节点(Node对象),里面又维护了prev,next,item三个属性,期中通过prev指向前一个,通过next指向后一个节点,最终实现双向链表
4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
ArrayList和LinkedList比较
如何选择ArrayList和LinkedList
1)如果我们的改查的操作多,选择ArrayList
2)如果我们的增删操作多,选择LinkedList
3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另一个模块使用的是LinkedList,也就是说,药根据业务来进行选择
set接口和常用方法
set接口的基本介绍
1)无序(增加和取出的顺序不一致),没有索引
2)不允许重复元素,所以最多包含一个null
3)JDK API 中Set接口的实现类有:
set接口的常用方法
和List接口一样,Set接口也是Collection的子接口,因此常用方法和Collection一样
set接口的遍历方式
同Collection的遍历方式一样,因为Set接口是Collection接口的子接口
1)可以使用迭代器
2)增强for
3)不能使用索引的方式来获取
HashSet的全面说明
1)HashSet实现了Set接口
2)HashSet实际上是HashMap
3)可以存放null值,但是只能存放一个
4)HashSet不保证元素是有序的,没取决于hash后,再确定索引的结果
5)不能有重复元素/对象,再前面Set接口使用已经讲过
链表底层机制说明
分析HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
模拟下简单的数组和链表结构
package practice2;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//模拟一个HashSet的底层(HashMap的底层结构)
//1:创建一个数组,数组的类型是Node[]
//2:有些人,直接把Node[]数组称为表
Node[] table = new Node[16];
System.out.println(table);
//3.创建结点
Node john = new Node("john",null);
table[2] = john;
Node jack = new Node("jack",null);
john.next = jack;
Node Rose = new Node("Rose",null);
jack.next = Rose;
}
}
class Node{//结点,存储数据,可以指向下一个结点,从而形成链表
Object item;//存放数据
Node next;//指向下一个结点
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
添加元素底层的实现
1)Hash底层是HashMap,第一次添加时,table数组扩容到16,临界值是16 ,加载因子就是0.75*16 =12 ,当里面的数组内容加到12的时候,就会扩容到16*2 =32依此类推
2)添加一个元素时,先得到hash值 -会转成 ->索引值
3)找到存储数据表table,看这个索引位置是否已经存放的铀元素
4)如果没有,直接加入
5)如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加再最后
6)在Java8中,如果一条链表的元素个数到达8,且table大小>=64就会进行树化
package practice2;
import java.util.HashSet;
import java.util.Objects;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Dog(13,"hlk"));
hashSet.add(new Dog(13,"hlk"));
System.out.println(hashSet);
}
}
class Dog{
private int age;
private String name;
public Dog(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return age == dog.age && Objects.equals(name, dog.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
LinkedHashSet的解读
LinkedHashSet的全面说明
1)LinkedHashSet是HashSet的子类
2)LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
3)LinkedHashSet是根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
4)LinkedHashSet不允许添加重复元素
LinkedHashSet添加的元素顺序
主要看韩老师的这个图理解LinkedHashSet的图的元素添加顺序
和HashSet的最大优点就是有顺序,遍历顺序一致
有关Map的体系图
Properties 性能,属性
Map接口和常用方法
Map接口特点(有点像python中的字典)
1)Map与Collection并列存在。用于保存具有映射关系的数据Key - Value(双列元素)
2)Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3)Map中的 key 不允许重复,原因和HashSet一样(因为hashcode一样,放一样的位置)
如果key值重复了,那么后面的值会代替掉前面的值
4)Map中的 value是可以重复的
5)Map中的key可以为null,value也可以为null,Map中的key只能有一个null,但是value可以有多个null
6)常用String类作为Map的key
形象一点的Map图
Map存放数据的key - vlaue示意图,一队k - v是放在一个HashMapNode中的,有因为Node实现了,Entry接口,有些书上也说一对k-v就是一个Entry
Map接口和常用方法
1)put:添加
2)remove:根据键删除映射关系
3)get:根据键获得值
4)sieze:获取元素个数
5)isEmpty:判断元素个数是否为0
6)containKey:查找键是否存在
//这个算是小儿科了,我就不放代码了,和之前的都差不多的
Map接口的遍历6种形式
1)containsKey:查找键是否存在
2)keySet获取所有的键
3)entrySet获取所有关系的k -y
4)values获取所有的值
package practice2;
import java.util.*;
public class Test {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//演示map接口的常用方法
Map map = new HashMap();
map.put("邓超","孙俪");
map.put("王宝强","马蓉");
map.put("宋吉","马蓉");
//1.第一种使用keyset来判断
//(1)增强for
Set keyset = map.keySet();
for (Object key : keyset) {
System.out.println(key+ "-" + map.get(key));
}
//(2)迭代器
System.out.println("------------------------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "--"+ map.get(key));
}
System.out.println("----------");
//2.第二种是把所有的values取出
Collection values = map.values();
//(1)增强for
for (Object value : values) {
System.out.println(value);
}
//(2)迭代器
System.out.println("-----------");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object value = iterator1.next();
System.out.println(value);
}
//3.通过EntrySet来获取来获取key - value
System.out.println("-----------");
Set entrySet = map.entrySet();
//(1)增强for
for (Object entry :entrySet) {
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "--" +m.getValue());
}
//(2)迭代器
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object entry = iterator2.next();
Map.Entry Entry = (Map.Entry) entry;
System.out.println(Entry.getKey()+"--"+Entry.getValue());
}
}
}