List集合
1、List接口
List是Collection子接口
特点:允许保存重复元素数据
定义:public interface extends Collection
List子接口对Collection接口进行了扩充
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | E get(int index) | 普通 | 获取指定索引数据 |
2 | E set(int index,E element) | 普通 | 修改指定索引数据 |
3 | ListIterator listIterator() | 普通 | 返回ListIterator接口对象 |
4 | boolean contains(Object o) | 普通 | 查询数据是否存在,徐亚equals()支持 |
5 | boolean remove(Object o) | 普通 | 数据删除,需要equals()支持 |
6 | int size() | 普通 | 获取数据长度 |
7 | Object[] toArray | 普通 | 将集合变为对象数组返回 |
8 | Iterator iterator() | 普通 | 将集合变为Iterator接口返回 |
List中常用子类:ArrayList , Vector , LinkedList
JDK1.9后追加了一些静态方法
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = List.of("Hello", "World", "!");
for (Object o : list.toArray()) {
System.out.print(o + "、");
}
}
}
2、ArrayList子类
定义:
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
ArrayList继承结构:
使用ArrayList实例化List父接口
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Hello"); //重复数据
list.add("World");
list.add("!");
System.out.println(list);
}
}
//[Hello, Hello, World, !]
List存储特征:
- 保存的顺序就是存储顺序
- List集合里面允许存在重复数据
以上程序虽然实现了输出,但是是利用了toString()实现的。
Iterable父接口中定义有forEach()方法,其定义:
- 输出支持:default void forEach(Consumer<? super T> action)
利用forEach()输出(非标准输出)
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Hello");
list.add("World");
list.add("!");
list.forEach((str) -> {
System.out.print(str + ",");
});
}
}
//Hello,Hello,World,!,
此种输出不是正常开发情况下需要考虑的操作
List集合中的其他操作
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
System.out.println("集合是否为空?" + list.isEmpty() + ",集合元素个数:" + list.size());
list.add("Hello");
list.add("Hello");
list.add("World");
list.add("!");
list.remove("Hello");
System.out.println("集合是否为空?" + list.isEmpty() + ",集合元素个数:" + list.size());
list.forEach((str) -> {
System.out.print(str + " ");
});
}
}
//集合是否为空?true,集合元素个数:0
//集合是否为空?false,集合元素个数:3
//Hello World !
ArrayList中的操作与链表形式相似,但并非使用链表实现,ArrayList封装的是数组
ArrayList构造:
public ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
在进行添加时,如果数组长度不够,会开辟新的数组,并将旧数组拷贝到新数组中
JDK1.9之后:ArrayList默认的构造只会使用默认的空数组,使用的时候才会开辟数组,默认的开辟长度为10
JDK1.9之前:ArrayList默认的构造就会开辟大小为10的数组
当ArrayList之中保存的容量不足的时候会采用成倍的方式进行增长,原始长度为10,下次增长为20,以此类推
使用ArrayList子类时要估算数据量大小,若超过10个,应使用有参构造方法进行创建,避免垃圾空间的产生
3、ArrayList保存自定义对象
实现自定义类对象的保存
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<Person> list = new ArrayList<>();
list.add(new Person("linlin" , 18));
list.add(new Person("xiaowu" , 19));
list.add(new Person("axu" , 20));
System.out.println(list.contains(new Person("linlin" , 18)));
list.remove(new Person("linlin" , 18));
list.forEach(System.out::println); //方法引用代替了消费型接口
}
//true
//Person{name='xiaowu', age=19}
//Person{name='axu', age=20}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
在使用List保存自定义对象时,如果需要使用到contains(),remove()方法进行查询与产出处理时,必须保证类中已经重写了equals()方法
4、LinkedList子类
LinkedList类是基于链表实现的
定义:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
LinkedList继承关系:
使用LinkedList实现集合操作
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = new LinkedList<>();
list.add("Hello");
list.add("Hello"); //重复数据
list.add("World");
list.add("!");
list.forEach(System.out::println);
}
}
LinkList与ArrayList使用方式使完全相同的,但内部的实现是不同的
LinkedList构造方法里面并没有提供有像ArrayList那样的初始化大小的方法,而只是提供有无参的构造方法:public LinkedList()
如果观察源码,就会发现LinkedList封装的就是一个链表
面试题:请问ArrayList与LinkedList有什么区别?
- ArrayList是数组实现的集合操作,而LinkedList是链表实现的集合操作
- 在使用List集合中的get()方法根据索引获取数据是,ArrayList的时间复杂度为“O(1)”,而LinkedList的时间复杂度为“O(n)” (n为集合的长度)
- ArrayList在使用的时候默认的初始化对象数组的大小长度为10,如果空间不足则会采用2倍的形式进行容量的扩充,保存大数据量的时候有可能会造成垃圾的产生以及性能的下降,但是这个时候可以使用LinkedList保存
5、Vector子类
Vector定义结构:
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
继承结构与ArrayList是相同的
Vector继承结构:
Vector类使用
public class JavaDemo {
public static void main(String[] args) throws Exception {
List<String> list = new Vector<>();
list.add("Hello");
list.add("Hello"); //重复数据
list.add("World");
list.add("!");
list.forEach(System.out::println);
}
}
观察Vector类实现
public Vector() {
this(10);
}
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
Vector类如果使用的是无参构造方法,则一定会默认开辟一个10个长度的数组,而后其余的实现操作与ArrayList是相同的
Vector类中的操作方法
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
通过观察源码可以发现Vector类之中操作方法采用的是synchronized同步处理,而ArrayList没有进行同步处理
Vector类之中的方法在多线程访问的时候属于线程安全的,但是性能不如ArrayList高