上次学到了list的几种实现类,接着上次没学完的LinkedList

本文探讨了Java中的LinkedList数据结构,详细解析了其底层实现为双向链表的特点。在List总结部分,讨论了并发环境下一个线程使用迭代器访问数据,另一个线程修改数据时可能出现的问题,特别是`ConcurrentModificationException`。文章还深入讲解了对象赋值与克隆,区分了浅克隆和深克隆,并展示了如何实现深克隆,包括实现Serializable接口和使用对象流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类定义

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() { //没有初始化容积
 }
  • 创建Node对象,其中包含需要添加的元素值
  • Node对象的next为null
  • prev指向last
  • last对象的next为新建对象Node
  • last指向新建的Node对象

List总结

在这里插入图片描述
修改同时并发迭代访问的问题

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

public class T4 {
 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...."); 
 }
}

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

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

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;
 }
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值