JAVA核心基础-集合(下)-Map集合与集合辅助类collections
1.Java集合类存放在java.util包中,是一个用来存放对象的容器(集合可以存放不同类型的对象,并不限数量)。
2.集合存放的都是对象的引用,而非对象本身。所以我们称集合中的对象就是集合中对象的引用。
3.集合只能存放对象。存放基本数据类型会转为对应的引用类型。例如:int->Integer。
泛型:即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
泛型的作用:
代码更加简洁
程序更加健壮
可读性和稳定性
泛型的特性:泛型只在编译阶段有效。在编译之后程序会采取去泛型化的措施。Java中的泛型只在编译阶段有效。
泛型的使用: 泛型类、泛型接口、泛型方法
泛型类:是在实例化类的时候指明泛型的具体类型
泛型接口与泛型类的定义及使用基本相同。
泛型方法:是在调用方法的时候指明泛型的具体类型 。
通配符类型:通配符类型一般是使用 ? 代替具体的类型实参。此处是类型实参,而不是类型形参
Company<? extends Emp>
?:泛型是Emp的子类类型,不需要确认具体的类型
Lambda表达式是Java 8 的重要更新,Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更加简洁的代码来创建只有一个抽象方法的接口(函数式接口)的实例。
如果Lambda表达式的代码块只有一条代码,程序就可以省略Lambda表达式中代码块的花括号。
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
filter(Predicate predicate):过滤不满足条件的元素
collect(toList()): 将stream流中的元素放入的list集合中。
map():一种类型的值转换成另外一种类型
max(): 找出集合中的最大值
sort(): 排序
List<Integer> list =new ArrayList<>();
list.add(3);
list.add(7);
list.add(1);
list.add(6);
list.add(2);
list =list.stream().sorted((a,b)->a>b ?1:-1).collect(Collectors.toList());//将集合从小到大排序
List接口是继承Collection接口。list接口有ArrayList和LinkedList两个实现类
ArrayList类是一个特殊的数组–动态数组。与数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。
ArrayList源码属性:
1.默认初始集合容量为:10。(初始大小为0,第一次添加时默认为10)
2.需要进行动态扩容时:当前容量扩容1.5倍。
3.集合容量最大值:Integer.Max_Value-8。
两个重要对象:elementData 和 size
1.elementData 是"Object[]类型的数组",它保存了添加到ArrayList中的元素。=
2.size 则是动态数组的实际大小。
特性:
1.ArrayList适合在对数据进行存储和访问的情况下使用,不适用频繁修改数据的场景。
2.在删除和插入元素时,需要移动元素,在元素较多情况下,效率会比较低。
用法:
一.初始化
1.不初始化容量
List<Integer> list =new ArrayList<>();//不初始化数组容量,当数组容量满时数组会自动以当前数组容量的1.5倍扩容
2.初始化容量
List<Integer> list =new ArrayList<>(10);//初始容量为10
二.添加元素
add(object value):将元素添加到集合的末端。
add(int index, Object obj):将元素添加到集合的指定index位置。
List<Integer> list =new ArrayList<>();
list.add(3);//集合末尾添加3
list.add(1,5);//在第一个位置添加5
三.删除元素
remove():可根据集合元素内容或下标删除。
List<Integer> list =new ArrayList<>();
list.add(3);//集合末尾添加3
list.add(4);//集合末尾添加3
list.add(1,5);//在第一个位置添加5
list.remove(3);//删除元素3
list.remove(1);//删除位置1的元素
四.查询元素
get(int index):根据下标找到集合元素
List<Integer> list =new ArrayList<>();
list.add(3);//集合末尾添加3
list.add(5);//集合末尾添加5
System.out.print(list.ger(1));
五.修改元素
set(int index, E element):将下标元素替换为新的元素
List<Integer> list =new ArrayList<>();
list.add(3);//集合末尾添加3
list.add(5);//集合末尾添加5
list.set(1,99);//将下标1的元素替换为99
链表(LinkedList)是一种在物理上非连续、非顺序的数据结构,由若干个节点(node)所组成。
LinkedList 实现了List接口,能对它进行列表操作。
LinkedList 实现了Queue接口,能当作队列使用。
LinkedList 实现了Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,能克隆。
LinkedList 实现了java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
特性:
1.分配内存空间不是必须是连续的;
2.插入、删除操作很快,只要修改前后指针就OK了,时间复杂度为O(1);而修改和查找效率较低,需要指针不断移动。
3.访问比较慢,必须得从第一个元素开始遍历,时间复杂度为O(n)
用法:
一.初始化
LinkedList<类> list = new LinkedList<类>();//构建一个空链表
LinkedList<类> list = new LinkedList(Collection<? extends E> c); //使用一个集合创建一个新的linkedList。
二.添加节点
add(E e):链表末尾添加元素
add(int index, E element):向指定位置插入元素
addFirst(E e):添加到第一个元素
addLast(E e),添加到最后一个元素
offer(E e):向链表末尾添加元素
offerFirst(E e):头部插入元素
offerLast(E e):尾部插入元素
三.删除节点
remove(int index):删除指定位置的元素
poll():删除并返回第一个元素
remove():删除并返回第一个元素
四.查找元素
get(int index):返回指定位置的元素
peek():返回第一个元素;
五.更改元素
set(int index, E element),设置指定位置的元素
六.其他api
栈:限定仅在表尾进行插入或删除操作的线性表,表尾为栈顶,表头为栈底,不含元素的空表称空栈。
**特点:**先进后出(LIFO)。类似于进电梯,先进去的人后出去,后进去的人先出去。
实现:
1.链表实现
和单链表相同,链式堆栈也是由一个个结点组成的,每个结点由两个部分组成,一个是存放数据元素的数据元素引用element,另一个是存放指向下一个结点的对象引用next。
堆栈有两端,插入数据元素和删除数据元素的一端为栈顶,另一端为栈底。链式堆栈都设计成把靠近栈头head的一端定义为栈顶。
2.数组实现
使用数组来模拟栈的实现,首先考虑到数组的长度是固定的,所以使用栈就必须给一个特定的长度,即最大长度MaxSize。自定义一个栈顶指针, 初始化数据为-1,因为数组的索引值是从0开始的,为了不引起冲突,从-1开始。
栈为空:当top=-1时,即等于初始化数据,没有任何元素存在数组中,则说明栈为空。
操作api:
pop():删除并返回栈顶元素。
push():向栈中存放元素
isEmpty():判断栈是否为空栈。
peek():获得栈顶元素
ArrayList线程不安全
Vector线程安全
所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector
Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。
ArrayLisy通过迭代器(Iterator)遍历的方式:
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(7);
Iterator iter = list.iterator();//构造迭代器
while(iter.hasNext()){
System.out.println(iter.next());//3 5 7
}
队列:也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。
队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。(FIFO先进先出)
用法
一.初始化
Queue<String> queue = new LinkedList<>();
二.常用api
offer():添加元素
poll():删除并返回第一个元素
peek():返回头元素
Deque是一个双端队列接口,继承自Queue接口,Deque的实现类是LinkedList、ArrayDeque、LinkedBlockingDeque,其中LinkedList是最常用的。
Deque是一个线性collection,支持在两端插入和移除元素。
常用方法:
set集合是Collection接口下一个子类,并且是不包含重复元素的collection
特点:
1.set集合是无序的.
2.set不允许重复(在set.add()方法中,添加已有的相同元素会返回false)
3.set集合没有索引
常用api:
boolean add(E e):给集合中添加一个元素,如果元素已经存在,添加失败并且返回false,成功返回true.
boolearn remove(Object o):如果此元素存在,则删除此元素,成功返回true,失败返回false.
boolean contains(Object o) :判断集合中是否含有该元素。
boolean equals(Object o):将指定的对象与此集合进行比较,判断是否相等
boolean isEmpty():判断集合是否为空
HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个实现类。HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。底层数据结构是哈希表。
特点:
1.不保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
2.HashSet不是同步的;
3.集合元素值可以是null;
class MyQueue {
private Stack<Integer> s1;//存储元素的主栈
private Stack<Integer> s2;//辅助栈,按队列顺序拿出或删除元素
public MyQueue() {
s1=new Stack<Integer>();
s2=new Stack<Integer>();
}
public void push(int x) {
s1.push(x);//直接将元素存入主栈中
}
public int pop() {
while(!s1.isEmpty()){
//将主栈元素放入辅助栈中
s2.push(s1.pop());
}
int x = s2.pop();
while(!s2.isEmpty()){
//将辅助栈元素放回主栈中
s1.push(s2.pop());
}
return x;
}
public int peek() {
while(!s1.isEmpty()){
s2.push(s1.pop());
}
int x =s2.peek();
while(!s2.isEmpty()){
s1.push(s2.pop());
}
return x;
}
public boolean empty() {
return s1.size()==0;
}
}