(十四)集合框架(List接口、泛型)

集合框架(一)


1.数据结构

Java的集合框架其实是对数据的封装,那么什么是数据结构呢?

我认为,数据结构其实就是计算机中存储的形式不同

数据结构使用来模拟数据的存储操作,其实就是增删改查


1.1常见的数据结构

  • 数组(Array)
  • 链表(Linked List)
  • 哈希表(Hash)
  • 栈(Stack)
  • 队列(Queue)
  • 树(Tree)
  • 图(Graph)
  • 堆(Heap)


1.2数组结构

数组的特征:数组一旦初始化完成,长度是不再发生改变的,数组在内存中是连续的(物理连续,逻辑连续),

可以通过索引值类找到对应的索引,所以数组的查询效率高,反之添加和删除的效率低,

因为在中间进行添加与删除的操作时,数组元素是需要进行移动的


1.3链表结构

链表结构分为 单向链表双向链表

1.单向链表:只能从头遍历到尾,从头进,从尾出

2.双向链表: 从头到尾,从尾到头都可以遍历

链表是通过引用上一个节点与下一个节点来表示之间的关系的

单向链表

单向链表只有一条链子连接,只能单向读取下一个结点.

在这里插入图片描述

双向链表

链表中有两条链子,有一条专门记录元素的顺序,前驱后继,能够读取前后的结点

链表优缺点:查询,更改慢(查询要从头开始查),添加,删除快


1.4队列

队列是一种特殊的线性表,分为单向队列,双向队列

  • 单向队列(Queue):先进先出(FIFO),只能从队尾插入数据,队列头部删除数据
    在这里插入图片描述

  • 双列队列(Deque):可以从队列尾/头插入数据,只能从队列头/尾删除数据
    在这里插入图片描述


1.5栈

栈(stack)又名堆栈,它是一种运算受限的线性表,后进先出(LIFO)

在这里插入图片描述

非线性数据结构(暂时不写)


2.集合框架体系

集合是java提供的一种容器,用来存储多个数据(元素),并且元素只能是对象(引用类型),

根据不同的存储方式所形成的体系就叫集合框架体系
Collection是java集合框架中的顶层接口,定义了增删改查的方法,预定了增删改查规范


2.1容器的分类

1.每一种容器类底层都拥有不同的底层算法,根据容器的存储特点不同,大致分为三种

  • List(列表):允许记录添加顺序,可重复(有序可重复)
  • Set(集合):无序且唯一
  • Map(映射):每一个元素包含一对键对值(key,value),key不可重复,value可重复,严格来说不算容器,只是两个容器元素的映射关系

2.List和Set接口继承于Collection接口,Map接口不继承Collection接口。

3.我们使用的容器接口或类都在java.util包中

4.注意:集合类中存储的对象,都存储的是对象的引用,而不是对象本身。

在这里插入图片描述


3.List接口和实现类

List接口是Collection接口的子接口,该接口的常用实现类有

实现类的命名方式(底层数据结构+实现接口),List实现类必须加引用数据类型,最好保持同一类型

  • ArrayList类:数组列表, ArrayList是List接口的实现类.底层数据结构是数组,

    底层数据结构决定了ArrayList的适用场景是给定索引进行查询和修改操作

  • LinkedList类 :链表,表示双向列表,双向队列结构,采用链表实现

  • Stack类 :栈,表示栈结构,采用数组实现

  • Vector类:向量,其实是老版的ArrayList,线程安全高


3.1List常用的API方法

  • 添加操作

boolean add(Object e):将元素添加到列表的末尾

void add(int index, Object element):在列表的指定位置插入指定的元素

boolean addAll(Collection c):把c列表中的所有元素添加到当前列表中

  • 删除

Object remove(int index):从列表中删除指定索引的元素,返回被删除的元素

boolean removeAll(Collection c):删除指定列表中的所有元素

  • 修改

Object set(int index, Object ele):修改指定索引位置的元素,返回被替换的元素

  • 查询

int size():返回当前列表中元素个数

boolean isEmpty():判断列表中是否为空

Object get(int index):查询列表中指定索引的元素

Object[] toArray():把列表对象转换为Object数组

boolean contains(Object o):判断列表是否存在指定对象


3.2ArrayList类

List接口的实现类,底层是一个Object数组,常用于查询与修改操作

1.操作List接口常用方法
import java.util.ArrayList;
import java.util.List;

public class Test01 {
    public static void main(String[] args) {

        //创建对象
        List list = new ArrayList();
        //1.追加
        list.add("小罗");
        list.add("小月");
        System.out.println(list);
        list.add(1, "520");
        System.out.println(list);
        System.out.println(list.size());

        //addAll,增加一个集合的元素
        List list1 = new ArrayList();
        list1.add( "123");
        list.addAll(list1);
        System.out.println(list);

        //2.查询 :get
        System.out.println(list.get(0));

        //3.修改:set
        list.set(0, "小轩");
        System.out.println(list);

        //4.删除
        list.remove(3);
        System.out.println(list);

        //5.其他:size() /isEmpty /contains()
        System.out.println(list.isEmpty()); //是否为空
        System.out.println(list.size());
        System.out.println(list.contains("aaa")); //是否包含aaa
    }
}

2.ArrayList深度理解:ArrayList容量与拓容机制

1.构造方法:默认构建10个容量,也可以指定容量

new ArrayList() / new ArrayList(int initCapacity)

2.当我们进行添加元素时,达到了ArrayList默认的容量,会触发自动拓容机制

在这里插入图片描述

newCapacity = oldCapacity = oldCapacity/2;

3.当然我们也可以手动拓容

list.ensureCapacity();

4.未来如果明确知道我不会再向容器中添加元素,此时考虑裁剪容量

list.trimToSize();

总结:

ArrayList是可变数组,能自动拓容,一般如果我们知道具体的容量时

一定要使用new ArrayList(int initCapacity),如果不够用可以手动拓容,

当明确知道自己不会再添加元素时,可以裁剪容量


3.3LinkedList类

LinkList是List接口的实现类,底层数据结构是链表,适合添加与删除操作

1.常用方法
  • void addFirst(Object e) 将指定元素插入此列表的开头。
  • void addLast(Object e) 将指定元素添加到此列表的结尾。
  • Object getFirst() 返回此列表的第一个元素。
  • Object getLast() 返回此列表的最后一个元素。
  • Object removeFirst() 移除并返回此列表的第一个元素。
  • Object removeLast() 移除并返回此列表的最后一个元素。

例子

import java.util.LinkedList;
import java.util.List;
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList list =new LinkedList();
        //void addFirst(Object e) 将指定元素插入此列表的开头
        list.addFirst("小罗");
        //void addLast(Object e) 将指定元素添加到此列表的结尾
        list.addLast("小东");
        System.out.println(list); //[小罗, 小东]
        //Object getFirst() 返回此列表的第一个元素
        System.out.println(list.getFirst()); //小罗
        //Object getLast() 返回此列表的最后一个元素
        System.out.println(list.getLast()); //小东
        //Object removeFirst()  移除并返回此列表的第一个元素
        System.out.println(list.removeFirst());//小罗
        //Object removeLast()  移除并返回此列表的最后一个元素
        System.out.println(list.removeLast());//小东
    }

}

LinkedList 总结

1.LinkedList 底层数据结构是链表,特别适合添加,删除的场景
    
2.LinkedList 是List接口的实现类,add/remove/set/get
  LinkedList 也可以以栈结构来操作,push/pop
    
3.LinkedList 也是Queue(单向队列)接口的实现类
            add/remove/element 会产生异常
            offer/poll/peek 返回特殊值null
    
LinkedList 也是Deque(双向队列)接口的实现
            addFirst/addLast, removeFirst/removeLast , getFirst/getLast 会产生异常
            offerFirst/offerLast , pollFirst/pollLast , peekFirst/peekLast 返回特殊值null



4.泛型

1.什么是泛型?

  • 泛型其实是一种类型参数,主要用于不知道某个类或接口中的数据类型不确定的时候,泛型可以预知的使用未知的类型

  • Collection虽然可以存储各种对象,但实际上通常Collection只存储同一类型对象,

所以在存储各种类型对象时,会发生Java.lang.ClassCastException (类型转换异常)

  • 泛型可用到的接口、类、方法中,将数据类型作为参数传递
  • 如果不使用泛型,从容器中获取出元素,需要做类型强转,也不能限制容器只能存储相同类型的元素。
泛型拓展

当我们去定义两个不同类型的泛型对象时,在编译期间,所有泛型的信息都会被擦除,即List与List类型在编译后都会变成List类型(原始类型),因此对于运行期的来说,List与List就是同一个类.

java中的泛型的实现方法称为类型擦除,基于这种方法实现的泛型叫作 伪泛型 java中的泛型基本都是在编译器层次中实现


2.自定义泛型

一般在创建对象时,会给未知的类型设置一个具体的类型,当没有指定泛型时,默认类型为Object

定义泛型

修饰符 class 类名<代表泛型的变量> {  }
 
}

//自定义泛型类
public class Fan<T>{
    private T x;  //定义变量x的类型为泛型
    private T y;
    //省略getter,setter
}

测试类
    public class Test01 {
    public static void main(String[] args) {
        //创建对象时,指定泛型的类型为Integer
        Fan<Integer> integerFan = new Fan<Integer>();
        integerFan.setX(10); //设置值
        integerFan.setY(20);
        System.out.println(integerFan);

        //也可以定义String类型的对象,new Fan<>可以省略类型名称,
        //因为泛型确定左右两边都相同类型
        Fan<String> stringFan = new Fan<>();
        stringFan.setX("666");
        stringFan.setY("999");
        System.out.println(stringFan);
    }
}


3.泛型类型引用传递问题

泛型不存在继承的关系

以下代码的引用传递是不允许的

1.  ArrayList<String> arrayList1=new ArrayList<Object>();//编译错误   
2.  ArrayList<Object> list = new ArrayList<String>();//编译错误

分析过程

第一种情况,我们可以将其拆分

ArrayList<Object> list1 = new ArrayList<Object>();
list.add(new Object());
ArrayList<String> list2 = list1; //编译报错

假设编译没有错,当我们list2引用get()方法取值时,返回的是String类型的对象,

但是此时实际上我们已经存放了Object类型的对象了,所以就会产生类型冲突,为了避免这种情况我们是不允许传递的


第二种情况,

反过来,Object类型的值的确是可以容纳String类型的值,但是需要我们进行强制转换,

违背了当初我们设计泛型的理念,当初就是为了不想强制转换解决类型转换问题,所以也是不行的

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值