首页 文章 精选 留言 我的

精选列表

搜索[序列化框架],共10000篇文章
优秀的个人博客,低调大师

aop 框架底层的 Javassist API

javassist 可以实现 java 的动态性 比如在 java 程序运行时, 动态的添加新方法修改类结构 该类 API 与 java.lang.Class API 相似 动态的创建一个 class 对象 ClassPool pool = ClassPool.getDefault(); /** 声明类名及包名 */ CtClass ctClass = pool.makeClass("com.znsd.javassist.Emp"); /** 创建属性 */ CtField ctField = CtField.make("private Integer id;", ctClass); ctClass.addField(ctField); /** 创建方法 */ CtMethod ctMethod = CtMethod.make("public Integer getId(){return id;}", ctClass); ctClass.addMethod(ctMethod); // 将生成好的类输出在本地磁盘上 ctClass.writeFile("F:/"); System.out.println("执行成功!"); 获取类的基本信息 ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.get("com.znsd.javassist.Student"); System.out.println("获取类路径: " + ctClass.getName()); System.out.println("获取类名: " + ctClass.getSimpleName()); System.out.println("获取父类: " + ctClass.getSuperclass()); System.out.println("获取接口: " + ctClass.getInterfaces()); 动态创建方法 ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.get("com.znsd.javassist.Student"); /** 声明好一个方法 */ CtMethod ctMethod = CtNewMethod.make("public int add(int i, int j){return i + j;}", ctClass); ctClass.addMethod(ctMethod); /** 获取 Class 对象用于调用创建好的方法 */ Class classes = ctClass.toClass(); Object newInstance = classes.newInstance(); Method declaredMethod = classes.getDeclaredMethod("add", int.class, int.class); Object result = declaredMethod.invoke(newInstance, 110, 120); System.out.println(result); 实现 aop 编程 ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.get("com.znsd.javassist.Student"); CtMethod ctMethod = ctClass.getDeclaredMethod("show"); // 在方法前插入一些代码 ctMethod.insertBefore("System.out.println(\"aop:before\");"); // 在方法后插入一些代码 ctMethod.insertAfter("System.out.println(\"aop:after\");"); // 指定在哪一行插入一些代码 ctMethod.insertAt(29, "System.out.println(\"insertAt\");"); Class classes = ctClass.toClass(); Object newInstance = classes.newInstance(); Method method = classes.getDeclaredMethod("show"); method.invoke(newInstance);

优秀的个人博客,低调大师

Java 集合框架 ArrayList 源码剖析

ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量(capacity),表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。前面已经提过,Java泛型只是编译器提供的语法糖,所以这里的数组是一个Object数组,以便能够容纳任何类型的对象。 size(), isEmpty(), get(), set()方法均能在常数时间内完成,add()方法的时间开销跟插入位置有关,addAll()方法的时间开销跟添加元素的个数成正比。其余方法大都是线性时间。 为追求效率,ArrayList没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用Vector替代。 方法剖析 set() 既然底层是一个数组ArrayList的set()方法也就变得非常简单,直接对数组的指定位置赋值即可。 public E set(int index, E element) { rangeCheck(index);//下标越界检查 E oldValue = elementData(index); elementData[index] = element;//赋值到指定位置,复制的仅仅是引用 return oldValue; } get() get()方法同样很简单,唯一要注意的是由于底层数组是Object[],得到元素后需要进行类型转换。 public E get(int index) { rangeCheck(index); return (E) elementData[index];//注意类型转换 } add() 跟C++ 的vector不同,ArrayList没有bush_back()方法,对应的方法是add(E e),ArrayList也没有insert()方法,对应的方法是add(int index, E e)。这两个方法都是向容器中添加新元素,这可能会导致capacity不足,因此在添加元素之前,都需要进行剩余空间检查,如果需要则自动扩容。扩容操作最终是通过grow()方法完成的。 private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//原来的3倍 if (newCapacity – minCapacity < 0) newCapacity = minCapacity; if (newCapacity – MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity);//扩展空间并复制 } 由于Java GC自动管理了内存,这里也就不需要考虑源数组释放的问题。 空间的问题解决后,插入过程就显得非常简单。 add(int index, E e)需要先对元素进行移动,然后完成插入操作,也就意味着该方法有着线性的时间复杂度。 addAll() addAll()方法能够一次添加多个元素,根据位置不同也有两个把本,一个是在末尾添加的addAll(Collection c)方法,一个是从指定位置开始插入的addAll(int index, Collection c)方法。跟add()方法类似,在插入之前也需要进行空间检查,如果需要则自动扩容;如果从指定位置插入,也会存在移动元素的情况。addAll()的时间复杂度不仅跟插入元素的多少有关,也跟插入的位置相关。 remove() remove()方法也有两个版本,一个是remove(int index)删除指定位置的元素,另一个是remove(Object o)删除第一个满足o.equals(elementData[index])的元素。删除操作是add()操作的逆过程,需要将删除点之后的元素向前移动一个位置。需要注意的是为了让GC起作用,必须显式的为最后一个位置赋null值。 public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size – index – 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[–size] = null; //清除该位置的引用,让GC起作用 return oldValue; } 关于Java GC这里需要特别说明一下,有了垃圾收集器并不意味着一定不会有内存泄漏。对象能否被GC的依据是是否还有引用指向它,上面代码中如果不手动赋null值,除非对应的位置被其他元素覆盖,否则原来的对象就一直不会被回收。 原文发布时间为:2018-08-06本文作者:Java杂记本文来自云栖社区合作伙伴“Java杂记”,了解相关信息可以关注“Java杂记”

优秀的个人博客,低调大师

POI框架:Java程序读取Excel

APACHE-POI What:POI是什么? Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 HOW:如何使用java程序读取Excel文件中的内容? 1.坐标(导包) <!--APACHE POI--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.11</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.11</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>3.11</version> </dependency> 2.准备一份你要读取的Excel文件,这里我拿北京市的省市区的Excel文件作为示例文件。 北京市区域划分Excel文件 3.编码 public class POIDemo { @Test public void poiTestMethod() throws Exception { //1.读取Excel文档对象 HSSFWorkbook hssfWorkbook = new HSSFWorkbook(new FileInputStream("D:\\Solr\\测试数据.xls")); //2.获取要解析的表格(第一个表格) HSSFSheet sheet = hssfWorkbook.getSheetAt(0); //获得最后一行的行号 int lastRowNum = sheet.getLastRowNum(); for (int i = 0; i <= lastRowNum; i++) {//遍历每一行 //3.获得要解析的行 HSSFRow row = sheet.getRow(i); //4.获得每个单元格中的内容(String) String stringCellValue0 = row.getCell(0).getStringCellValue(); String stringCellValue1 = row.getCell(1).getStringCellValue(); String stringCellValue2 = row.getCell(2).getStringCellValue(); String stringCellValue3 = row.getCell(3).getStringCellValue(); String stringCellValue4 = row.getCell(4).getStringCellValue(); System.out.println(stringCellValue0+"--"+stringCellValue1+"--"+stringCellValue2+"--"+stringCellValue3+"--"+stringCellValue4); } } } 4.显示读取结果 "C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" ... 区域编号--省份--城市--区域--邮编 QY001--北京市--北京市--东城区--110101 QY002--北京市--北京市--西城区--110102 QY003--北京市--北京市--朝阳区--110105 QY004--北京市--北京市--丰台区--110106 QY005--北京市--北京市--石景山区--110107 QY006--北京市--北京市--海淀区--110108 QY007--北京市--北京市--门头沟区--110109 QY008--北京市--北京市--房山区--110111 QY009--北京市--北京市--通州区--110112 QY010--北京市--北京市--顺义区--110113 QY011--北京市--北京市--昌平区--110114 QY012--北京市--北京市--大兴区--110115 QY013--北京市--北京市--怀柔区--110116 QY014--北京市--北京市--平谷区--110117 QY015--北京市--北京市--密云县--110228 QY016--北京市--北京市--延庆县--110229

优秀的个人博客,低调大师

Linux未来监控tracing框架——eBPF

eBPF源于早年间的成型于 BSD 之上的传统技术 BPF(Berkeley Packet Filter)。BPF 的全称是 Berkeley Packet Filter,顾名思义,这是一个用于过滤(filter)网络报文(packet)的架构。 BPF 是在 1997 年首次被引入 Linux 的,Linux 内核中的报文过滤机制其实是有自己的名字的:Linux Socket Filter,简称 LSF。 从 3.15 开始,一个套源于 BPF 的全新设计开始,在3.17被添置到了 kernel/bpf 下。全新设计最终被命名为了 extended BPF(eBPF);为了后向兼容,传统的 BPF 仍被保留了下来,并被重命名为 classical BPF(cBPF)。相对于 cBPF,eBPF 带来的改变可谓是革命性的:一方面,它已经为内核追踪(Kernel Tracing)、应用性能调优/监控、流控(Traffic Control)等领域带来了激动人心的变革;另一方面,在接口的设计以及易用性上,eBPF 也有了较大的改进。 cBPF 所覆盖的功能范围很简单,就是网络监控和 seccomp 两块,数据接口设计的粗放;而 eBPF 的利用范围要广的多,性能调优、内核监控、流量控制什么的,数据接口的多样性设计。 由一个文件(net/core/filter.c)进化到一个目录(kernel/bpf) 目前,支持生成 BPF 伪代码的编译器只有 llvm 一家,即使是通篇使用 gcc 编译的 Linux 内核,samples 目录下的 bpf 范例也要借用 llvm 来编译完成。 1. 运行监测 eBPF 其实是内核模块,比内核模块更短小精干,实现的功能也更新颖, eBPF注入的代码是要在内核中运行的,会有安全隐患。 为了最大限度控制安全隐患,cBPF 时代就开始加入了代码检查机制以防止不规范的注入代码;到了 eBPF则在载入程序(bpf_load_program())时加入了更复杂的verifier 机制,会进行一系列的安全检查。 2. 架构 架构如下: 3. bcc 现在可以用 C 来实现 BPF,但编译出来的却仍然是 ELF 文件,开发者需要手动析出真正可以注入内核的代码。这工作有些麻烦,于是就有人设计了 BPF Compiler Collection(BCC),BCC 是一个 python 库,但是其中有很大一部分的实现是基于 C 和 C++的,python实现了对 BCC 应用层接口的封装。 使用 BCC 进行 BPF 的开发仍然需要开发者自行利用 C 来设计 BPF 程序——但也仅此而已,余下的工作,包括编译、解析 ELF、加载 BPF 代码块以及创建 map 等等基本可以由 BCC 一力承担,无需多劳开发者费心。 3.1 bcc安装 github的地址链接如下: https://github.com/iovisor/bcc 执行:git clone https://github.com/iovisor/bcc.git 在Ubuntu中直接安装二进制文件,命令如下: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D4284CDD echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list sudo apt-get update sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r) 这样就可以 使用bcc/example/tracing中的python用例。

优秀的个人博客,低调大师

集合框架源码学习之LinkedList

0-1. 简介0-2. 内部结构分析0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. 添加add方法 0-3-3. 根据位置取数据的方法 0-3-4. 根据对象得到索引的方法 0-3-5. 检查链表是否包含某对象的方法 0-3-6. 删除removepop方法0-4. LinkedList类常用方法 简介 LinkedList是一个实现了List接口和Deque接口的双端链表。 LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性;LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法: List list=Collections.synchronizedList(new LinkedList(...)); 内部结构分析 如下图所示:看完了图之后,我们再看LinkedList类中的一个内部私有类Node就很好理解了: 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; } } 这个类就代表双端链表的节点Node。这个类有三个属性,分别是前驱节点,本节点的值,后继结点。 LinkedList源码分析 构造方法 空构造方法: public LinkedList() { } 用已有的集合创建链表的构造方法: public LinkedList(Collection<? extends E> c) { this(); addAll(c); } 添加(add)方法 add(E e) 方法:将元素添加到链表尾部 public boolean add(E e) { linkLast(e);//这里就只调用了这一个,我们马上就分析这个方法的实现 return true; } private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f);//新建节点,以头节点为后继节点 first = newNode; //如果链表为空,last节点也指向该节点 if (f == null) last = newNode; //否则,将头节点的前驱指针指向新节点 else f.prev = newNode; size++; modCount++; } add(int index,E e):在指定位置添加元素 public void add(int index, E element) { checkPositionIndex(index); //检查索引是否处于[0-size]之间 if (index == size)//添加在链表尾部 linkLast(element); else//添加在链表中间 linkBefore(element, node(index)); } linkBefore方法需要给定两个参数,一个插入节点的值,一个指定的node,所以我们又调用了Node(index)去找到index对应的node addAll(Collection<? extends E> c ): 将集合插入到链表尾部 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } addAll(int index, Collection<? extends E> c): 将集合从指定位置开始插入 public boolean addAll(int index, Collection<? extends E> c) { //1:检查index范围是否在size之内 checkPositionIndex(index); //2:toArray()方法把集合的数据存到对象数组中 Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; //3:得到插入位置的前驱节点和后继节点 Node<E> pred, succ; //如果插入位置为尾部,前驱节点为last,后继节点为null if (index == size) { succ = null; pred = last; } //否则,调用node()方法得到后继节点,再得到前驱节点 else { succ = node(index); pred = succ.prev; } // 4:遍历数据将数据插入 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; //创建新节点 Node<E> newNode = new Node<>(pred, e, null); //如果插入位置在链表头部 if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } //如果插入位置在尾部,重置last节点 if (succ == null) { last = pred; } //否则,将插入的链表与先前链表连接起来 else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; } 上面可以看出addAll方法通常包括下面四个步骤: 检查index范围是否在size之内 toArray()方法把集合的数据存到对象数组中 得到插入位置的前驱和后继节点 遍历数据,将数据插入到指定位置 addFirst(E e): 将元素添加到链表头部 public void addFirst(E e) { linkFirst(e); } private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f);//新建节点,以头节点为后继节点 first = newNode; //如果链表为空,last节点也指向该节点 if (f == null) last = newNode; //否则,将头节点的前驱指针指向新节点 else f.prev = newNode; size++; modCount++; } addLast(E e): 将元素添加到链表尾部,与 add(E e) 方法一样 public void addLast(E e) { linkLast(e); } 根据位置取数据的方法 get(int index)::根据指定索引返回数据 public E get(int index) { //检查index范围是否在size之内 checkElementIndex(index); //调用Node(index)去找到index对应的node然后返回它的值 return node(index).item; } 获取头节点(index=0)数据方法: public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } public E element() { return getFirst(); } public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; } 区别:getFirst(),element(),peek(),peekFirst()这四个获取头结点方法的区别在于对链表为空时的处理,是抛出异常还是返回null,其中getFirst() 和element() 方法将会在链表为空时,抛出异常 element()方法的内部就是使用getFirst()实现的。它们会在链表为空时,抛出NoSuchElementException获取尾节点(index=-1)数据方法: public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } public E peekLast() { final Node<E> l = last; return (l == null) ? null : l.item; } 两者区别:getLast() 方法在链表为空时,会抛出NoSuchElementException,而peekLast() 则不会,只是会返回 null。 根据对象得到索引的方法 int indexOf(Object o): 从头遍历找 public int indexOf(Object o) { int index = 0; if (o == null) { //从头遍历 for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { //从头遍历 for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; } int lastIndexOf(Object o): 从尾遍历找 public int lastIndexOf(Object o) { int index = size; if (o == null) { //从尾遍历 for (Node<E> x = last; x != null; x = x.prev) { index--; if (x.item == null) return index; } } else { //从尾遍历 for (Node<E> x = last; x != null; x = x.prev) { index--; if (o.equals(x.item)) return index; } } return -1; } 检查链表是否包含某对象的方法: contains(Object o): 检查对象o是否存在于链表中 public boolean contains(Object o) { return indexOf(o) != -1; } 删除(remove/pop)方法 remove() ,removeFirst(),pop(): 删除头节点 public E pop() { return removeFirst(); } public E remove() { return removeFirst(); } public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } removeLast(),pollLast(): 删除尾节点 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); } public E pollLast() { final Node<E> l = last; return (l == null) ? null : unlinkLast(l); } 区别: removeLast()在链表为空时将抛出NoSuchElementException,而pollLast()方法返回null。 remove(Object o): 删除指定元素 public boolean remove(Object o) { //如果删除对象为null if (o == null) { //从头开始遍历 for (Node<E> x = first; x != null; x = x.next) { //找到元素 if (x.item == null) { //从链表中移除找到的元素 unlink(x); return true; } } } else { //从头开始遍历 for (Node<E> x = first; x != null; x = x.next) { //找到元素 if (o.equals(x.item)) { //从链表中移除找到的元素 unlink(x); return true; } } } return false; } 当删除指定对象时,只需调用remove(Object o)即可,不过该方法一次只会删除一个匹配的对象,如果删除了匹配对象,返回true,否则false。 unlink(Node x) 方法: E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next;//得到后继节点 final Node<E> prev = x.prev;//得到前驱节点 //删除前驱指针 if (prev == null) { first = next;如果删除的节点是头节点,令头节点指向该节点的后继节点 } else { prev.next = next;//将前驱节点的后继节点指向后继节点 x.prev = null; } //删除后继指针 if (next == null) { last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点 } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; } remove(int index):删除指定位置的元素 public E remove(int index) { //检查index范围 checkElementIndex(index); //将节点删除 return unlink(node(index)); } LinkedList类常用方法测试: package list; import java.util.Iterator; import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] srgs) { //创建存放int类型的linkedList LinkedList<Integer> linkedList = new LinkedList<>(); /************************** linkedList的基本操作 ************************/ linkedList.addFirst(0); // 添加元素到列表开头 linkedList.add(1); // 在列表结尾添加元素 linkedList.add(2, 2); // 在指定位置添加元素 linkedList.addLast(3); // 添加元素到列表结尾 System.out.println("LinkedList(直接输出的): " + linkedList); System.out.println("getFirst()获得第一个元素: " + linkedList.getFirst()); // 返回此列表的第一个元素 System.out.println("getLast()获得第最后一个元素: " + linkedList.getLast()); // 返回此列表的最后一个元素 System.out.println("removeFirst()删除第一个元素并返回: " + linkedList.removeFirst()); // 移除并返回此列表的第一个元素 System.out.println("removeLast()删除最后一个元素并返回: " + linkedList.removeLast()); // 移除并返回此列表的最后一个元素 System.out.println("After remove:" + linkedList); System.out.println("contains()方法判断列表是否包含1这个元素:" + linkedList.contains(1)); // 判断此列表包含指定元素,如果是,则返回true System.out.println("该linkedList的大小 : " + linkedList.size()); // 返回此列表的元素个数 /************************** 位置访问操作 ************************/ System.out.println("-----------------------------------------"); linkedList.set(1, 3); // 将此列表中指定位置的元素替换为指定的元素 System.out.println("After set(1, 3):" + linkedList); System.out.println("get(1)获得指定位置(这里为1)的元素: " + linkedList.get(1)); // 返回此列表中指定位置处的元素 /************************** Search操作 ************************/ System.out.println("-----------------------------------------"); linkedList.add(3); System.out.println("indexOf(3): " + linkedList.indexOf(3)); // 返回此列表中首次出现的指定元素的索引 System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));// 返回此列表中最后出现的指定元素的索引 /************************** Queue操作 ************************/ System.out.println("-----------------------------------------"); System.out.println("peek(): " + linkedList.peek()); // 获取但不移除此列表的头 System.out.println("element(): " + linkedList.element()); // 获取但不移除此列表的头 linkedList.poll(); // 获取并移除此列表的头 System.out.println("After poll():" + linkedList); linkedList.remove(); System.out.println("After remove():" + linkedList); // 获取并移除此列表的头 linkedList.offer(4); System.out.println("After offer(4):" + linkedList); // 将指定元素添加到此列表的末尾 /************************** Deque操作 ************************/ System.out.println("-----------------------------------------"); linkedList.offerFirst(2); // 在此列表的开头插入指定的元素 System.out.println("After offerFirst(2):" + linkedList); linkedList.offerLast(5); // 在此列表末尾插入指定的元素 System.out.println("After offerLast(5):" + linkedList); System.out.println("peekFirst(): " + linkedList.peekFirst()); // 获取但不移除此列表的第一个元素 System.out.println("peekLast(): " + linkedList.peekLast()); // 获取但不移除此列表的第一个元素 linkedList.pollFirst(); // 获取并移除此列表的第一个元素 System.out.println("After pollFirst():" + linkedList); linkedList.pollLast(); // 获取并移除此列表的最后一个元素 System.out.println("After pollLast():" + linkedList); linkedList.push(2); // 将元素推入此列表所表示的堆栈(插入到列表的头) System.out.println("After push(2):" + linkedList); linkedList.pop(); // 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元素) System.out.println("After pop():" + linkedList); linkedList.add(3); linkedList.removeFirstOccurrence(3); // 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表) System.out.println("After removeFirstOccurrence(3):" + linkedList); linkedList.removeLastOccurrence(3); // 从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表) System.out.println("After removeFirstOccurrence(3):" + linkedList); /************************** 遍历操作 ************************/ System.out.println("-----------------------------------------"); linkedList.clear(); for (int i = 0; i < 100000; i++) { linkedList.add(i); } // 迭代器遍历 long start = System.currentTimeMillis(); Iterator<Integer> iterator = linkedList.iterator(); while (iterator.hasNext()) { iterator.next(); } long end = System.currentTimeMillis(); System.out.println("Iterator:" + (end - start) + " ms"); // 顺序遍历(随机遍历) start = System.currentTimeMillis(); for (int i = 0; i < linkedList.size(); i++) { linkedList.get(i); } end = System.currentTimeMillis(); System.out.println("for:" + (end - start) + " ms"); // 另一种for循环遍历 start = System.currentTimeMillis(); for (Integer i : linkedList) ; end = System.currentTimeMillis(); System.out.println("for2:" + (end - start) + " ms"); // 通过pollFirst()或pollLast()来遍历LinkedList LinkedList<Integer> temp1 = new LinkedList<>(); temp1.addAll(linkedList); start = System.currentTimeMillis(); while (temp1.size() != 0) { temp1.pollFirst(); } end = System.currentTimeMillis(); System.out.println("pollFirst()或pollLast():" + (end - start) + " ms"); // 通过removeFirst()或removeLast()来遍历LinkedList LinkedList<Integer> temp2 = new LinkedList<>(); temp2.addAll(linkedList); start = System.currentTimeMillis(); while (temp2.size() != 0) { temp2.removeFirst(); } end = System.currentTimeMillis(); System.out.println("removeFirst()或removeLast():" + (end - start) + " ms"); } } 欢迎关注我的微信公众号(分享各种Java学习资源,面试题,以及企业级Java实战项目回复关键字免费领取):

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册