数组
数组、集合都是对多个数据进行存储操作的,简称为容器,
PS:这里的存储指的是内存层面的存储,而不是持久化存储
数组:特点
数组一旦确定了长度,那么长度就确定了,不可以更改。
数组一旦声明了类型以后,数组中只能存放这个类型的数据,数组中只能存放同一种类型的数据。
缺点:
数组长度一旦指定,那么长度就被确定了,不可以更改。
删除、增加元素,效率低
数组中实际元素的数量是没有办法获取的,没有提供对应的方法或者属性来取。
数组存储:有序,可重复,对于无序的,不可重复的数组不能满足要求
数据结构图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/adca3047ed3c44ce8d5557a0b2a46ecc.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aO55L2w5aSn5aSa,size_20,color_FFFFFF,t_70,g_se,x_16)
Jdk1.8:ArrayList源码
底层是一个object[]数组,size数组中的有效长度,
ArrayList obj=new ArrayList()
调用空构造器
在jdk1.8在调用空构器的时候,底层elementData数组的初始化为{}
jdk1.7:给数组赋值为一个空数组
底层数组,在调用构造器的时候,数组长度初始化为10,扩容的时候扩展为原数组的1,5倍
jdk1.8:底层数组,在调用构造器的时候,底层数组长度为{},在调用add方法以后,底层数组才重新赋值为新数组,新数组的长度为10,节省了内存,在add后才创建了为10的数组
Vector
底层也是一个数组和一个int类型的elementCount有效长度
Vector v=new Vectou()调用构造器
默认初始值为10
ArrayList和Vector的联系和区别:
联系:底层都是数组的扩容,查询效率高,删除和插入效率低
区别:Arraylist的底层扩容为1.5倍,线程不安全,效率高,Vector的底层扩容为两倍,线程安全,效率低
LinkList
LinkList常用方法:
增加:addFirst() addLast() offer() offerFirst() offerLast()
删除:poll() pollFirst() pollLast() remove() removeLast()
修改:
查看:element() getFirst() getLast() indexOf() LastindexOf() peek()
判断:
遍历方式:
1、普通的for循环
2、增强for循环
3、利用迭代器
ArrayList数据结构:
物理结构:紧密结构
逻辑结构:线性表(数组)
LinkList数据结构:
物理结构:跳转结构
逻辑结构:线性表(链表)
模仿写一个linklist
package com.example.demo.service.impl;
public class Node {
private Node pre;
private Object obj;
private Node next;
public Node getPre() {
return pre;
}
public void setPre(Node pre) {
this.pre = pre;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"pre=" + pre +
", obj=" + obj +
", next=" + next +
'}';
}
}
package com.example.demo.service.impl;
public class MyLinkList {
//链表中一定有一个首节点
private Node first;
//链表中一定有一个尾节点
private Node last;
//计数器
int count;
//提供一个构造器
public MyLinkList(){}
public void add(Object o){
if (first==null){
Node node = new Node();
node.setPre(null);
node.setObj(o);
node.setNext(null);
//当前链中第一个变成n
first=node;
//当前链中最后一个节点变成n
last=node;
}else{
Node node = new Node();
node.setPre(last);//n的上一个节点一定是当前链中的最后一个last
node.setObj(o);
node.setNext(null);
//当前链表中的最后一个节点的下一个元素要指向n
last.setNext(node);
//将当前链表的最后一个一个节点变成n
last=node;
}
//链中元素的数量加一
count++;
}
public int getsize(){
return count;
}
//根据索引获得元素
public Object get(int index){
Node n=first;
for(int i=0;i<index;i++){
n=n.getNext();
}
return n.getObj();
}
}
class Test{
public static void main(String[] args) {
MyLinkList myLinkList = new MyLinkList();
myLinkList.add("aa");
myLinkList.add("bb");
myLinkList.add("cc");
System.out.println(myLinkList.getsize());
System.out.println(myLinkList.get(2));
}
}
LinkList源码分析:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0; //集合中的元素数量
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first; //链表的首节点
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
private static class Node<E> {
E item; //当前元素
Node<E> next; //指向下一个元素地址
Node<E> prev; //指向前一个元素地址
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
transient Node<E> last;//链表的末节点
/**
* Constructs an empty list.
*/
空构造器
public LinkedList() {
}
//在链表中添加一个元素
public boolean add(E e) {
linkLast(e);
return true;
}
//添加元素e
void linkLast(E e) {
final Node<E> l = last;//将链表中的last节点给l,如果是第一个元素的话l为null
final Node<E> newNode = new Node<>(l, e, null);
//将链表的last节点指向新创建的对象
last = newNode;
//如果添加的是第一个元素
if (l == null)
first = newNode;//将链表的first节点指向尾新节点
else//如果不是第一个节点
l.next = newNode;
size++; //集合中元素的数量
modCount++;
}
Node<E> node(int index) {
// 如果index在链表的前半段,那么从前往后找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//如果index在链表的后半段,从后往前找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
iterator() Iterator Iterable关系
Collection的set接口
hashSet() 特点:无序切不可重复
疑问点:
1、数组的长度是多少
2、数组的类型是什么
3、hashCode和equal真的使用了吗?
4、底层表达式是什么?
5、同一个位置的数据向前放,还是向后方
6、放入数组中的数据,是直接放的吗?是否封装为对象了?
实现类:LinkedHashSet:唯一,有序(按照输入进行输出)
其实就是在hashSet的基础上,多了一个总链表,这个总链表将放入的元素串在一起,方便有序和一个表达式计算在数组中的位置。
比较器的使用
1、int类型的比较:将比较的数据做差,然后返回一个int类型的数据,将这个返回的数据按照>0 =0 <0做比较
2、比较String类型的数据:String实现了一个comparable接口,这个接口有一个抽象方法cpmpareTo,String重写了这个方法。
3、比较double类型的数据:Double实现了一个comparable接口,这个接口有一个抽象方法cpmpareTo,Double重写了这个方法。
4、比较类的时候只需要继承comparable接口,内部重写compareTo()接口
5、外部比较器,优点大于内部比较器,可以灵活的写。
TreeSet
特点:唯一、无序、按照升序进行排列。
原理:底层二叉树(数据结构中的一个逻辑结构)