List
List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。
注意:
List集合默认按元素的添加顺序设置元素索引,例如第一次添加元素索引为0,第二次添加索引为1…
List是Collection的子接口,可以使用Collection接口里的全部方法。因为List是有序集合,所以它有一些根据索引来操作集合元素的方法。
方法如下:
- void add(int index,Object element)
将元素element 添加到List集合index处。 - boolean addAll(int index ,Collection c)
将集合c所包含的所有元素插入到List集合的index处。 - Object get(int index )
返回集合index索引处的元素。 - int indexOf(Object o)
返回对象o在List集合中第一次出现的位置索引。 - int lastIndexOf(Object o)
返回对象o在List集合中最后一次出现的位置索引。 - Object remove(int index)
删除并返回index索引出的元素。 - Object set(int index ,Object element)
将index索引处的元素替换成element对象,返回被替换的旧元素。 - List subList(int fromIndex,int toIndex)
返回从索引fromIndex(包含)到索引toIndex(不包含)处所有集合元素组成的子集合。
1.8 - void replaceAll(UnaryOperator operator)
根据operator)指定的计算规则重新设置List集合的所有元素。 - void sort(Comparator c)
根据Comparator参数对List集合的元素排序。
示例:
package com.list;
import java.util.ArrayList;
/**
*
* @author hhmsw
*
*/
public class ListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("java疯狂讲义");
list.add("java多线程");
list.add("java真经");
System.out.println(list);//[java疯狂讲义, java多线程, java真经]
list.add(1, "C++");
System.out.println(list);//[java疯狂讲义, C++, java多线程, java真经]
list.remove(0);
System.out.println(list);//[C++, java多线程, java真经]
System.out.println(list.subList(1, 2));//[java多线程]
list.set(1, new String("C#"));
System.out.println(list);//[C++, C#, java真经]
System.out.println(list.indexOf(new String("C")));
}
}
List判断两个对象是否相等只要通过equals方法比较返回true即可。
示例:
class A{
@Override
public boolean equals(Object obj) {
return true;
}
}
public static void main(String[] args) {
ArrayList list2 = new ArrayList();
list2.add("java疯狂讲义2");
list2.add("java多线程2");
list2.add("java真经2");
list2.remove(new A());
System.out.println(list2);//[java多线程2, java真经2]
list2.remove(new A());
System.out.println(list2);//[java真经2]
}
原因:
以上程序试图删除一个A对象,List将会调用该A对象的equals方法依次与集合元素进行比较,如果该equals()方法以某个集合元素作为参数时返回true,List将会删除该元素。A类重写了equals()方法,该方法总是返回true。
所以每次从List集合删除A对象时,总是删除List集合中的第一个元素。
固定长度的List
操作数组的工具类,Arrays,该工具类里提供了asList(Object…a)方法,该方法可以把一个数组或者指定个数的对象转换成一个List集合。
注意:
这个List集合既不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList的实例,Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可增加、删除该集合里的元素。
如果试图通过这两个方法来增加、删除Arrays$ArrayList集合里的元素,将会引发异常UnsupportedOperationException。
示例:
public static void main(String[] args) {
List fixedList = Arrays.asList("Java原则","C++","Html5");
System.out.println(fixedList);//[Java原则, C++, Heml5]
System.out.println(fixedList.getClass());//class java.util.Arrays$ArrayList
//抛出异常:java.lang.UnsupportedOperationException
fixedList.add("C#");
fixedList.remove("Java原则");
}
迭代器ListIterator
List提供了Listiterator()方法,该方法返回一个ListIterator对象,ListIterator接口集成了Iterator接口并且增加了专门操作List的方法。
- boolean hasPrevious()
返回该迭代器关联的集合是否还有上一个元素。 - Object previous()
返回该迭代器的上一个元素。 - void add(Object o)
在指定位置添加一个元素。
示例:
package com.list;
import java.util.ArrayList;
import java.util.ListIterator;
/**
*
* @author hhmsw
*
*/
public class ListIteratorTest {
public static void main(String[] args) {
String [] books = new String[]{"Java基础","Java精要","Js实战"};
ArrayList list = new ArrayList();
for (String book : books) {
list.add(book);
}
ListIterator itera = list.listIterator();
while(itera.hasNext()){
System.out.println(itera.next());
//Java基础,Java精要,Js实战
}
while (itera.hasPrevious()) {
System.out.println(itera.previous());
//Js实战,Java精要,Java基础
}
}
}
ArrayList 和 Vector
相同点:
- 两者都是List接口的实现类,支持List接口的全部功能。
- 两者内部都封装了一个动态的、允许在分配的Object[]数组,默认长度10,当添加元素超出该数组长度时,initialCapacity值会自动增加。
区别:
- ArrayList是线程不安全的,必须手动保证该集合的同步性;
- Vector是线程安全的,无须程序保证该集合的同步性,因此Vector性能要比ArrayList性能低;
- Vector是一个古老的集合(从JDK1.0就有了)因此,即便要保证集合元素的同步性,也尽量不要使用Vector。
注意:
如果集合中需要添加大量的元素,可使用ensureCapacity(int minCapacity)方法一次性的增加initialCapacity。从而减少内存重分配的次数,提高性能。
重新分配Object[]长度的方法:
- ensureCapacity(int minCapacity)
将ArrayList或Vector集合的Object[]数组长度增加大于或等于minCapacity值。 - void trimToSize()
调整ArrayList或Vector集合的Object[]数组的长度为当前元素的个数。调用该方法可以减少ArrayList或Vector集合对象占地用的存储空间。
LinkedList
LinkedList类是List接口的实现类,它可以根据索引来随机访问集合中的元素。除此之外,LinkedList还实现了Deque接口,可以被当成双端队列来使用,因此既可以被当成“棧”来使用,也可以当成队列使用。
LinkedList集合用法,示例:
package com.list;
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("Java");
//讲一个字符串的元素加入棧的顶部
list.push("java讲义");
//将字符串元素加入队列的尾部
list.offer("Java疯狂讲义");
//将一字符串的元素添加到队列的头部(相当于棧的顶部)
list.offerFirst("C++");
//输出:[C++, java讲义, Java, Java疯狂讲义]
System.out.println(list);
//访问并不删除棧顶元素,输出:C++
System.out.println(list.peekFirst());
//访问并不删除队列最后一个元素,输出:Java疯狂讲义
System.out.println(list.peekLast());
//将棧顶元素弹出,输出:C++
System.out.println(list.pop());
//访问并删除队列的最后一个元素,输出:Java疯狂讲义
System.out.println(list.pollLast());
System.out.println(list);
//[java讲义, Java]
}
}
上面程序分别示范了LinkedList作为List集合、双端队列、棧的用法。LinkedList是一个功能非常强大的集合类。
LinkedList与ArrayList、ArrayDeque的实现机制完全不同,ArrayList、ArrayDeque内部以数组的形式来保存集合中的元素,因此随机访问集合元素时有较好的性能;
而LinkedList内部是以链表的性质来保存集合中的元素,因此随机访问集合元素时性能较差,但在插入、删除元素时性能比较出色(只需改变指针所指的地址即可)。
需要指出的是,Vector也是以数组的形式来存储集合元素的,但因为它实现了线程的同步功能(而且实现机制也不好),所以各方面都比较差。
一般来说,由于数组以一块连续内存去来保证所有数组元素,所以数组在随机访问时性能最好,所有的内部以数组作为底层实现的集合,在随机访问时性能都比较好;而内部以链表作为底层实现的集合在执行插入、删除操作时有较好的性能。
但总体来说,ArrayList的性能笔LinkedList的性能要好,因此大部分时候应该使用它ArrayList。
建议:
- 如果遍历List集合元素,对于ArrayList、Vector集合,应该使用随机访问的方法(get)来遍历集合元素,这样性能更好;
- 对于LinkedList集合,则应该使用迭代器Iterator来遍历集合元素。
- 如果要经常执行插入、删除操作来改变包含大量数据的List集合的大小,可考虑使用Linkedlist集合。
原因:使用ArrayList、Vector集合可能需要经常重新分配内部数组的大小,效果可能较差。
如果有多个线程需要同事访问List集合中的元素,那么可以考虑使用Collections将集合包装成线程安全的集合。
Friends are lost by calling often and calling seldom.
交往过密过疏,都会失去朋友。