java基础中的Collection接口下的List接口

mac2024-07-30  59

关键知识点及补充

容器内存放的都是引用数据类型的数据,基本类型的数据会自动装箱所有的实现类都有属于自己的迭代器( //1.获取迭代器对象  Iterator it=col.iterator();  //2.判断是否存在下一个元素   while(it.hasNext()){  //3.获取元素  System.out.println(it.next()); //获取下一个元素迭代器的底层实现是利用foreach来实现的ListIterator  是迭代器的升级版本,会按照适当的顺序迭代 这只适合List,因为是ListIterator * List 接口下的实现类:  *     List接口的实现类,有序可重复  *     ArrayList  *         底层实现: 由可变数组数组实现,通过数组拷贝实现容器可以根据内容进行动态扩容   *         优点: 遍历和获取的时候效率高,因为数据根据索引操作效率高  *         缺点: 增删效率低,大量涉及到数组拷贝问题  *         扩容: 使用Arrays的copyOf方法进行扩容,每次扩容原容量的1.5倍  *             int newCapacity = oldCapacity + (oldCapacity >> 1); 新的容量是老容量的1.5倍  *         新增方法:    没有新增方法,可以多态      *         应用场景:  *             单线程环境下,在大量做查询的业务下,适合使用ArrayList容器  *   *  Vector:  *      和ArrayList非常像  *      区别:1.ArrayList线程不安全,效率较高,Vector线程安全的,效率较低  *          2.扩容是每次扩容原容量的2倍,ArrayList1.5倍  *      应用场景:多线程环境下,保证数据安全,大量做查询适合使用Vector  *   * LinkedList  *         底层实现: 底层是由双向链表结构实现  *         优点: 做增删效率高  *         缺点: 做查询效率低  *         新增方法: 新增了一些有关于链表头和链表尾部的方法  * 比较器:  *     内部比较器|自然排序:  *         实现java.lang.Comparable,重写 compareTo方法,在方法中自定义比较规则,默认的类型的比较规则  *   *  每次修改需要修改源码,不符合设计原则开闭原则  对修改关闭,对扩展开放  *   * 外部比较器|自定义比较器    *     实现接口java.util.Comparator<T>的接口,重写compare()方法,方法中自定义比较规则  *      int compare(T o1, T o2)            比较用来排序的两个参数。 内部比较器是在创建类的时候就实现Comparable<E>接口,重写compareTo方法外部比较器就是在排序的时候Arrays.sort(persons,重写Comparator接口)     可以利用Lambda表达式 

之前接触到的数组:

数组: 存储多个数据     数据类型相同     长度不可变     有序(索引)

容器: 存储多个数据     长度可以随着内容的多少进行改变     可以存储任意类型的数据

自定义一个容器,去体会容器的概念:

这个容器具有添加和删除的功能(其实类似ArrayList的实现):

import java.util.Arrays; public class MyCollectionDesign { public static void main(String[] args) { ConterMyContainer test = new ConterMyContainer(); test.add("你好"); test.add("我好"); test.add("大家好好"); test.delete(2); System.out.println(test); } } //自定义一个容器类,模仿 class ConterMyContainer{ //字符串数组,存储容器中的数据 private String[] arr; //存储容器中数据的个数 private int size; public ConterMyContainer() { arr = new String[0]; } public String get(int index) { if(index<0 || index>=size){ //这边也可以创建一个异常 return "数组索引越界!!!"; } return arr[index]; } public void add(String string) { //备份原数组 String[] temp= arr; //建立一个长度多一的新数组赋值给arr arr = new String[size+1]; for (int i = 0; i < temp.length; i++) { arr[i] = temp[i]; } arr[size] = string; size++; } @Override public String toString() { return "ConterMyContainer [arr=" + Arrays.toString(arr) + ", size=" + size + "]"; } public void delete(int index){ //备份原数组 String[] temp = arr; //建立一个长度少一的新数组用于表示删减后的数组 arr = new String[size-1]; //遍历原数组,将index之前的完全给新数组,将index之后的给新数组的原来对应位置-1 for (int i = 0; i < temp.length; i++) { if (i<index) { arr[i] = temp[i]; }else { if (i==index) { continue; } arr[i-1] = temp[i]; } } } }

Collection接口测试:

public class CollectionDemo02 { public static void main(String[] args) { Collection col=new ArrayList(); Collection col2=new ArrayList(); col.add(123); col.add("哈哈"); col.add(false); col.add('c'); // boolean add(E e) col2.add(1); col2.add(2); col2.add(3); System.out.println(col); col.addAll(col2); System.out.println(col); //boolean contains(Object o) System.out.println(col.contains("哈哈")); System.out.println(col.containsAll(col2)); // boolean remove(Object o) System.out.println(col.remove(123)); System.out.println(col); //for..each for(Object o:col){ System.out.println(o); } //2.迭代器 //1.获取迭代器对象 Iterator it=col.iterator(); //2.判断是否存在下一个元素 while(it.hasNext()){ //3.获取元素 System.out.println(it.next()); //获取下一个元素 } } }

 List接口测试:

import java.util.ArrayList; import java.util.Arrays; import java.util.List; /* * List 子接口 * 有序(索引)可重复 * 新增了一些根据索引操作的方法 * * 遍历方式: * 1.增强for * 2.迭代器 * 3.普通for 根据索引遍历 */ public class ListDemo01 { public static void main(String[] args) { //添加泛型 增可读性 后面的可以省略,前面的不可以 List<Integer> ls=new ArrayList(); List<Integer> ls2 = new ArrayList(); //存储班级学生分数 ls.add(2); ls2.add(1); ls.add(0); ls2.add(4); ls.add(1); ls.add(4); ls.add(3); System.out.println("=============================="); //将所有的括号中的对象的内容添加到后面,或着前面的索引不写 ls.addAll(1,ls2); System.out.println("=============================="); System.out.println(ls);//多态重写了Object的toString方法 //add(index, element) 添加 ls.add(3, 3); System.out.println(ls); //E set(int index, E element) 修改 ls.set(5, 5); System.out.println(ls); // E get(int index) 获取 System.out.println(ls.get(2)); // E remove(int index) | boolean remove(Object o) 从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。 //当容器中的数据也是整数时候,以索引为主 System.out.println(ls.remove(2)); System.out.println(ls); System.out.println("//List<E> subList(int fromIndex, int toIndex) 不包含结束索引"); System.out.println(ls.subList(1, 4)); System.out.println(Arrays.toString(ls.toArray())); //toArray后变成数组,可以用Arrays的方法 System.out.println(ls.toArray()[1]); //普通for for(int i=0;i<=ls.size()-1;i++){ System.out.println(ls.get(i)); } //如果出现多个相同的值,boolean remove(Object o) 从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。 /* * 定义一个容器,存储你喜欢的漫威人物,如果有灭霸,就添加一个惊奇队长 */ } }

 注意ArrayList在使用的时候注意事项,这个例题里面的foreach和迭代器是不能用的,因为涉及到了一个多线程安全问题.可以用ListIterator迭代器

import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /* * 定义一个容器,存储你喜欢的漫威人物,如果有灭霸,就添加一个惊奇队长 */ public class ListDemo02 { public static void main(String[] args) { List<String> list=new ArrayList(); list.add("钢铁侠"); list.add("美国队长"); list.add("黑寡妇"); list.add("灭霸"); list.add("蜘蛛侠"); list.add("雷神"); System.out.println(list); //1.普通for /*for(int i=0;i<list.size();i++){ if("灭霸".equals(list.get(i))){ list.add("惊奇队长"); } }*/ //1.for each //ConcurrentModificationException /*for(String s :list){ if("灭霸".equals(s)){ list.add("惊奇队长"); } }*/ //3.迭代器 //ConcurrentModificationException 通过多个引用同时操作对象时,不允许同时操作,可能会发生这个异常 /*for(Iterator<String> it=list.iterator();it.hasNext();){ if("灭霸".equals(it.next())){ list.add("惊奇队长"); } }*/ //4.列表迭代器 //ListIterator<E> listIterator() //这是迭代器的升级版本,会按照适合的顺序来迭代,因为多线程问题,正着迭代,这边普通迭代的坏处是会发生异常 ListIterator it=list.listIterator(); while(it.hasNext()){ if("灭霸".equals(it.next())){ it.add("惊奇队长"); } } System.out.println(list); } }

List接口的运用

public class ListDemo03 { public static void main(String[] args) { ArrayList<Person> ls=new ArrayList(); ls.add(new Person("张三",18)); ls.add(new Person("李四",18)); ls.add(new Person("王五",20)); System.out.println(ls); //构建一个list容器,存储Person类型的数据判断,名字叫做张三,年龄18岁的人在容器中的索引位置 System.out.println(ls.indexOf(new Person("张三",18))); //默认调用equals方法比较的地址,重写equals方法,让person比较的时候比较内容非地址 } } class Person{ private String name; private int age; public Person() { // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } @Override public boolean equals(Object obj) { //增强程序健壮性的代码 if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }

首先用签到的事例复习下List接口:

public class Work { public static void main(String[] args) { //存储学生的容器 ArrayList<Person> list=new ArrayList<Person>(); //签到使用Scanner模拟 Scanner sc=new Scanner(System.in); System.out.println("开始签到"); Date end=new Date(System.currentTimeMillis()+60*1000); //循环签到 结束的条件: 1)人数够了 2)到点了 while(true){ System.out.println("请输入学生姓名:"); String name=sc.next(); Person p=new Person(name,new Date()); list.add(p); //人数判断 if(list.size()==5){ System.out.println("所有人已签到"); break; } //时间 if(new Date().after(end)){ System.out.println("到点了,结束签到"); break; } } System.out.println("签到人数"+list.size()); System.out.println("签到名单"+list); } } class Person{ private String name; //签到时间 private Date time; public Person() { // TODO Auto-generated constructor stub } public Person(String name, Date time) { super(); this.name = name; this.time = time; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getTime() { return time; } public void setTime(Date time) { this.time = time; } @Override public String toString() { return "Person [name=" + name + ", time=" + time + "]"; } }

模仿单链表实现:

/* * 自定义MyLinkedList容器使用单向链表简单实现 */ public class LinkedListDemo { public static void main(String[] args) { MyLinkedList my=new MyLinkedList(); my.add("你好1"); my.add("你好2"); my.add("你好3"); System.out.println(my.size()); System.out.println(my.get(0)); System.out.println(my.get(1)); System.out.println(my.get(2)); } } //自定义容器类 class MyLinkedList{ //记录链表头节点 private Node head; //记录容器中数据的个数 private int size; public MyLinkedList() { } //添加数据的方法 public void add(String value) { Node node=new Node(value,null); //第一次添加,当前节点作为链表头存在 if(head==null){ head=node; size++; return; } //把当前节点挂到原链表的最后 ,定义为原链表的最后一个节点,把当前的节点地址赋值给原链表的最后一个节点的nextNode属性 Node temp=head; //永远指向当前的节点 temp指向最后一个节点 while(true){ //temp作为最后一个节点出现,最后一个节点记录下一个节点的地址为null if(temp.getNextNode()==null){ temp.setNextNode(node); break; } temp=temp.getNextNode(); } size++; } public int size(){ return this.size; } //根据索引获取的方法 public String get(int index){ //判断索引 if(index<0 || index>=size){ return "索引越界"; } Node temp=head; for(int i=0;i<index;i++){ //temp指向下一个节点 temp=temp.getNextNode(); } return temp.getData(); } } //节点 class Node{ //存储的数据 private String data; //下一个节点的地址 private Node nextNode; public Node(String data, Node nextNode) { super(); this.data = data; this.nextNode = nextNode; } public String getData() { return data; } public void setData(String data) { this.data = data; } public Node getNextNode() { return nextNode; } public void setNextNode(Node nextNode) { this.nextNode = nextNode; } @Override public String toString() { return "Node [data=" + data + ", nextNode=" + nextNode + "]"; } }

内部和外部比较器

public class Demo01 { public static void main(String[] args) { int[] arr={4,1,7,2,8,3}; System.out.println(Arrays.toString(arr)); //默认升序 Arrays.sort(arr); System.out.println(Arrays.toString(arr)); Person p1=new Person("张三",18,180); Person p2=new Person("李四",15,190); Person p3=new Person("王五",30,160); Person[] persons={p1,p2,p3}; System.out.println(Arrays.toString(persons)); //内部比较器(默认排序): Arrays.sort(persons); System.out.println("内部比较器:"+Arrays.toString(persons)); //可以用外部比较器,按照下方的是利用匿名内部类 //static <T> void sort(T[] a, Comparator<? super T> c) 第二个参数中定义当前排序的比较规则 /*Arrays.sort(persons,new Comparator(){ @Override public int compare(Object o1, Object o2) { return ((Person)o2).getAge() - ((Person)o1).getAge(); } });*/ //外部比较器,对Person用外部比较器,这是实现接口 改版:利用的是Lambda表达式 Arrays.sort(persons,(Object o1, Object o2) ->((Person)o1).getAge() - ((Person)o2).getAge()); System.out.println(Arrays.toString(persons)); } }

 

最新回复(0)