List集合类中元素是有序的,即添加顺序和取出顺序是一致的,且可以重复。List的底层是一个数组,集合中的每个元素都有对应的索引。可以使用list.get(数字)取出对应索引的元素。
List接口的实现类有很多,常用的有ArrayList、LinkedList和Vector。
package com.edu.list_;
import java.util.ArrayList;
import java.util.List;
/**
* @auther
*/
public class List_01 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("Tom");
list.add("Jack");
list.add("Mary");
//add方法,在指定索引添加元素
list.add(1,"Summer");
//get方法获得指定索引的元素
System.out.println(list.get(1));
//indexOf返回对象在集合中首次出现的位置
System.out.println(list.indexOf("Summer"));
//remove移除指定index位置的元素
list.remove(0);
System.out.println(list);
//set设置指定index位置的元素,相当于替换
list.set(0,"Amy");
System.out.println(list);
//subList(fromIndex,toIndex)返回从fromIndex到toIndex位置的子集合。左闭右开。
System.out.println(list.subList(0,2));
}
}
Summer
1
[Summer, Jack, Mary]
[Amy, Jack, Mary]
[Amy, Jack]
Process finished with exit code 0
List的三种遍历方式有iterator迭代器、增强for循环还有普通for循环。
使用普通for循环的代码如下:
package com.edu.list_;
import java.util.ArrayList;
import java.util.List;
/**
* @auther
*/
public class List_02 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("Tom");
list.add("Amy");
list.add("Summer");
list.add("Jack");
for (int i = 0; i < list.size(); i++) {
Object object = list.get(i);
System.out.println(object);
}
}
}
Tom
Amy
Summer
Jack
Process finished with exit code 0
案例:使用List的实现类添加三本图书,并遍历按价格从低到高排序。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Collection_01 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Book("红楼梦","曹雪芹",34));
list.add(new Book("机器学习","周志华",54));
list.add(new Book("三国演义","罗贯中",28));
System.out.println(list);
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
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 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 double price;
public Book(String name, String author, double 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 double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
[Book{name='红楼梦', author='曹雪芹', price=34.0}, Book{name='机器学习', author='周志华', price=54.0}, Book{name='三国演义', author='罗贯中', price=28.0}]
Book{name='红楼梦', author='曹雪芹', price=34.0}
Book{name='机器学习', author='周志华', price=54.0}
Book{name='三国演义', author='罗贯中', price=28.0}
排序后
Book{name='三国演义', author='罗贯中', price=28.0}
Book{name='红楼梦', author='曹雪芹', price=34.0}
Book{name='机器学习', author='周志华', price=54.0}
Process finished with exit code 0
ArrayList
ArrayList基本等同于vector,ArrayList是线程不安全的,但是执行效率高
在多线程情况下,不建议使用ArrayList。
ArrayList中维护了一个Object类型的数组elementData。当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData的容量为0,第一次添加,则扩容为10.如果需要再次扩容,则扩容elementData为1.5倍。如果使用指定大小的构造器,则初始elementData为指定大小,如果再需扩容,则直接扩容elementData为1.5倍。
vector
vector底层也是一个对象数组,是线程安全的。在开发时,需要线程同步安全时,考虑使用vector。
vector底层也是一个可变数组。扩容机制为 如果是无参,则默认是10,满后,就按2倍扩容。如果指定大小,则每次直接按2倍扩容。
LinkedList
LinkedList底层是一个双向链表,增删元素的效率较高。
线程不安全,没有实现同步。
LinkedList中维护了两个属性,first和last分别指向首节点和尾节点。每个节点是一个Node对象,里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点,实现双向链表。
所以LinkedList元素的添加和删除,不需要扩容,效率会比较高。
public class LinkedList_01 {
public static void main(String[] args) {
Node jack = new Node("Jack");
Node mary = new Node("Mary");
Node tom = new Node("Tom");
//连接三个节点,形成双向链表
jack.next = mary;
mary.next = tom;
tom.pre = mary;
mary.pre = jack;
Node first = jack;
Node last = tom;
//从头到尾进行遍历
while (true){
if (first == null){
break;
}
System.out.println(first);
first = first.next;
}
//从尾到头的遍历
while (true){
if (last == null){
break;
}
System.out.println(last);
last = last.pre;
}
}
}
class Node{
public Object item;//真正存放数据的地方
public Node next;//指向下一个节点
public Node pre;//指向前一个节点
public Node(Object item) {
this.item = item;
}
@Override
public String toString() {
return "Node{" +
"item=" + item +
'}';
}
}
Node{item=Jack}
Node{item=Mary}
Node{item=Tom}
Node{item=Tom}
Node{item=Mary}
Node{item=Jack}
Process finished with exit code 0
如何选择ArrayList和LinkedList?
1、如果改查的操作比较多,选择ArrayList。
2、如果增删的操作比较多,选择LinkedList。
实际开发中,大部分还是选择ArrayList。