Vector

Vector

类定义
属于老版本提供的,从1.0,而ArrayList比较新,从1.2。属于线程安全的类,大部分方法上都有synchronized,一般用于要求线程安全的属性定义

public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable,
java.io.Serializable

数据存储

protected Object[] elementData; 采用也是数组的方式存储数据

构造器方法

public Vector() {
 this(10); //表示调用当前类的其它构造器,初始化容积为10,增长的步长值为0
}
public Vector(int initialCapacity) {
 this(initialCapacity, 0);
}
public Vector(int initialCapacity, int capacityIncrement) { //参数1是初始化容积,参数2是容
积增长的步长值
 super();
 if (initialCapacity < 0)
 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
 this.elementData = new Object[initialCapacity]//按照初始化容积值构建对应的数组
 this.capacityIncrement = capacityIncrement;
}

add新增元素的方法实现

public synchronized boolean add(E e) {// 线程安全的方法
		modCount++; // 修改次数+1
		ensureCapacityHelper(elementCount + 1); // 处理容积
		elementData[elementCount++] = e; // 在数组中存储元素
		return true;
	}

	private void ensureCapacityHelper(int minCapacity) {
		 // overflow-conscious code
		 if (minCapacity - elementData.length > 0) //需要储存的数据超出数组可以存放的数据格
		式,则需要进行增长
		 grow(minCapacity);
		 }

	private void grow(int minCapacity) {
		 int oldCapacity = elementData.length; //当前数组的长度,也就是可以存放的元素个数
		 int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement :
		oldCapacity); //新长度为原始长度的2倍或者原始长度+步长值
		 if (newCapacity - minCapacity < 0) //如果新长度不满足最小长度要求,则新长度为最小要
		求的长度
		 newCapacity = minCapacity;
		 if (newCapacity - MAX_ARRAY_SIZE > 0) //如果新长度大于最大数组长度进行长度处理
		 newCapacity = hugeCapacity(minCapacity);
		 elementData = Arrays.copyOf(elementData, newCapacity); //将原始数组中的数据拷贝到新
		数组中,并替换原始数组
		 }

	private static int hugeCapacity(int minCapacity) { // 和ArrayList处理一致
		if (minCapacity < 0) // OOM 内存溢出
			throw new OutOfMemoryError();
		return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
	}
  • 方法同步
  • 增长为2倍
  • 无参数创建时是10个长的数组

删除元素的方法remove(Object)

public boolean remove(Object o) {
		return removeElement(o);
	}

	public synchronized boolean removeElement(Object obj) {
		modCount++;
		int i = indexOf(obj); // 查找元素的索引值
		if (i >= 0) {
			removeElementAt(i); // 按照索引删除指定元素
			return true;
		}
		return false;
	}
	public synchronized void removeElementAt(int index) {
		modCount++;
		// 针对index索引值进行合法性验证
		if (index >= elementCount) {
			throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
		} else if (index < 0) {
			throw new ArrayIndexOutOfBoundsException(index);
		}

		int j = elementCount - index - 1; // 获取需要移动的元素个数
		if (j > 0) { // 通过拷贝的方式将数据的后续移动元素向前移动一位
			System.arraycopy(elementData, index + 1, elementData, index, j);
		}
		elementCount--; // 元素个数-1
		elementData[elementCount] = null; // 将数组末尾的元素值赋null
	}

LinkedList

类定义

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>,
Cloneable, java.io.Serializable
//Deque是队列接口,提供一个双端队列的访问方法实现

底层实现为双向链表

private static class Node<E> { //节点定义
 E item; //具体存储的数据
 Node<E> next; //向后的指针
 Node<E> prev; //向前的指针
}

LinkedList类中的数据存储

transient Node<E> first; //头指针,指向链表的第一个元素
transient Node<E> last; //尾指针,指向链表的最后一个元素

对应的构造器

public LinkedList() { //没有初始化容积
 }

add方法中

  • 创建Node对象,其中包含需要添加的元素值
  • Node对象的next为null
  • prev指向last
  • last对象的next为新建对象Node
  • last指向新建的Node对象

List总结

在这里插入图片描述

修改同时并发迭代访问的问题

需求:一个线程使用Iterator迭代访问集合中的元素,另外一个线程修改集合中的元素。临界资源为集合

public class A {
	public static void main(String[] args) throws Exception {
		List list = new ArrayList();
		for (int i = 0; i < 5; i++)
			list.add(i);
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + ",begin....");
			Iterator it = list.iterator();
			while (it.hasNext()) {
				Object tmp = it.next();
				System.out.println(tmp);
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + ",end....");
		}).start();
		Thread.sleep(100);
		System.out.println(Thread.currentThread().getName() + ",begin modify....");
		list.remove(0);
		System.out.println(Thread.currentThread().getName() + ",end modify....");
	}
}

ConcurrentModicationException

一个线程使用迭代器访问数据,另外一个线程修改数据

  • 如果仅仅只是修改集合中的元素值,可以正常执行
  • 如果修改了集合的结构则会报错ConcurrentModicationException add/remove

ArrayList中提供了Iterator接口的私有实现

private class Itr implements Iterator<E> {
	int expectedModCount = modCount;当构建迭代器对象时获取当前集合的修改次数

	报错的调用方法 @SuppressWarnings("unchecked")

	public E next() {
		checkForComodification(); // 检查修改的状态
		int i = cursor;
		if (i >= size)
			throw new NoSuchElementException();
		Object[] elementData = ArrayList.this.elementData;
		if (i >= elementData.length)
			throw new ConcurrentModificationException();
		cursor = i + 1;
		return (E) elementData[lastRet = i];
	}

	final void checkForComodification() {
	 if (modCount != expectedModCount) 如果修改次数不等于希望的修改次数则报异常
	 throw new ConcurrentModificationException();
	 }

快死异常主要用于检查遍历数据时的并发修改操作。主要作用是杜绝在遍历元素时其它线程修改了集合框架结构

对象赋值和克隆

对象赋值 Date now2=now;

两个变量now2和now中存放是同一个对象的地址,不管操作那个变量两个都受影响,因为now2和now是同一个对象

如果希望两个变量相互不影响,则只能通过克隆实现。Java中的克隆可以分为深克隆和浅克隆

public class Student{
 private long id;
 private Date birth;
}

如果需要支持克隆操作要求必须实现Cloneable接口

Object类中提供了clone()方法,这个方法是一个本地方法,是由虚拟机提供实现的

protected native Object clone() throws CloneNotSupportedException;

Cloneable接口属于标志性接口,没有具体的实现,具体实现实际上是Object类中提供的

  • 自定义类上要求实现Cloneable接口
  • 自定义类中要求实现clone方法,这个方法只需要调用父类的clone方法即可,一般不需要额外的处理
public class Test2 {
	public static void main(String[] args) throws Exception {
		Student s1 = new Student();
		s1.setId(100L);
		s1.setBirth(new Date());
		// 浅克隆,只是克隆s1对象,但是针对s1中的引用类型属性只是克隆地址
		Student s2 = (Student) s1.clone();
		s2.getBirth().setYear(9000);
		System.out.println(s2);
		System.out.println(s1);
	}
}

class Student implements Cloneable {
	private Long id;
	private Date birth;

	public Object clone() throws CloneNotSupportedException{ //定义该方法的原因是Object中的
	clone方法是protectedreturn super.clone();
	 }

	@Override
	public String toString() {
		return "Student [id=" + id + ", birth=" + birth + "]";
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}

}

深克隆
一般采用对象流实现。自定义类要求实现Serializable接口

public class Test2 {
	public static void main(String[] args) throws Exception {
		Student s1 = new Student();
		s1.setId(100L);
		s1.setBirth(new Date());
		// 浅克隆,只是克隆s1对象,但是针对s1中的引用类型属性只是克隆地址
		Student s2 = (Student) s1.deepClone();
		s2.getBirth().setYear(9000);
		System.out.println(s2);
		System.out.println(s1);
	}
}

class Student implements Serializable {
	private Long id;
	private Date birth; // 其中的属性也必须实现了序列化接口
	private transient String password;// transient表示该属性不能被序列化处理

	public Student deepClone() {
		Student res = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(this);
			ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
			res = (Student) ois.readObject();
			oos.close();
			ois.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return res;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", birth=" + birth + "]";
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Date getBirth() {
		return birth;
	}

	public void setBirth(Date birth) {
		this.birth = birth;
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值