关键知识点及补充
容器内存放的都是引用数据类型的数据,基本类型的数据会自动装箱所有的实现类都有属于自己的迭代器(
//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));
}
}