华清远见-重庆中心-JAVA高级阶段技术总结

本文深入解析Java集合框架,包括常用容器如ArrayList、LinkedList的特点及应用场景,HashMap与TreeMap的选择依据,以及HashSet的工作原理等核心概念。

1.Java容器都有哪些?

  • ArrayList、LinkedList、HashSet、TreeSet、HashMap。

2.Collection和Collections有什么区别

  1. Collection是集合的根接口,定义集合操作元素的方法。
  2. Collections是集合的工具类,定义操作元素的静态方法。

3.List、Set、Map之间的区别

  1.  List:有序、可重复。在该接口继承Collection接口的同时,又拓展了一些操作元素的方法,如添加到指定索引、根据索引删除、获取指定索引的元素、截取子集合的方法等。
  2. Set:无序、不可重复的集合。允许保存null,没有索引。没有自己的构造方法,都是继承于Collection接口在的方法
  3. Map:Map 集合中存储的是键值对,键(Key)不能重复,键允许出现一个null作为键,值(Value)可以重复。键和值都是引用类型。

4、如何决定使用 HashMap 还是 TreeMap?

  • 如果要对保存的元素进行排序、遍历,使用TreeMap集合
  • 如果要对元素进行插入、删除和指定查找等操作,使用HashMap集合

5、 说一下 HashMap 的实现原理?

  • JDK1.8之后,HashMap采用"数组+链表+红黑树"实现
  • 当没有哈希冲突时,元素保存到数组中
  • 如果出现哈希冲突,在对应的位置上创建链表,元素保存到链表中
  • 如果链表的长度大于8,将链表转换为红黑树
  • 数据采用键值对key-value的形式保存,键不能重复,能用null作为键;值没有限制,键和值都是引
  • 用类型
  • HashMap集合中添加元素时,原理同HashSet

6、说一下 HashSet 的实现原理?

采用哈希表实现 ,元素不能重复,无序保存,允许保存一个null ,本质是一个HashMap对象
使用HashSet集合时,通常要重写实体类中的equalshashcode方法
  • 如果两个元素的hashCode相同且equals结果为true,视为同一个对象,不能添加。
  • 每次向集合中添加元素时,先判断该元素的hashCode是否存在
  • 如果不存在,视为不同对象,直接添加
  • 如果存在,再判断equals方法的结果
  • 如果false,视为不同对象,可以添加
  • 如果true,视为同一对象,不能添加
  • 由此可见,不能添加的条件是两个对象的hashCode相同且equals的结果为true
  • 如果每次只判断equals的话,由于equals方法通常重写时会判断很多属性,效率不高。
  • 如果每次只判断hashCode的话,效率高,但有可能会有哈希冲突,
  • 所以先判断hashCode,再判断equals,技能保证效率,又能保证不添加重复元素。

7、ArrayList 和 LinkedList 的区别是什么?

  • 这两个类都是List接口的实现类,保存的元素有序可重复,允许保存null
  • ArrayList采用数组实现,随机读取效率高,插入删除效率低,适合用于查询
  • LinkedList采用双向链表实现,插入删除时不影响其他元素,效率高,随机读取效率低,适合用于频繁更新集合

8、如何实现数组和 List 之间的转换?

  • 数组转换为List,使用 Arrays. asList(array) 进行转换。
  • List 转换为数组:使用 List 自带的 toArray() 方法。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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

            /*
             * List转Array
             */
            List<String> lst = new ArrayList<>();
            lst.add("ab");

            //使用toArray之后,转换的是Object数组,方法的返回值为 Object[]
            Object[] objects = lst.toArray();
            System.out.println(Arrays.toString(objects));

            /*
             * Array转List
             */
            String[] str = {"a", "b", "c"};
            List<String> list = Arrays.asList(str);
            System.out.println(list.toString());


    }
}

9、 Array 和 ArrayList 有何区别?

  • 存储类型不同:Array只可存储基本数据类型和对象;ArrayList只能存储对象
  • Array长度是固定的,ArrayList是一个可变数组,长度可变

10、哪些集合类是线程安全的?

  • Stack、Vextor、Properties、Hashtable

11、 Iterator 怎么使用?

import java.util.ArrayList;
import java.util.Iterator;
public class Main {
    public static void main(String[] args) {

        ArrayList<String> nameList = new ArrayList();
        nameList.add("Tom");
        nameList.add("Jerry");
        nameList.add("LiHua");
        nameList.add("Danny");
        System.out.println("使用迭代器遍历");
        //迭代器
        //Collection类型的集合对象.iterator(),获取迭代器
        Iterator<String> iterator = nameList.iterator();
        // iterator.hasNext()判断集合中是否还有下一个元素
        // iterator.next();获取下一个元素
        while (iterator.hasNext()) {
            String name = iterator.next();
            System.out.println(name);
        }

    }
}

12、线程和进程的区别?

  • 进程是操作系统资源分配的基本单元
  • 线程是处理器任务调度和执行的基本单位

13、什么是死锁?

  • 两个或者两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的现象

例:定义两个线程类,线程A先获取资源A后,在获取资源B;线程B先获取资源B后,再获取资源A。如果对资源A和资源B使用了synchronized进行同步,就会在线程A获取资源A的时候,线程B无法获取资源A,相反线程B在获取资源B的时候,线程A无法获取资源B,所以两个线程都不会得到另一个资源。

1.PersonA类

public class PersonA implements Runnable {
//定义两个共享的成员变量,刀、叉
private Object knife;
private Object fork;


public PersonA(Object knife, Object fork) {
    this.knife = knife;
    this.fork = fork;

}

/*
 * 该线程执行run方法时,先获取knife对象,等待3s后获取fork对象
 *
 * */
@Override
public void run() {

        synchronized (knife) {
            System.out.println(Thread.currentThread().getName() + "获取了knife,3s后获取fork");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (fork) {
                System.out.println(Thread.currentThread().getName() + "获取了fork,可以吃饭了");
            }
        }
}
}

2.PersonB类

public class PersonB implements Runnable {
    //定义两个共享的成员变量,刀、叉
    private Object knife;
    private Object fork;


    public PersonB(Object knife, Object fork) {
        this.knife = knife;
        this.fork = fork;
    }

    /*
     * 该线程执行run方法时,先获取fork对象,等待3s后获取对象knife
     *
     * */
    @Override
    public void run() {
        synchronized (fork) {
            System.out.println(Thread.currentThread().getName() + "获取了fork,3s后获取knife");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (knife) {
                System.out.println(Thread.currentThread().getName() + "获取了knife,可以吃饭了");
            }
        }
    }
}

 3.测试类Main类

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Object knife = new Object();
        Object fork = new Object();

        new Thread(new PersonB(knife,fork),"B").start();
        new Thread(new PersonA(knife,fork),"A").start();

    }
}

4.运行结果 ,没有结束运行也没有继续进行。


14、 sleep() 和 wait() 有什么区别?

  • 都是使线程暂停执行一段时间的方法
  • sleep()是Thread类的方法,wait()是Object类中定义的方法
  • sleep()方法可以在任何地方使用
  • wait()方法只能在synchronized方法或synchronized块中使用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值