类集复习
动态数组
1.基于数组实现
import java.util.Arrays;
/**
* @Author:Star
* @Date:Created in 8:05 2019/4/16
* @Description:自己实现的动态数组
*/
public class MyArray<E> {
//数组默认容量大小
private final static int DEFAULT_CAPACITY = 10;
//存放元素的数组
private E[] elementData;
//数组元素的大小
private int size;
public MyArray(){
this(DEFAULT_CAPACITY);
}
public MyArray(int initCap){
elementData = (E[]) new Object[initCap];
}
public void add(E e){
if(size == elementData.length){
//扩容
int oldCap = elementData.length;
int newCap = oldCap+((size>64)?(oldCap >> 1):oldCap);
if(newCap > Integer.MAX_VALUE - 8){
throw new IndexOutOfBoundsException("数组元素过多");
}
elementData = Arrays.copyOf(elementData,newCap);
}
elementData[size++] = e;
}
}
2.基于链表实现
public class MyArrayBasedOnListedList<E> {
private class Node{
E data;
Node next;
Node prev;
public Node(E data, Node next, Node prev) {
this.data = data;
this.next = next;
this.prev = prev;
}
}
//链表元素的大小
private int size;
//头节点
private Node head;
//尾节点
private Node tail;
//插入操作
public void add(E e){
Node node = new Node(e,null,tail);
if(tail == null){
head = tail = node;
}
tail.next = node;
tail = node;
size++;
}
}
Collection
1.出现版本
JDK1.2
2.解决问题
数组定长问题
3.定义
Collection接口是Java中保存单个对象的最顶层接口
4.继承关系
5.常用操作方法
-
添加元素:boolean add(E e);
-
删除元素:boolean remove(Object o);
-
查找元素:boolean contains(Object o);
-
取得集合大小:int size();
-
转为数组:Object[] toArray();
-
取得类集的迭代器:Iterator<E> iterator();
List
1.独有方法
index默认从0开始编号
-
根据索引下标取得元素:E get(int index);
-
根据索引下标修改元素,返回修改前的数据:E set(int index,E element);
2.空集合(含有空元素)
Collections.EMPTY_LIST
3.添加自定义类
List集合中添加自定义类
使用contains()、remove()需要equals()的支持
举个栗子,比如使用contains()方法时需要查找对象张三在不在列表中:如下
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(!(obj instanceof Person)){
return false;
}
Person person = (Person) obj;
return Objects.equals(age,person.age) && Objects.equals(name,person.name);
}
}
public class listTest {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三",12));
list.add(new Person("李四",13));
list.add(new Person("王五",14));
System.out.println("list中是否包含张三:"+list.contains(new Person("张三",12)));
}
}
4.子类及其关系
ArrayList、Vector、LinkedList的区别:
ArrayList:Vector区别
ArrayList | Vector | |
---|---|---|
出现版本 | JDK1.2 | JDK1.0 |
调用无参构造 | 懒加载策略,在构造方法阶段并不初始化对象数组,第一次添加元素时初始化对象数组大小为10 | 产生对象时,内部数组初始化为10的数组 |
扩容策略 | 新数组大小变为原数组的1.5倍 | 新数组大小变为原数组的2倍 |
线程安全性 | 异步处理,线程不安全,效率较高 | 在方法上加锁(synchronized同步方法),线程安全,效率较低(锁的是当前Vector对象,当前对象的所有方法均上锁,其他线程不可调用) |
遍历 | 不支持较老的迭代器Enumeration | 支持较老迭代器Enumeration |
特殊 | JDK内置的Stack继承Vector |
1.出现版本:
ArrayList JDK1.2
Vector JDK1.0(出现在List、Collection接口之前)
2.调用无参构造
Vector在无参构造执行后将对象数组大小初始化10
ArrayList采用懒加载策略,在构造方法阶段并不初始化对象数组,
在第一次添加元素时才初始化对象数组大小为10
3.扩容策略
ArrayList:扩容时,新数组大小变为原数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
Vector:扩容时,新数组大小变为原数组的2倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
4.线程安全性:
ArrayList采用异步处理,线程不安全,效率较高
Vector采用在方法上加锁,线程安全,效率较低(即使要使用线程安全的List,也不用Vector)
public synchronized boolean add(E e){}
5.遍历区别
Vector支持较老的迭代器Enumeration,ArrayList不支持
ArrayList、Vector的共同点
底层均使用数组实现
遍历时都支持Iterator/ListIterator/foreach
ArrayList、LinkedList区别
LinkedList底层采用双向链表实现(不存在扩容操作);特殊:是JDK Queue的一个子类(适用于增删频繁的情况下)
ArrayList底层采用数组实现(适用于经常查找的情况下)
ArrayList、LinkedList共同点
线程安全性:异步处理,线程不安全,效率较高
Set
不允许数据重复
本质是Map接口
public TreeSet() {
this(new TreeMap<E,Object>());
}
只实现了Collection接口,并没有对其扩充
1.常用子类
2.TreeSet
-
底层实现:红黑树
-
有序存储--按照升序存储;
-
不允许存放null;
-
不允许数据重复:利用实现Comparable接口/传入外部比较器接口的返回值判断是否重复
2.1升序存储
自定义类要想使用TreeSet,前提:
要么自定义类自己实现了Comparable接口
要么从外部传入一个该类的比较器对象,该类的比较器类实现了Comparator接口
2.2排序
2.2.1Comparable接口
(1)java.lang.Comparable:内部排序接口
(2)类实现了Comparable表示此类具备可比较的性质
(3)比较方法compareTo(T o);
public int compareTo(T o) {}
返回正数:表示当前对象>目标对象
返回0:表示当前对象=目标对象
返回负数:表示当前对象<目标对象
2.2.2Comparator接口
(1)java.util.Comparator:外部排序接口(策略模式)
(2)类本身不具备可比较的特性,专门有一个类来比较自定义类的大小
(3)
public int compare(T o1,T o2) {}
返回正数:表示当前对象>目标对象
返回0:表示当前对象=目标对象
返回负数:表示当前对象<目标对象
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
class Person{
private Integer age;
private String name;
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
public Integer getAge() {
return age;
}
public String getName() {
return name;
}
}
/*按照年龄升序排序,实现了外部比较器Comparator接口*/
class PersonAgeSec implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
if(o1.getAge() > o2.getAge()){
return 1;
}
if(o1.getAge() < o2.getAge()){
return -1;
}
return 0;
}
}
public class setTest {
public static void main(String[] args) {
PersonAgeSec p = new PersonAgeSec();
Set<Person> set = new TreeSet<>(p);
set.add(new Person(20,"A"));
set.add(new Person(23,"y"));
set.add(new Person(21,"B"));
System.out.println(set);
}
}
3.HashSet
-
无序存储
-
不允许元素重复:使用equals()与hashcode()共同判断元素是否重复
equals():判断对象的属性是否相等
hashcode():对象在内存中的地址根据hash算法转为int
//判断对象的属性值是否相等
public boolean equals(Object o){
if(this == o){
return true;
}
if(!(o instanceof Person)){
return false;
}
Person p = (Person) o;
return this.age.equals(p.age)
&& this.name.equals(p.name);
}
//判断地址是否相等
public int hashCode(){
return Objects.hash(name,age);
}
equals()和hashCode()的关系
equals()相同,hashCode一定相同
hashCode()相同,equals不一定相同