java第一阶段-JavaSE-Day17,ArrayList、LinkedList集合,常用数据结构

本文深入讲解了数据结构中的栈、队列、数组和链表,以及Java中的ArrayList和LinkedList,还涵盖了泛型的使用、类定义、方法定义和接口,以及无序集合Set的应用和通配符技巧。通过实例演示,提升数据操作效率与编程灵活性。
摘要由CSDN通过智能技术生成

一、常见的数据结构

        1、概述

        数据结构是计算机储存,组织数据的方式,通常情况下,精心选择的数据结构可以带来更高的运行和储存效率

        2、栈

        栈:stack,又称堆栈,简称栈,它是运算受限的线性表,其限制是仅允许在标记的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。

        特点:先进后出,后进先出。

 

        压栈:就是存元素,即把元素存储到栈顶端位置,栈中已有元素依次向栈低方向移动一个位置。

        弹栈:就是取元素,即把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

        3、队列

queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

特点:

①先进先出,后进后出

②队列的入口、出口各占一侧。

 

数据结构之数组和链表

        1、数组

        Array:是有序的元素序列,数组时在内存中开辟一段连续的空间,并在此空间存放元素。

        数组特点:查找快,增删慢

        特点一:

        特点查找元素快:起始地址+索引*每个元素所占的空间大小,只需要经过一次寻址就可以找到元素,通过可以快速访问指定位置的元素

 

        特点二:

        增加元素慢:指定索引位置增加元素,需要创建一个新数组,将制定的新元素存储在指定索引位置,再把原数组元素根据索引复制到新数组对应索引位置

 

        指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引位置,原数组中指定索引位置元素不赋值到新数组中。

 

        2、链表

        链表:linkedlist,有一系列节点node组成,节点可以在运行时动态生成。每个节点包括两部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。

 

        简单的说,采用该结构的集合,对元素的存取有如下的特点:

        多个节点之间,通过地址进行连接。

 

        查改元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素,也就是要经过多次寻址

        增删元素快:增加元素--->只需要修改连接下个元素的地址即可。

                删除元素--->只需要修改连接下个元素的地址即可。

 

二、有序单列集合实现类

        1.ArrayList

        ArrayList是List接口的典型实现类,没有自己特有的功能,功能都是List接口的功能。

        底层采用数据结构构建的一个实现类集合。

        2、ArrayList集合源码分析

        ①在创建ArrayList集合对象的时候,使用空参构造默认绑定了一个长度为0数据组

        ②第一次添加元素时,根据是否要扩容的操作,把数组扩容为10;

        ③当插入数据10个长度不够时,按照原来的容量+原来的容量>>1的方式扩容

        ArrayList操作特点:查改快,增删慢

 

 

        3、LinkedList集合源码分析

        LinkedList是List的另一个实现类集合,底层采用得我是双向链表结构构建而成有自己的特有的功能,特有功能基本上是对集合首位元素的操作功能,实际开发中主要使用它的特有功能方便元素添加、删除。

        LinkedList是一个双向链表、

 

 

 

        LinkedList的常用独有方法

        实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。

 

代码:

import java.util.LinkedList;

public class Demo01 {
    public static void main(String[] args) {
        LinkedList ll = new LinkedList();
        ll.addFirst("刘备");
        ll.addFirst("关羽");
        ll.addLast("张飞");
        ll.addLast("小乔");
        System.out.println(ll);
        Object o = ll.getFirst();
        Object o1= ll.getLast();
        System.out.println(o);
        System.out.println(o1);
        ll.removeFirst();
        System.out.println(ll);
        ll.removeLast();
        System.out.println(ll);
        System.out.println(ll.pop());
        System.out.println(ll);
        ll.push("大乔");
        ll.push("曹操");
        System.out.println(ll);
    }
}

三、泛型

(一)泛型的使用(重点)

        1、泛型的介绍

//集合添加的方法,将来要添加某种类型元素,但是现在无法确定是哪一种
//就是使用一个符号E表示未来的数据类型,这个符号E就是泛型
public boolean add(E e){
    linkLast(e);
    return true;
}

        泛型的概述:

        使用一个符号,代表未来的任意的,引用数据类型,这个符号就是泛型

        现在想要使用未来的数据,但是又不知道未来数据的数据类型,可以使用一个符号代替未来要操作的明确数据类型,这个符号就是泛型

        将来在创建一个使用泛型的对象时,要使用明确的数据类型把符号替换调用,这个明确数据是有要求的不能使用基本数据类型,只能使用引用数据类型。

        泛型只能代表引用类型的数据,像(int 、float 、 double)都是基本类型的数据,不能当做明确的数据类型替换掉泛型符号。

        泛型使用分为两个阶段:

        ①声明泛型【定义了一个泛型概念(符号)】 目前不需要我们操作

        例如:

        class ArrayList<E> 在这个ArrayList类中,E就表示将来要操作一个不确定的引用类型名。public boolean add(E e) ArrayList是一个集合,将来肯定要装数据,但是定义方法时候,不知道将来装哪种类型数据,就是一个符号E,代表将来要装的数据,E就是泛型

        ②实例化泛型【未来使用泛型的时候,对泛型的类型具体化,泛型符号就消失了】也就是一旦使用一个明确数据类型代替了泛型符号,此时这个类中凡是出现泛型符号的地方都会使用明确数据类型替换,也就意味着泛型符号消失了。

 

        2、泛型的好处

        ①把运行时期的问题提前到了编译时期,避免了向下转型的错误和麻烦操作

        ②避免了强制类型转换,避免向下转型的麻烦操作

import java.util.ArrayList;
import java.util.Iterator;

public class Demo01 {
    public static void main(String[] args) {
        //使用明确数据类型创建一个ArrayList对象
        //数据类型<明确数据类型> name = new ArrayList<数据类型>();
        //这就是泛型的实例化,也就是用了一个明确数据类型替换了泛型符号。
        ArrayList<String> names = new ArrayList<String>();
        names.add("张三");
        names.add("李四");
        names.add("王五");
        String s = names.get(0);
        System.out.println(s);
        //迭代器遍历
        Iterator<String> it = names.iterator();
        while(it.hasNext()){
            String n = it.next();
            System.out.println(n);
        }

        //增强for循环遍历
        for(String n : names){
            System.out.println(n);
        }
    }
}

        泛型使用注意事项

        ①不能使用基本类型替换泛型符号

        ②创建对象是前后尖括号中类型一致

        ③泛型推断(一种简化泛型使用操作)

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

public class Demo02 {
    public static void main(String[] args) {
        //不能使用基本类型替换泛型符号

        //LinkedList<int> ll = new LinkedList<int>();
        //Collection<double> c = new ArrayList<double>();
        LinkedList<Integer> ll1 = new LinkedList<Integer>();

        //创建对象前后尖括号中类型要一致

        //ArrayList<String> a = new ArrayList<Double>();

        //泛型推断(一种简化使用操作)
        //数据类型<明确数据类型> 对象名 = new 数据类型<>();
        //后面尖括号里可以不写数据类型,系统会自动推断后面尖括号中的
        //明确类型就是前面尖括号中的数据类型

        ArrayList<Integer> list = new ArrayList<>();
        list.add(12);
        list.add(132);
        list.add(456);
        for (Integer i : list) {
            System.out.println(i);
        }
    }
}

(二)泛型类的定义(了解)

        1、泛型的定义格式

        修饰符 class 类名<泛型符号1,泛型符号2,...>{//这里就是泛型符号声明的过程

                类的内容就可以使用这个未来的数据类型

                泛型符号在类中的使用,可以定义成员变量,可以定义为成员方法形参和返回值

        }

        2、泛型的实例化时机

        泛型符号使用明确数据类型替换时机

        创建类对象的时候必须实例化泛型,如果人为不实例化,系统自动实例化为Object类型

        3、泛型类中泛型的使用注意事项

        ①不能在静态的内容中使用,因为泛型类中泛型符号使用明确数据类型替换的实际是创建该类对象的时候,对象比静态的内容出现的晚,所以不能使用泛型类上的泛型符号在静态内容中使用。

        ②泛型类中泛型符号只能在非静态的内容中使用

//Person类就是一个泛型类
public class Person<T> {
    //使用泛型符号可以定义所有非静态内容
    private T t;//成员变量

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public void print(T t){
        System.out.println(t);
    }
}

 

public class Demo03 {
    public static void main(String[] args) {
        //1、创建Person对象使用明确数据类型替换泛型符号
        Person<String> p1 = new Person<>();
        p1.setT("张三");
        String t = p1.getT();
        p1.print(t);
        p1.print("我爱java");

        //2、创建Person对象未使用泛型,这个类中泛型符号默认被Object替换掉
        Person p2 = new Person();
        p2.setT(100);
        Object o = p2.getT();
        System.out.println(o);
    }
}

(三)泛型方法的定义(了解·)

        1、格式

        普通泛型方法(非静态方法)

        修饰符<泛型> 返回值类型 方法名(类型 变量名){

                这个泛型只属于方法自身,可以用来定义方法参数、返回值类型、或者在内部定义局部变量。

        }

        静态泛型方法

        修饰符 static <泛型> 返回值类型 方法名(类型 变量名){

                这个泛型只属于方法自身,可以用来定义方法参数、返回值类型、或者在内部定义局部变量。

        }

        泛型实例化时机

        泛型方法中自定义泛型符号确定明确数据类型时机,是调用方法时候,由实参的数据类型来决定

 

代码:

public class Student {
    //这个泛型符号只属于我的useT方法
    //这个T可以作为返回值类型和形参类型,也可以在方法内部定义局部变量
    public <T> void useT(T t){
        T x = null;
        System.out.println(t);
    }
    //E就可以在这个静态方法中定义:返回值类型和形参烈性,也可以在方法内部定义局部变量
    public static <E> E showT(E y){
        E e = null;
        return e;
    }
}
public class Demo04 {
    public static void main(String[] args) {
        //泛型实例化时机
        //泛型方法中自定泛型符号确定明确数据类型时机
        //是调用方法时候,由实参的数据类型来决定
        Student s = new Student();
        s.useT("李四");
        s.useT(1);

        Student.showT(3.14);
        Student.showT('c');
    }
}

 

        3、注意事项

        ①普通方法自己声明了泛型可以使用自己的泛型

        ②普通方法没有声明反省过可以使用类声明的泛型

        ③静态方法不可以使用类声明的泛型,要想使用必须自己声明

        ④静态方法的泛型声明在static和返回值类型之间

        4.实例化时机

        方法被调用的时候

(四)泛型接口(了解)

        1、概述

        在接口名后面声明泛型的接口就是泛型接口

        修饰符 interface 接口名<泛型>{

                抽象方法;

        }

        2、泛型接口中泛型的实例化时机

        ①创建实现类对象的时候必须实例化接口中的泛型

        修饰符 class 实现类<泛型符号> implements 泛型父类接口<泛型符号>{}

public class Demo07 implements MyInter<String> {
    @Override
    public void useT(String s) {

    }

    @Override
    public String getT() {
        return null;
    }
}

public class Demo05 {
    public static void main(String[] args) {
        //泛型接口的是实现类创建对象时才明确了泛型符号,泛型才实例化
        UseInter<String> ui = new UseInter<>();
        ui.useT("香辣鸡煲");
        System.out.println(ui.getT());

    }
}

        ②子接口继承的时候或者实现类实现的时候,接口本身实例化泛型

public class Demo07 implements MyInter<String> {
    @Override
    public void useT(String s) {

    }

    @Override
    public String getT() {
        return null;
    }
}

 

public class Demo06 implements SubInter {
    @Override
    public void useT(Integer integer) {

    }

    @Override
    public Integer getT() {
        return null;
    }
}

(五)泛型通配符的使用(了解)

        1、概述

        泛型是假设的未来数据类型的代表符号

        泛型通配符是泛型实例化的具体数据类型不确定的代表符号,就是用来限制能操作的明确数据类型范围的

        2、类型通配符<?>

        ArrayList<?>:表示元素类型未知的ArrayList,他的元素可以匹配任何类型

        3、类型通配符上限<? extends T>

        ArrayList <? extends 明确类型>:他表示的类型是明确数据类型及其子类

        4、类型通配符下限<? super T>

        ArrayList <? super 明确类型> : 他表示的类型是明确数据类型及明确数据类型父类类型

import java.util.ArrayList;

public class Demo01 {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        print1(list1);
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");
        list2.add("c");
        list2.add("d");
        print1(list2);

        ArrayList<Number> list3 = new ArrayList<>();
        print3(list3);
        print3(list1);
        ArrayList<Object> list4 = new ArrayList<>();
        print4(list3);
        print4(list4);
    }
    public static void print1(ArrayList<?> list){
        for(Object o : list){
            System.out.println(o);
        }
    }
    public static void print2(ArrayList<String> list){
        for(Object o : list){
            System.out.println(o);
        }
    }
    public static void print3(ArrayList<? extends Number> list){
        for(Number n : list){
            System.out.println(n);
        }
    }
    public static void print4(ArrayList<? super Number> list){
        for(Object o : list){
            System.out.println(o);
        }
    }
}

四、无序单列集合

(一)Set集合

        1.概述

        Set集合也是Collection的分支,他没有自己独有的的功能和遍历方式,他的功能和遍历方式全部来自于Collection

        只不过功能更加严谨了。Set集合是无序集合的顶层接口。学习的时候学习典型的实现类HashSet

        Set s = new HashSet();

        2、特点

        ①无序:存取顺序不一致

        ②没有索引

        ③元素唯一:set集合只能存放单一元素

        3、Set集合实现类

        HashSet

        LinkedHashSet

        TreeSet

 

        4、用处

        对数据进行去重

        5、Set集合的遍历方式

import java.util.HashSet;
import java.util.Set;

public class Demo01 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("赵六");
        System.out.println(set);
        System.out.println("===========================");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皇正经

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值