文章目录
List集合和Object类
1. List集合
1.1 List集合概述
List集合
特征:
有序 添加顺序和存储顺序一致
可重复 允许出现相同元素
三个常用实现类:
ArrayList[最常用] LinkedList Vector
1.2 List集合涉及到的方法
增
add(E e);
添加当前创建List集合约束类型的元素,到集合末尾。
add(int index, E e);
在List集合指定下标位置,添加符合类型的元素
addAll(Collection<? extends E> c);
添加参数集合到当前集合的末尾,要求参数集合存储元素类型为当前约束类型或者其子类
addAll(int index, Collection<? extends E> c);
在指定下标位置,添加参数集合到当前集合,要求参数集合存储元素类型为当前约束类型或者其子类
删
E remove(int index);
删除指定下标的元素,返回值是被删除的元素内容
remove(Objec obj);
在List集合中删除指定元素
removeAll(Collection<?> c);
删除两个集合的交集
retainAll(Collection<?> c);
保留两个集合的交集
clear();
清空整个集合
改
E set(int index, E e);
使用符合类型的元素,替换指定下标元素,返回值是被替换的元素对象
查
int size();
当前集合有效元素个数
boolean isEmpty();
判断当前集合是否为空
boolean contains(Object obj);
判断指定元素是否存在
boolean containsAll(Collection<?> c);
判断指定集合是否为当前集合的子集合
Object[] toArray();
获取当前集合所有元素的Object类型数组
int indexOf(Object obj);
获取指定元素在集合中第一次出现的下标位置
int lastIndexOf(Objec obj);
获取指定元素在集合中最后一次出现的下标位置
E get(int index);
获取集合中指定下标元素
List<E> subList(int fromIndex, int endIndex);
获取当前集合的子集合,要求从fromIndex开始,到endIndex结束。要头不要尾
1.3 代码演示
package com.qfedu.a_list;
import java.util.ArrayList;
import java.util.List;
/**
* List接口常用方法
* @author 期年之前ying@
*
*/
public class Demo2 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("张三");
list1.add("李四");
list1.add("王五");
list1.add("");
list1.add("华中路京广路交叉口向东200m 老北京炸酱面");
list1.add("大骨头");
System.out.println(list1);
list1.add(1, "湖南牛肉米粉");
System.out.println(list1);
List<String> list2 = new ArrayList<String>();
list2.add("沙县小吃");
list2.add("兰州拉面");
list2.add("黄焖鸡米饭");
list1.addAll(3, list2);
System.out.println(list1);
String string = list1.remove(5);
System.out.println(string);
System.out.println(list1);
String str = list1.set(3, "糖醋鲤鱼");
System.out.println(str);
System.out.println(list1);
System.out.println(list1.get(6));
System.out.println(list1.indexOf("大骨头"));
System.out.println(list1.lastIndexOf("大骨头"));
List<String> subList = list1.subList(2, 5);
System.out.println(subList);
}
}
1.4 ArrayList 可变长数组【重点】
1.4.1 ArrayList概述
ArrayList底层采用数组形式进行数据保存和处理。底层数组为Object类型,可以存储任意类型数据。存储对应具体数据类型通过创建ArrayList类对象约束,因为所有的添加操作都是通过该add和addAll方法完成的。
可变长数组是通过grow方法来进行底层数组容量扩容操作。扩容比例大约是原数组的1.5倍
ArrayList特征:【重点】
增删慢,查询快
特有方法:
可以使用所有的List集合对应方法。
了解两个特殊方法:
trimToSize();
当前底层数组容量缩小至有效元素个数,节约内存空间。时间换空间
ensureCapacity(int capacity);
判断当前容量是否满足需求
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// elementData是底层Object数组,用于数据存储,所谓的原数组
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 1. 创建新数组,2. copy原数据 3. 返回新数组地址
elementData = Arrays.copyOf(elementData, newCapacity);
}
1.4.2 特征分析
增删慢:
增加慢:
1, 有可能触发扩容操作。在扩容方法操作中,从原数组拷贝数据到新数组浪费时间,同时在扩容操作会出现无效内
存销毁问题,同样浪费时间。
2. 插入数据到指定下标位置,从插入位置开始,数组中的其他数据会整体向后移动。移动操作浪费时间。
删除慢:
1. 删除指定下标元素,数组中的元素整体向前移动。
2. 删除元素较多情况下,会导致空间冗余。空间效率较低
查询快:
【寻址操作】
ArrayList底层数据操作方式为数组方式,数组+下标获取对应元素的操作效率是非常高!!!是CPU根据对应【地址】直接访问操作。
1.4.3 【补充知识点 地址到底是什么】
开发中经常听说的地址到底是什么?
内存编号
内存中最小单位是【字节】,计算机按照每一个字节空间,进行编号操作。每一个字节都有一个独一无二的编号。
例如:
8GB内存,内存地址编号范围
8,589,934,592 编号总值,计算机中很多数据都是从0开始
范围:
0 ~ 8,589,934,591
计算机中所有的地址都是 十六进制展示方式 0x0 ~ 0x1 FFFF FFFF
null 是什么???
null ==> 0x0 内存中编号为0的字节空间,该字节空间受系统保护,任何程序不得读取或者写入数据到当前字节空间中。如果操作直接发送计算机最高权限命令 kill -9
null 一般用于引用数据类型变量初始化操作。如果出现了NullPointerException都是因为null地址空间读取或者写入操作。
NullPointerException问题 向刘不配提问 需要在QQ群发普通拼手气红包50元RMB
1.4.4 【补充知识点 数组内存地址分析图】
1.5 LinkedList 双向链表
1.5.1 双向链表
1.5.2 LinkedList常用方法
其他方法都是List集合规定方法:
addFirst(E e);
添加元素到链表头
addLast(E e);
添加元素到链表尾 ==> add(E e);
E removeFisrt();
删除链表头元素,返回值是被删除元素
E removeLast();
删除链表尾元素,返回值是被删除元素
E getFirst();
获取链表头元素
E getLast();
获取链表尾元素
队列:
先进先出,排队!!!
addLast(E e);
E getFirst();
E removeFirst();
堆栈:
先进后出,弹夹!!!
addFirst(E e);
E getFirst();
E removeFirst();
package com.qfedu.a_list;
import java.util.LinkedList;
/*
* LinkedList集合
*/
public class Demo3 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>();
list.add("唐人街");
list.add("你好,李焕英");
list.add("流浪地球");
list.add("战狼2");
list.add("人在囧途");
list.addLast("湄公河行动");
list.addFirst("魔童降世");
String first = list.getFirst();
String last = list.getLast();
String removeFirst = list.removeFirst();
String removeLast = list.removeLast();
System.out.println(list);
System.out.println(first);
System.out.println(last);
System.out.println(removeFirst);
System.out.println(removeLast);
}
}
2. Object类
2.1 Object类概述
Object是Java中所有类的基类,万物都是Object。
Object规定了每一个的唯一标记:
hashCode方法
比较方式
equals方法
字符串期望方法
String toString();
线程操作相关方法:
notify
notifyAll
wait
2.2 equals方法重写
boolean equals(Object obj);
是Object类内规定的两个对象比较使用方法,如果两个对象为同一个对象,返回true,否则返回false
【默认方式】
比较参数对象和调用方法对象的空间首地址。
地址相同的两个对象,一定是同一个对象。
/*
* 重写equals流程/内容
* 1. 原则不变,地址相同的两个对象为同一个对象,返回true
* 2. 参数类型和当前调用方法的数据类型一致!!!【数据类型判断】
* 3. 比较两个对象中数据元素
*/
@Override
public boolean equals(Object obj) {
// 1. 原则不变,地址相同的两个对象为同一个对象,返回true
if (this == obj) {
return true;
}
/*
* 2. 参数类型和当前调用方法的数据类型一致!!!【数据类型判断】
* instanceof 关键字
* obj instanceof Person
* 判断obj对应的数据到底是不是Person类型。是返回true,否则返回false
*/
if (!(obj instanceof Person)) {
return false;
}
/*
* 3. 比较两个对象中数据元素
* 当前参数对象通过以上两步验证,可以明确不是同地址对象,同时和当前方法调用对象类型一致。
* 可以明确obj引用数据类型指向的数据是一个Person对象。参数对象目前对外数据效果为Object
* 类型。我们需要拔掉衣服看本质,【强制类型转换】
*/
Person p = (Person) obj;
return this.id == p.id
/*
* this.name.equals(p.name)
* 该equals方法为String类型equals方法,也是重写Object类内的equals完成
* 为了满足字符串比较使用。
*
* 字符串比较绝对不允许使用 ==
*
* 【必须明确每一个方法的执行者到底是谁!!!】
*/
&& this.name.equals(p.name)
&& this.age == p.age;
}
2.3 hashCode方法重写
Java中的规定
两个对象通过equals方法比较结果为true,要求hashCode结果一致。
在Object类内
hashCode方法返回值数据是当前对象在内存空间中的地址十进制数据
@Override
public int hashCode() {
/*
* Objects工具类方法
* int hash(Object... values);
* ... 不定长参数,要求当前参数的类型为Object类型,参数个数不限制。
* 不定长参数在方法内实际上是一个数组形式
* Object... ==> 方法内就是一个Object[]
*
* hash方法可以将当前给予方法的参数进行hash计算,得到一个hash值。
* 这里要求参与equals方法比较的成员变量,全部放入到hash方法中进行
* 哈希值获取操作。
*/
return Objects.hash(id, name, age);
}
* hash方法可以将当前给予方法的参数进行hash计算,得到一个hash值。
* 这里要求参与equals方法比较的成员变量,全部放入到hash方法中进行
* 哈希值获取操作。
*/
return Objects.hash(id, name, age);
}