7月19日JavaSE学习笔记

容器、集合:List、Set、Map

数组的弊端:只能存指定的数据类型,数组的长度不可变

List

List 接口的实现类:ArrayList、LinkedList、vector

ArrayList 数组列表

线性表是指由一系列元素组成的数据结构,元素之间具有顺序关系。ArrayList是一种线性表的实现方式,它是基于数组的数据结构。它的特点是可以通过索引直接访问元素,插入和删除元素时需要移动其他元素。

        List list = new ArrayList();

List中的常用方法

1.添加元素 add( 添加的内容 )

没有额外声明则可以存储任意类型,也可以往里面存放一个数组或链表作为元素

        //添加元素
        list.add("A");
        list.add(12);
        list.add(null);
        list.add(33.33);

2.在指定位置插入元素 add( 插入位置的下标 , 插入的内容 )

插入后,之后的元素会自动向后移

如果插入位置不连贯会出现下标越界异常

        //在指定位置插入元素
        list.add(1,44);//放到下标为1的地方,其他的元素向后移
        //list.add(6,"B");//插入下标不连贯会出现下标越界异常

3.获取指定下标的元素 get( 指定下标 )

        //获取元素
        Object obj = list.get(2);
        System.out.println(obj);

4.设置指定位置的元素 set( 指定下标 , 设置的值 )

        //设置指定位置元素的值
        list.set(2,22);
        System.out.println(list);

5.是否包含某一个对象 contains( 对象 )

也可以使用 indexOf( 对象 ) != -1 来判断

        //是否包含某一个对象
        boolean bool = list.contains(22);
        System.out.println(bool);
        bool = list.indexOf(22)!=-1;
        System.out.println(bool);

6.是否包含另一个集合的所有元素 containsAll( 另一个集合 )

有一个元素不包含就返回false

        List listA = new ArrayList();
        listA.add(33.33);
        listA.add(null);
        listA.add(2);
        //是否包含另一个集合的所有元素
        bool = list.containsAll(listA);

7.把另一个集合的所有元素依次添加到集合中 addAll( 另一个集合 )

注意,如果直接 add( 另一个集合 ) 是把整个集合作为一个元素添加到其中

        //把另一个集合的所有值依次添加到集合中
        list.addAll(listA);
        //list.add(listA);  //是将集合作为一个元素添加到集合中
        System.out.println(list);

8.删除元素 remove( 要删除的下标或内容 )

删除找到的第一个元素,分两种情况:

        参数传对象,删除这个对象,返回boolean值

        参数传数值,删除下标位置的对象,然后返回被删除的对象

        //删除元素  删除掉找到的第一个元素
        list.remove(null);
        System.out.println(list);
        //参数传对象 删除这个对象  返回boolean
        //参数传下标 删除下标位置的对象   返回被删除的对象
        obj = list.remove(2);//传数字,下标越界会报异常
        bool = list.remove((Integer)2);//强转成封装类删除指定元素
        System.out.println(bool);
        System.out.println(list);

传入下标越界会报异常,如果希望删除指定数值内容的元素需要强转成对应包装类


遍历

使用 size() 获取当前集合容量,然后使用循环遍历

        for (int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }

        while (!list.isEmpty()){//非空,循环删除
            list.remove(0);//删除第一个元素会自动补齐
        }

当不知道里面有多少元素时,可以使用迭代器

Iterator 迭代器:只知道是否有下一个元素,和下一个元素是什么,不知道下标是多少

        Iterator it = list.iterator();//获取一个迭代器
        while (it.hasNext()){//是否有下一个
            System.out.println(it.next());//获取下一个元素
            //一开始指向空,下一个指向第一个
        }

增强for循环是一种语法糖,它在底层使用迭代器来遍历集合中的元素,而不是直接操作集合中的元素。迭代器是一种访问集合中元素的方式,它提供了一种顺序访问集合中元素的方法,但它并不允许修改集合中的元素。

在增强for循环中,迭代器会在每一次迭代中返回集合中的下一个元素,并且迭代器本身并不知道集合中元素的索引位置。因此,增强for循环无法直接通过迭代器来修改集合中的元素。

        System.out.println(list);// [A, 44, 33.33, [33.33, null, 2]]
        for(Object item : list){
            //System.out.println(item);//不能进行修改值的操作
            if(item instanceof Double){
                if((Double) item ==33.33) {
                    //ClassCastException 类型转换异常(不安全)
                    System.out.println("item赋值" + item);
                    item = 44.44;//不能直接赋值
                }
            }
            //if(item.getClass()==item.getClass()){}//比较是不是同一个类
            if(item instanceof List){
                List list1 = (List) item;
                list1.set(1,"ABC");
            }
        }
        System.out.println(list);// [A, 44, 33.33, [33.33, ABC, 2]]

在上面的例子中,通俗来讲,item只是一个指向集合元素地址的变量,当对item直接赋值时,改变的只是变量指向的地址,而不改变原集合内存空间中的元素;但当通过item定位到一个List类型的元素时,通过对应的set方法直接设置了对象内存空间的内容,实现了修改。


扩容

ArrayList扩容方式

默认初始容量10,也可以通过构造方法传入一个值手动设置初始容量

创建时还没有容量,还是一个空数组,往里添加元素时才会初始化一个默认容量10

扩容1.5倍,新容量 =  原容量 + (原容量 >> 1)除2取整

扩容过程:10 +5、 15 +7、 22 +11、 33...

最大容量为 Integer.MAX_VALUE - 8 的安全容量,如果还不够,最多只能 Integer.MAX_VALUE

LinkedList 链表

链表也是一种线性表的实现方式,它是由一系列节点组成的。每个节点包含一个数据元素和指向下一个节点的指针。链表的特点是插入和删除元素时不需要移动其他元素,只需要改变节点之间的指针。

LinkedList 链表和 ArrayList 的使用方法一样,存储数据的方式(结构)不一样。

LinkedList 是双向链表,同时记录着前一个元素和后一个元素的地址,实现双向检索。

使用链表存储理论上无限扩容,但由于size属性是int类型存储,实际上最大值只能是 Integer.MAX_VALUE,超过这个值将无法查询。

ArrayList 和 LinkedList 性能比较

ArrayList通过数组存储数据,通过下标索引查找数据非常快

                    插入和删除慢,插入和删除元素时需要移动其他元素。

LinkedList通过节点指针从头遍历,查找速度慢

                     插入和删除快,插入和删除时只需要改变前后指向。

                     可以通过双向检索,将指定位置和(size>>1)比较,选择从前或从后。

ArrayList适合频繁访问元素的场景,而LinkedList适合频繁插入和删除元素的场景。

当处理超大数据量时,二者的性能几乎一样。


内部类

独立的类叫外部类,定义在类中的类叫内部类

外部类只能用public和default(默认)来修饰

静态内部类:当前类中需要某些对象来支持他的业务,但又不希望外部访问和修改,用static修饰

成员内部类:对象的类,需要通过对象调用可以使用任意访问权限修饰符

局部内部类:在方法中声明,只能在方法中调用,方法结束后消亡,不能使用其他修饰符

public class EasyInnerClass {
    //静态内部类
    //当前类中需要某些对象来支持他的业务,但又不希望外部访问和修改
    public static class InnerA{
    }
    //成员内部类(对象的类)
    public class InnerB{//访问权限修饰符都行

    }
    public void inner(){
        //局部内部类(在方法中声明,只能在方法中调用,方法结束后消亡)
        class InnerC{   //不能使用其他修饰符
        }
        new InnerC();
    }
    public static void test(){
        InnerA innerA = new InnerA();
        new EasyInnerClass().new InnerB();//成员内部类需要通过对象去调用
    }
}
class Test{
    public static void method(){
        //通过类名在外部调用某个类的内部类
        EasyInnerClass.InnerA a = new EasyInnerClass.InnerA();
    }
}

匿名内部类,对象

匿名内部类是没有名字的类,它是在创建时同时定义和实例化的。它通常用于创建只需要简单实现的接口或抽象类的实例。

//抽象类
abstract class AbstractClass{
    public abstract void method();//抽象方法
}
//函数式接口
@FunctionalInterface
interface EasyInter{
    void method();
}
interface EasyInterA{
    int method();
}

使用匿名内部类的语法是在创建对象时,直接在对象创建表达式的花括号内定义类的实现

        //匿名内部类对象,接口也可以声明匿名内部类
        AbstractClass ac = new AbstractClass() {
            @Override
            public void method() {//实现抽象方法
            }
        };
        System.out.println(ac.getClass());//class com.easy719.EasyInnerClass$1
        AbstractClass acac = new AbstractClass() {
            @Override
            public void method() {//实现抽象方法可以不同
            }
        };
        System.out.println(ac.getClass()==acac.getClass());//false,不是同一个匿名内部类
        EasyInter ei = new EasyInter() {
            @Override
            public void method() {

            }
        };

在上面的例子中,创建了一个匿名内部类来实现AbstractClass抽象类和EasyInter接口,并重写了各自的抽象方法。使用getClass方法获取类全名,其中的$1表示这是外部类中的第一个匿名内部类

Lambda表达式是一种更简洁的方式来声明函数式接口的实例,它可以作为参数传递给方法或者赋值给变量。Lambda表达式可以看作是一种匿名函数,是简化匿名内部类的一种写法,它可以被当作一个对象来使用。

使用Lambda表达式的语法是在参数列表和方法体之间使用箭头符号(->)来定义函数的实现。

    public static void test(){
        //lambda表达式,简化匿名内部类的一种写法
        EasyInter eia =()-> System.out.println("1111");
        EasyInter eib =()->{int aa=12;
            System.out.println("2222");
        };
        EasyInterA ea =()->12;//直接用12作为抽象方法的返回值
        EasyInterA eaa =()-> {
            return 12;//更多实现写在花括号中
        };
        EasyInter ee = EasyInnerClass::fun;//直接将静态方法作为抽象方法的实现
        ee.method();
    }
    public static void fun(){
        System.out.println("function");
    }

代码块

一对大括号 { } 就是代码块

成员代码块:直接在类中写一对大括号 { } 就是成员代码块,每一次new对象时执行;

                     成员代码块在构造方法之前执行。

静态代码块:大括号前面用static修饰,在加载类对象时执行;

                      一个类的静态代码块在程序运行期间只会执行一次。

public class EasyBlock {
    static {
        System.out.println("父类---静态代码块");
    }
    {
        System.out.println("父类---成员代码块");
    }
    EasyBlock(){
        System.out.println("父类---构造方法");
    }
    public static void main(String[] args) {
        new EasySon();
    }
}
class EasySon extends EasyBlock {
    static {
        System.out.println("子类---静态代码块");
    }
    {
        System.out.println("子类---成员代码块");
    }
    EasySon(){
        System.out.println("子类---构造方法");
    }
}

执行顺序:先有类再有对象,先执行static静态代码块;

                  先有父类再有子类,如果子类和父类都有静态代码块,先执行父类的

        1.父类静态代码块
        2.子类静态代码块
        3.父类的成员代码块
        4.父类的构造方法
        5.子类的成员代码块
        6.子类的构造方法

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值