Java Class11

Java Class11

集合

概念

集合是用于存储对象的工具类容器,实现了常用的数据结构,提供了一系列公开的方法用于删除、修改、查找和遍历数据,降低了日常开发成本。

三种集合

在这里插入图片描述

Set
set集合中元素是无序、不可重复的

List
list集合中元素是从前到后遍历的
List分为ArrayList和LinkedList

Map
map集合采用键值对存储,一个键对应一个值

在这里插入图片描述

ArrayList

基本操作

public class Demo {
    public static void main(String[] args) {
        List<Integer> list=new ArrayList<>();//定义ArrayList集合
        //add增
        list.add(1);
        list.add(2);
        list.add(3);
        //remove删
        list.remove(2);
        //set改
        list.set(0,3);
        //get取
        list.get(0);

    }

}

三种遍历方式

public class A {
    public static void main(String[] args) {
        //定义ArrayList集合
        List<Integer> list=new ArrayList<>(1000);//开辟空间为1000,类型为Integer
        //进行add操作  添加元素
        list.add(1);
        list.add(2);
        list.add(3);

        for(int i=0;i<list.size();i++){//循环遍历集合的值
            System.out.println(list.get(i));//依次遍历输出元素的值
        }
        Iterator <Integer>it=list.iterator();//初始化迭代器

        while (it.hasNext()){//判断下一元素值是否存在
            Integer i=it.next();//遍历下一元素的值
            System.out.println(i);//打印当前元素的值
        }

        for(int i:list){//利用foreach循环遍历元素的值
            System.out.println(i);
        }
        //定义ArrayList集合并赋初值
        List<Integer> list2= Arrays.asList(1,2,3,4,5);
        //已经定义初值的集合不能对元素的个数进行修改
//        list2.add(6);
//        list2.remove(2);
//        list2.clear();
        list2.set(1,30);//set操作是修改元素的值,并没有改动元素个数
    }
}

可变形参

public class Demo {
    private int age;
    private String name;

    public void method1(int age1,String name1){
        age=age1;
        name=name1;
    }

    public void method2(int age1,int age2,String name1){
        age1=age2;
        age=age1;
        name=name1;
    }

    public void method3(String name,int...age){

    }
}

可变形参可以帮助解决重载问题,避免同一类型参数重复调用造成冗余

fail-safe

fail-fast
fail-fast存在多线程环境下,当线程1对集合进行遍历时,线程2在期间进行修改,造成线程1读取的结果发生变化

public class B {
    public static void main(String[] args) {
        List list=new ArrayList();//定义集合
        list.add(1);
        list.add(2);
        list.add(3);

        List list1=list.subList(0,2);
        list.remove(0);
        list.add(6);
//        输出子集合会报错,输出原集合不会报错
//        System.out.println(list1);
    }
}

上述代码中,两个list同时对其进行读写操作,控制台会报异常,启动sail-safe机制保证读写一致。

addAll

addAll可以看做是add操作的加强版,可以一次性将多个值一次存储到集合,避免了每次add都会进行的开堆操作。

public class C {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();//定义list集合
        Collection c=new ArrayList();//定义集合
        //向集合添加元素
        c.add("A");
        c.add("B");
        c.add("C");
        list.addAll(c);//addAll一次加入元素
        Iterator<String> it=list.iterator();//定义迭代器
        while (it.hasNext()){//判断是否还有下个元素
            System.out.println(it.next());//打印下个元素
        }

    }
}

CopyOnWriteArrayList

CopyOnWriteArrayList是基于ArrayList在多线程处理中出现异常而出现的。

CopyOnWriteArrayList在内部会进行加锁操作,在多线程时会复制一个新的集合,在原来的集合中进行读操作,而在复制集合中进行修改操作,修改操作完毕后将原集合指针指向复制集合,原集合做删除操作。

public class C1 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();//定义list集合
        //向集合依次添加元素
        list.add("A");
        list.add("B");
        list.add("C");
        List<String> list2=new CopyOnWriteArrayList<>();//定义COW集合
        list.add("D");
        Iterator<String> it=list.iterator();//定义迭代器
        while (it.hasNext()){//判断是否由下一个元素
            System.out.println(it.next());//进行打印
        }
    }
}

CopyOnWriteArrayList的内存占用很大,所以不适合进行多次修改操作

原来集合内存占用:100M
复制集合占用:100M
插入大小占用:10M

总共:100+100+10=210M

LinkedList

LinkedList是双向链表,LinkedList插入和删除快,但查找慢。

public class D {
    public static void main(String[] args) {
        Queue<String> q=new LinkedList<>();//定义Linked集合
        //依次输入元素的值
        q.offer("北京");
        q.offer("上海");
        q.offer("广州");
        String str="";//定义字符串
        while ((str=q.poll())!=null){//判断是否为空
            System.out.println(str);//打印元素的值
        }
    }
}

ArrayList与LinkedList比较

ArrayList底层采用顺序表进行存储,所以查找容易,增删改操作效率较低

LinkedList底层采用双向链表进行存储,所以增删改操作容易,但查找不如ArrayList

HashMap

在这里插入图片描述
HashMap在JDK8.0前是是顺序表+链表
JDK8.0后是顺序表+链表+红黑树

slot哈希槽:位置标识,类似指针对应数组的下标
table顺序表:是一个数组,做bucket的表头
bucket哈希桶:用链表存储对应的元素的值

public class E {
    public static void main(String[] args) {
        Map<String,Object> map=new HashMap(100);//定义HashMap
        map.put("北京",100);
        map.put("上海",200);
        map.put("天津",300);
        map.put(null,null);

        List list=new ArrayList();//定义list集合
        list.add("张");
        list.add("王");
        list.add("李");

        Iterator it=map.keySet().iterator();//定义迭代器
        //输出键
        while (it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println();
        Iterator it2=map.values().iterator();//定义迭代器
        //输出值
        while (it2.hasNext()){
            System.out.println(it2.next());
        }
    }
}

HashMap存在的问题

1.数据丢失
两个线程同时进行修改操作时,后一个操作会覆盖前一个,造成对象丢失

2.已遍历区间新增元素会丢失
使用迁移方法时,新增的元素会落在已遍历过的哈希槽上,在遍历完成后,table数组引用指向了newTable,这时新增元素会被当做垃圾回收

3.新表会被覆盖

4.迁移丢失

ConcurrentHashMap

ConcurrentHashMap采用volatile关键字而不使用加锁方法,牺牲部分效率,但性能较好

ConcurrentHashMap利用锁分段技术加强锁的数量,使争夺同一把锁的线程数目得到控制。

在这里插入图片描述

使用锁分段技术,在面对大量数据的时候,想要处理部分数据不需要对整体加锁(这样频繁操作会大大降低效率),而是采用锁分段技术对每段数据进行加锁,这样只需要对该部分进行解锁,而不改变其他数据段,从而提高效率

但在面对size(判断大小)containsValue(查找值)等操作需要遍历整体才能得出结果时,还是需要对整体进行加锁

ConurrentHashMap由Segment和HashEntry组成。
Segment是一种可重入锁
HashEntry用来存储键值对数据

Segment结构和HashMap类似,一个Segment包含一个HashEntry数组

Set

Set中不允许出现重复元素
常用HashSet、TreeSet、LinkedSet等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值