List接口基本介绍
List接口是Collection接口的子接口
-
List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复
-
List集合中的每个元素都有其对应的顺序索引,即支持索引。
-
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根
据序号存取容器中的元素。 -
JDK API中List接口的实现类有:
常用的有: ArrayList、 LinkedList和Vector.
package www.xz.list_;
import java.util.ArrayList;
import java.util.List;
/**
* @author 许正
* @version 1.0
*/
public class List_ {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("tom");
list.add("jack");
list.add("milan");
list.add("zeaper");
list.add("xz");
list.add("tom");
System.out.println("list=" + list);
//索引下标从0开始
System.out.println(list.get(3));
}
}
List接口和常用方法
●List接口的常用方法
List集合里添加了一些根据索引来操作集合元素的方法
- void add(int index, Object ele):在index位置插入ele元素
- boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
- Object get(int index):获取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index, Object ele):设置指定index位置的元素为ele 相当于是替换.
- List subList(int fromIndex, int tolndex):返回从fromIndex到 toIndex位置的子集合
package www.xz.list_;
import java.util.ArrayList;
import java.util.List;
/**
* @author 许正
* @version 1.0
*/
public class ListMethod {
public static void main(String[] args) {
@SuppressWarnings({"all"})
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
// 1) void add(int index, Object ele):在index位置插入ele元素
//在 index=1 的位置插入 许正 ,如果index位置不填默认添加到最后
list.add(1, "许正");
System.out.println("list=" + list);
// 2) boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2);
System.out.println("list=" + list);
// 3) Object get(int index):获取指定index位置的元素
System.out.println(list.get(3));
// 4) int indexOf(Object obj):返回obj在集合中首次出现的位置
list.add("tom");
System.out.println(list.indexOf("tom"));//2
// 5) int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
System.out.println(list);
System.out.println(list.lastIndexOf("tom"));//5
// 6) Object remove(int index):移除指定index位置的元素,并返回此元素
// list.remove("tom");
list.remove(5);
System.out.println("list=" + list);
// 7) Object set(int index, Object ele):设置指定index位置的元素为ele 相当于是替换.
list.set(3, "zeaper");
System.out.println("list=" + list);
// 8) List subList(int fromIndex, int toIndex):返回从fromIndex到 toIndex位置的子集合
//注意: 左闭右开!
List subList = list.subList(1, 4);
System.out.println("sublist=" + subList);
}
}
List的三种遍历方式[ArrayList, LinkedList, Vector]
1)方式一:使用iterator
Iterator iter = col.iterator();
while(iter.hasNext(){
Object 0 = iter.next();
}
2)方式二:使用增强for
for(Object o:col){
}
3)方式三:使用普通for
for(int i= 0;i< list.size();i++){
Object object = list.get(i);
System.out.println(object);
}
说明:使用LinkedList完成使用方式和ArrayList一样
ArrayList底层结构和源码分析
●ArrayList的注意事项
- permits all elements, including null , ArrayList可以加入null,并且多个
- ArrayList是由数组来实现数据存储的
- ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码.
在多线程情况下,不建议使用ArrayList
●ArrayList的底层操作机制源码分析(重点,难点.)
- ArrayList中维护了一个Object类型的数组elementData.
transient Object[] elementData;
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1
次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1. 5倍。 - 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,
则直接扩容elementData为1.5倍。
package www.xz.list_;
import java.util.ArrayList;
/**
* @author 许正
* @version 1.0
*/
@SuppressWarnings({"all"})
public class ArrayListSource {
public static void main(String[] args) {
// ArrayList list = new ArrayList();
ArrayList list = new ArrayList(8);
for (int i = 1; i <= 10; i++) {
list.add(i);
}
for (int i = 11; i <= 15; i++) {
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);
// System.out.println(list);
for (Object o : list) {
System.out.println(o);
}
}
}
Vector底层结构和源码剖析
●Vector的基本介绍
- Vector类的定义说明
-
Vector底层也是一个对象数组,protected Object[] elementData;
-
Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
- 在开发中,需要线程同步安全时,考虑使用Vector
package www.xz.list_;
import java.util.Vector;
/**
* @author 许正
* @version 1.0
*/
public class Vector_ {
public static void main(String[] args) {
Vector vector = new Vector();
for (int i = 0; i < 10; i++) {
vector.add(i);
}
}
}
Vector和ArrayList的比较
LinkedList的全面说明
- LinkedList底层实现了双向链表和双端队列特点
- 可以添加任意元素(元素可以重复),包括null
- 线程不安全,没有实现同步
LinkedList底层结构
●LinkedList的底层操作机制
- LinkedList底层维护了一个双向链表
- LinkedList中维护了两个属性first和last分别指向首节点和尾节点
- 每个节点(Node对象) ,里面又维护了prev、next、 item三个属性,其中通过
prev指向前一个, 通过next指向后一个节点。最终实现双向链表. - 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
- 模拟一个简单的双向链表
package www.xz.list_;
/**
* @author 许正
* @version 1.0
*/
public class LinkedList01 {
public static void main(String[] args) {
//模拟一个双向链表
Node jack = new Node("jack");
Node tom = new Node("tom");
Node xz = new Node("许正");
//连接三个结点,形成双向链表
//jack -> tom -> xz
jack.next = tom;
tom.next = xz;
//xz -> tom -> jack
xz.pre = tom;
tom.pre = jack;
Node first = jack;// 让first引用指向jack,就是双向链表的头结点
Node last = xz;//让Last引用指向hsp,就是双向链表的尾结点
System.out.println("从头到尾进行遍历:");
//演示:从头到尾进行遍历
while (true) {
if (first == null) {
break;
}
//输出first 信息
System.out.println(first);
first = first.next;
}
System.out.println("从尾到头进行遍历:");
//演示:从尾到头进行遍历
while (true) {
if (last == null) {
break;
}
//输出last 信息
System.out.println(last);
last = last.pre;
}
//演示链表的添加对象/数据,是多么的方便
//要求,是在 tom --- xz 之间直接,插入一个对象 smith
Node smith = new Node("smith");
smith.next = xz;
smith.pre = tom;
xz.pre = smith;
tom.next = smith;
//再次遍历
//让first重新指向第一个对象(jack)
first = jack;
System.out.println("添加信息之后再次进行遍历:");
while (true) {
if (first == null) {
break;
}
System.out.println(first);
first = first.next;
}
//重新进行从尾到头遍历
System.out.println("重新进行从尾到头遍历:");
last = xz;
while (true) {
if (last == null) {
break;
}
System.out.println(last);
last = last.pre;
}
}
}
//定义一个Node类,Node 对象表示双向链表的一个结点
class Node {
public Object item;//真正存放数据
public Node next;//指向后一个结点
public Node pre;//指向前一个结点
public Node(Object item) {
this.item = item;
}
@Override
public String toString() {
return "Node name=" + item;
}
}
●LinkedList的增删改查案例
追源码会理解的更加透彻!!!
package www.xz.list_;
import java.util.Iterator;
import java.util.LinkedList;
/**
* @author 许正
* @version 1.0
*/
@SuppressWarnings({"all"})
public class LinkedListCRUD {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
System.out.println("linkedList=" + linkedList);
//演示删除节点:
//删除第一个结点:
linkedList.remove();
// linkedList.remove(1);
System.out.println(linkedList);
//修改某个结点对象
linkedList.set(1, 999);
System.out.println(linkedList);
//得到某个对象
//get(1)指的是得到双向链表中第二个对象
System.out.println(linkedList.get(1));
//因为 LinkedList 实现了 List 接口,所以 增强for 和 迭代器 都可以使用
for (Object o : linkedList) {
System.out.println("o=" + o);
}
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("next=" + next);
}
System.out.println("====普通for循环====");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
}
}
ArrayList和LinkedList的比较
如何选择ArrayList和LinkedList:
- 如果我们改查的操作多,选择ArrayList
- 如果我们增删的操作多,选择LinkedList
- 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
- 在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另
外一个模块是LinkedList,也就是说,要根据业务来进行选择
这两个集合都是单线程的!不安全!!!无并发情况下进行两个之间的选择。
ListExercise 两个练习
package www.xz.list_;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author 许正
* @version 1.0
*/
public class ListExercise {
public static void main(String[] args) {
// 添加10个以上的元素(比如String "hello" ),在2号位插入一个元素"许正",
// 获得第5个元素,删除第6个元素,修改第7个元素,在使用迭代器遍历集合,
// 要求:使用List的实现类ArrayList完成。
List list = new ArrayList();
for (int i = 0; i < 12; i++) {
list.add("hello" + i);
}
System.out.println(list);
list.add(2, "许正");
System.out.println(list);
System.out.println(list.get(4));
list.remove(5);
System.out.println(list);
list.set(6, "zeaper");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("next=" + next);
}
}
}
package www.xz.list_;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
/**
* @author 许正
* @version 1.0
*/
@SuppressWarnings({"all"})
public class ListExercise02 {
public static void main(String[] args) {
List list = new ArrayList();
// List list = new Vector();
// List list = new LinkedList();
list.add(new Book("红楼梦", "曹雪芹", 100));
list.add(new Book("西游记", "吴承恩", 10));
list.add(new Book("水浒传", "施耐庵", 19));
list.add(new Book("三国演义", "罗贯中", 80));
// list.add(new Book("西游记", "吴承恩", 100));
for (Object o : list) {
System.out.println(o);
}
sort(list);
System.out.println("====按照价格排序后的结果====");
for (Object o : list) {
System.out.println(o);
}
}
public static void sort(List list) {
for (int i = 0; i < list.size() - 1; i++) {
for (int j = 0; j < list.size() - 1 - i; j++) {
//取出对象Book
Book book1 = (Book) list.get(j);
Book book2 = (Book) list.get(j + 1);
if (book1.getPrice() > book2.getPrice()) {
list.set(j, book2);
list.set(j + 1, book1);
}
}
}
}
}
class Book {
private String name;
private String author;
private int price;
public Book(String name, String author, int price) {
this.name = name;
this.author = author;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "名称:" + name + "\t\t价格:" + price + "\t\t作者:" + author;
}
}