1.List 概念介绍
有序集合(也称为 序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。 有序集合, List 集合有一个下标 ( 索引 ) ,我们可以根据索引来操作集合中的元素。 List 接口是 Collection 接口的子接口。 实现了 List 接口的集合类中是有序的,且 允许重复。 List 集合中的元素都对应一个整数型的序号,记载了其在集合中的位置,可以根据序号存取集合中的元素。
2.常用的方法介绍
2.1 重复元素和null 在 List 接口中是可以存储重复元素和 null 值的。
2.2 添加功能
Collection 接口中提供的功能。
boolean add(E e)
//确保此集合包含指定的元素(可选操作)。
boolean addAll(Collection<? extends E> c)
//将指定集合中的所有元素添加到此集合(可选操作)。
List 接口中 新增的功能。
void add(int index, E element)
// 将指定的元素插入此列表中的指定位置(可选操作)
boolean addAll(int index, Collection<? extends E> c)
//将指定集合中的所有元素插入到此列表中的指定位置(可选操作)
import java.util.ArrayList;
import java.util.List;
public class ListDemo02 {
/**
* List接口
* @param args
*/
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(1); // 存储重复的元素
list1.add(2);
list1.add(null); // 添加 null
System.out.println(list1);
list1.add(2,"张三");
System.out.println(list1);
List list2 = new ArrayList();
list2.add("小明"); // 添加第一个元素
System.out.println(list2);
list2.add(0,"小李"); // 在集合的第一个位置添加一个元素
System.out.println(list2);
list2.addAll(1,list1); // 将list1集合中的元素插入到 list2集合的第一个元素之后
System.out.println(list2);
}
}
2.3 删除功能
肯定具有 Collection 接口中定义的删除方法。
void clear()
// 从此集合中删除所有元素(可选操作)。
boolean remove(Object o)
// 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
boolean removeAll(Collection<?> c)
// 删除指定集合中包含的所有此集合的元素(可选操作)。
List 接口中特有的删除方法。
E remove(int index)
// 删除该列表中指定位置的元素(可选操作)。
2.4 修改功能
在 Collection 接口中针对修改并不友好,但是在 List 接口中修改就非常的方便了,我们可以同下标可以直接来修改。
E set(int index, E element)
用指定的元素(可选操作)替换此列表中指定位置的元素。
import java.util.ArrayList;
import java.util.List;
public class ListDemo04 {
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(1); // 存储重复的元素
list1.add(2);
list1.add(null); // 添加 null
System.out.println(list1);
list1.set(1,666);
System.out.println(list1);
}
}
2.5 遍历功能
遍历获取集合中的相关元素,当然肯定可以使用 Collection 接口中定义的方式及 foreach 循环。
Object[] toArray()
// 返回一个包含此集合中所有元素的数组。
Iterator<E> iterator()
// 返回此集合中的元素的迭代器
还可以使用 List 接口中定义的新的方式,接口下标通过普通 for 循环来实现。
public static void main(String[] args) { // 获取一个List接口对象 List list1 = new ArrayList(); list1.add(1); list1.add(1); // 存储重复的元素 list1.add(2); list1.add(null); // 添加 null // 循环获取集合中的元素 // System.out.println(list1.get(2)); for(int i = 0 ; i < list1.size() ; i ++){ System.out.println(list1.get(i)); } } }
总遍历方法
public class Demo4 {
public static void main(String[] args) {
List list1 = new ArrayList();
list1.add(1);
list1.add(1);
list1.add(3);
list1.add(5);
list1.add(null);
System.out.println(list1);
//for循环
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
//foreach
Object[] objects = list1.toArray();
for (Object o : objects) {
System.out.println(o);
}
//Iterator
Iterator it = list1.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
迭代功能在 List 接口中也有扩展。
ListIterator<E> listIterator()
//返回列表中的列表迭代器(按适当的顺序)。
ListIterator<E> listIterator(int index)
//从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。
2.6 其他功能
E get(int index)
// 返回此列表中指定位置的元素。
int indexOf(Object o)
// 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
int lastIndexOf(Object o)
// 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
List<E> subList(int fromIndex, int toIndex)
// 返回此列表中指定的 fromIndex (含)和 toIndex之间的视图
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(3); // 存储重复的元素
list1.add(2);
list1.add(null); // 添加 null
list1.add("张三");
list1.add("李四");
list1.add(3);
System.out.println(list1.indexOf(3));
System.out.println(list1.lastIndexOf(3));
System.out.println(list1.subList(2,4));
}
}
3.ListIterator接口
ListIterator 接口是 Iterator 接口的子接口,在 Iterator 正向迭代的基础上扩展了逆向迭代的操作。
public class Demo07 {
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(3); // 存储重复的元素
list1.add(2);
list1.add(null); // 添加 null
list1.add("张三");
list1.add("李四");
list1.add(3);
// 获取ListIterator接口实例
ListIterator li = list1.listIterator();
System.out.println(li.previousIndex()+ ":" +li.hasPrevious()); // 游标指向了第一个元素的左侧
while(li.hasNext()){ // 正向迭代 判断是否有下一个元素
System.out.println(li.nextIndex() + ":" + li.next());
}
//System.out.println(li.previousIndex()+ ":" +li.hasPrevious()); // 游标指向了最后一个元素的右侧
//System.out.println(li.previousIndex()+ ":" +li.hasPrevious()); // 游标指向了最后一个元素的右侧
System.out.println("***************************");
while(li.hasPrevious()){
System.out.println(li.previousIndex() + ":" + li.previous());
}
}
4.List接口的小结
4.1 List接口遍历方式
toArray
Iterator
foreach
普通的 for 循环
ListIterator
4.2 List接口去除重复元素
方式一:创建一个新的集合来存储去除重复元素。
public class Demo08 {
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(3); // 存储重复的元素
list1.add(2);
list1.add(null); // 添加 null
list1.add("张三");
list1.add("李四");
list1.add(3);
// 获取ListIterator接口实例
System.out.println(list1);
List list2 = new ArrayList();
for(Object o : list1){ // 遍历原来的集合
if(!list2.contains(o)){ // 判断新的集合中是否包含的有遍历的元素
list2.add(o); // 新的集合中不含有该元素,就直接添加进新的集合中
}
}
System.out.println(list2);
}
}
方式二:在原有集合的基础上使用选择排序的思想来去除重复元素【单纯的准备面试】
public class ListDemo09 {
public static void main(String[] args) {
// 获取一个List接口对象
List list1 = new ArrayList();
list1.add(1);
list1.add(3); // 存储重复的元素
list1.add(3);
list1.add(3);
list1.add(3);
list1.add("aa"); // 添加 null
list1.add("张三");
list1.add("李四");
list1.add(3);
// 获取ListIterator接口实例
System.out.println(list1);
for(int i = 0 ; i < list1.size() - 1;i++){
for(int j = i + 1; j < list1.size() ; j++){
if(list1.get(i).equals(list1.get(j))){
list1.remove(j);
j--;
}
}
}
System.out.println(list1);
}
}
5.List接口的相关实现类
5.1 ArrayList
可调整大小的数组的实现 List 接口。 实现所有可选列表操作,并允许所有元素,包括 null 。除了实现List 接口 之外,该类还提供了一些方法来操纵内部使用的存储列表的数组的大小。 (这个类是大致相当于 Vector , 不同之处在于它是不同步的)。
5.1.1 ArrayList的特点
特点:
-
底层的数据结构是数组。
-
能够存储 null 值。
-
线程不安全,效率高。
-
底层是数组结构,那么就意味着查询和修改的效率高,而增加和删除的效率就低了。
-
有索引,能够方便的检索。
-
元素是可以重复的,我们可以自己通过选择排序法去重。
-
不可排序。
注: ArrayList 中常用的方法全部来自于 父类 Collection 、 List 、 Object 。我们都介绍过,所以在次就不再重复了。
课堂案例:
存储多个员工信息(包括工号、姓名、年龄,入职时间),逐条打印所有员工姓名,并输出员工的个数 使用 ArrayList 存储数据 元素个数不确定 要求获得元素的实际个数 按照存储顺序获取并打印元素信息
public class ArrayListDemo02 {
/**
* 存储多个员工信息(包括工号、姓名、年龄,入职时间),逐条打印所有员工姓名,并输出员工的个数
* 使用ArrayList存储数据
* 元素个数不确定
* 要求获得元素的实际个数
* 按照存储顺序获取并打印元素信息
* @param args
*/
public static void main(String[] args) {
ArrayList list = new ArrayList();
for(int i = 0 ; i < 10 ; i ++){
Employee e = new Employee("emp"+i,"张三"+i,10+i,new Date());
list.add(e);
}
System.out.println(list);
// 逐条打印员工的信息
for (Object o:list) {
if(o instanceof Employee){
Employee e = (Employee) o;
System.out.println(e);
}
}
// 员工的个数
System.out.println("员工的个数是:" + list.size());
}
}
/**
* 员工类
*/
class Employee{
private String empNo; // 员工编号
private String empName; // 员工姓名
private Integer age; // 在成员变量中如果是基本数据类型 我们推荐使用包装类声明
private Date entryDate; // 入职时间
public Employee(String empNo, String empName, Integer age) {
this.empNo = empNo;
this.empName = empName;
this.age = age;
}
public Employee(String empNo, String empName, Integer age, Date entryDate) {
this(empNo,empName,age);
this.entryDate = entryDate;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getEntryDate() {
return entryDate;
}
public void setEntryDate(Date entryDate) {
this.entryDate = entryDate;
}
@Override
public String toString() {
return "Employee{" +
"empNo='" + empNo + '\'' +
", empName='" + empName + '\'' +
", age=" + age +
", entryDate=" + entryDate +
'}';
}
}
5.1.2 ArrayList原理分析
ArrayList 的本质就是 动态数据,动态扩容 初始的属性了解
/**
* 集合默认的容量 10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认容量的空的数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 集合中真实的存储数据的 数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 集合中的元素的个数,注意 不是数组的长度!!!!
* @serial
*/
private int size;
5.1.3 ArrayList作业 ArrayList 集合练习: ( 1 )创建一个 Person 类,添加属性 :name,age; 封装这些属性并分别设置各个属性的方法。 ( 2 )根据用户输入的对象个数创建 Person 对象,接收用户在控制台上输入的每个对象的信息。 ( 注意,将有些Person 对象的名字和年龄设置相同 )。 ( 3 )创建一个 ArrayList 集合,将 Person 对象添加到 ArrayList 集合中。 ( 4 )使用迭代器迭代输出该 List 集合。 ( 5 )写一个方法,可以去除 ArrayList 集合中重复的 Person 对象。姓名和年龄相同视为重复的 Person 对象。
Person 类
public class Person {private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public class ArrayListHomeWork {public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("请输入Person对象的个数:");
int number = in.nextInt();
System.out.println("Person的姓名:");
String name = in.next();
System.out.println("Person的年龄:" );
Integer age = in.nextInt();
// 创建一个ArrayList集合
ArrayList list = new ArrayList();
for(int i = 0 ; i < number ; i ++){
Person person = new Person(name,age);
// 将创建的Person对象添加到list集合中去
list.add(person);
}
// 使用迭代器 输出集合
printIteratorList(list);
System.out.println("*************");
// 移除重复的元素
removeRepetitionElement(list);
// 使用迭代器 输出集合
printIteratorList(list);
}
/**
* 移除重复元素
* 通过选择排序的方式来移除重复的元素
* 姓名和年龄相同表示是重复的元素
* @param list
*/
public static void removeRepetitionElement(ArrayList list){
for(int i = 0 ; i < list.size() - 1 ; i ++){
for(int j = i + 1 ; j < list.size() ; j ++){
Person p1 = (Person) list.get(i);
Person p2 = (Person)list.get(j);
if(p1.getName().equals(p2.getName()) && p1.getAge() == p2.getAge()){
list.remove(j);
j--;
}
}
}
}
/**
* 迭代输出集合中的信息
* @param list
*/
private static void printIteratorList(ArrayList list) {
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
Object next = listIterator.next();
if(next instanceof Person){
Person p = (Person) next;
System.out.println(p);
}
}
}
}