Java基础、集合

1. 基础

  1. Java语言特点:面向对象、通过JVM实现平台无关性和移植性、多线程、网络编程

  2. 基本数据类型:int(32)、char(16)、byte(8)、short(16)、long(64)、float(32)、double(64)、Boolean(1)

  3. String是不可变的,用final声明,不可继承,线程安全,字符串常量池

  4. String、StringBuffer、StringBuilder

    1. 可变性:String不可变,是通过new一个字符串来拼接。StringBuffer和StringBuilder可通过append()方法拼接字符串
    2. 线程安全:String线程安全,StringBuffer的append方法用了synchronized修饰,是线程安全,StringBuilder的append方法没有
    3. 性能:StringBuilder > StringBuffer > String
  5. 深拷贝:拷贝对象和原始对象引用不同,修改原始对象的值不会影响拷贝对象的值

  6. 浅拷贝:拷贝对象和原始对象引用相同,修改原始对象的值会影响拷贝对象的值
    例子:公会乱斗保存的公会成员,要断开引用

  7. equals和==的区别

    1. 基本数据类型,==比较的是值。引用数据类型,==比较的是内存地址
    2. 基本数据类型没有equals方法。引用数据类型,equals默认比较内存地址,如果有重写则按照重写逻辑
  8. 访问权限修饰符

    1. public:对所有类可见,使用对象:类、接口、方法、变量
    2. protected:对同一个包的类和所有子类可见,使用对象:变量、方法,不能修饰外部类
    3. private:仅同一个类可见,使用对象:变量、方法,不能修饰外部类
    4. default:同一包可见,使用对象:类、接口、变量、方法
  9. static关键字

    1. static变量:静态变量,可通过类.变量名访问。内存中只有一个副本,在类加载时被初始化(用来定义事件、协议)
    2. static方法:静态方法,在static方法内不能访问非静态的变量和非静态方法
    3. static代码块:仅在类加载时执行一次,可以将一些只进行一次的初始化操作放在static代码块执行
  10. 初始化顺序:父类静态变量和静态代码块 —— 子类静态变量和静态代码块 —— 父类实例变量和普通代码块 —— 父类构造函数 —— 子类实例变量和普通代码块 —— 子类构造函数

  11. final关键字

    1. 修饰类:不可继承
    2. 修饰方法:不可被重写
    3. 修饰变量:值不可变
  12. this关键字

    1. 调用当前类的实例变量,this.aid = aid
    2. 调用当前类的方法,this.mehtodName()
    3. 调用当前类的构造函数,this()
  13. super关键字

    1. 引用父类的实例变量,super.aid = aid
    2. 引用父类的方法,super.methodName()
    3. 引用父类的构造函数,super()
  14. 面向对象的三大特性:封装、继承、多态

    1. 封装:隐藏了对象的属性和实现细节,仅对外公开接口,通过使用访问权限修饰符来定义访问级别。比如类就是将类的变量和方法实现隐藏在类中,通过类才能访问类的变量和方法
    2. 继承:子类可以继承父类的特征和行为,也可以拓展自己的特征和行为。单继承,一个子类只能有一个父类。
    3. 多态:实现多态的三要素:继承、重写、父类引用指向子类对象和接口引用指向实现类对象
      1. 静态多态性:通过方法的重载实现,即相同的方法可以有不同的参数列表,实现根据参数不同做出不同的逻辑处理。在代码编译时就可以根据参数列表不同区分
      2. 动态多态性:子类重写父类方法或者接口实现类重写接口方法,代码运行期间通过引用对象的不同调用不同的方法。比如子类cat,父类animal,都有eat()方法。Aniaml cat = new Cat(),cat.eat()调用的是子类cat的方法
  15. 抽象类与接口:

    1. 修饰:abstract class 和 interface
    2. 实现:extends 和 implements。子类和实现类都必须提供方法实现
    3. 继承:一个类只能继承一个抽象类,但可以实现多个接口
    4. 访问修饰符:抽象方法有public、protected、default。接口方法默认是public
    5. 构造函数:抽象类可以有构造函数,接口没有构造函数
  16. 变量

    1. 类变量:方法外,static修饰
    2. 实例变量:方法外,没有static修饰
    3. 局部变量:方法中
  17. 内部类:成员内部类、局部内部类、匿名内部类、静态内部类

  18. 重写和重载

    1. 重载:在同一个类中,方法名相同但参数列表不同
    2. 重写:@Override在父子类之间,方法名、参数列表相同,子类重写的方法的访问修饰符小于等于父类
    3. 构造函数可以被重载不能被重写
  19. hashcode和equals

    1. 如果两个对象调用equals比较返回true,那么他们的hashcode一定相同
    2. 如果两个对象的hashcode相同,调用equals比较不一定为true
    3. 重写equals要重写hashcode,是为了保证equals返回true的情况下,hashcode也相同。如果重写了equals没有重写hashcode,就会出现两个对象相等但是hashcode不同的情况,这时当其中一个对象作为key保存到hashMap中,再通过另一个对象从hashMap中获取时,会拿不到
  20. 反射:在运行状态中,对于任何一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。(例子:spring的ioc、项目执行groovy脚本)

    1. clazz.getMethod()
    2. clazz.getDeclaredMethod()
    3. clazz.getDeclaredFields()
    4. clazz.getFields()
    5. 设置访问权限:field.setAccessible(true)、method.setAccessible(true);
    6. 反射为什么慢:https://juejin.cn/post/7330115846140051496
  21. 当编译一个类之后,会产生一个.class文件,该文件内存放着class对象。类加载相当于class对象的加载,而反射可以在运行时通过.class字节码问题件生成类并实现对象的增强

    1. Field:变量级别,get和set
    2. Method:方法级别,invoke()调用
    3. Constructor:构造函数,new instance()

2. 集合

  1. List:有序可重复
    1. ArrayList:数组,初始容量10,线程不安全

      1. 扩容:默认情况下,扩容为原来的1.5倍,然后将原数组通过Arrays.copyOf()复制到新数组中
      2. 如果在遍历arrayList的过程中移除一个元素
        使用for循环或者forEach会报错,可以使用迭代器Iterator.remove()
    2. ArrayList和LinkedList

      1. 都是线程不安全
      2. ArrayList是数组,LinkedList是双向链表
      3. ArrayList扩容为原来的1.5倍,LinkedList是指针后移
      4. 访问、插入和删除元素:
        1. ArrayList增删时间复杂度为On(找到对应的位置n),查询时间复杂度O1(通过索引定位)。适合多查询少增删
        2. LinkedList增删时间复杂度为O1(指针指向),如果是指定index的插入,时间复杂度On,查询时间复杂度On(要遍历链表)。适合多增删少查询
      5. 绝大部分情况下直接使用arraylist,linkedlist作者自己也调侃从来没使用过linkedlist
    3. ArrayList和Vector

      1. 底层都是数组
      2. Vector线程安全,使用synchronized修饰,性能不如ArrayList
      3. ArrayList扩容1.5倍,Vector扩容2倍
  1. Set:无序不可重复

    1. HashSet:底层是HashMap,初始容量16,负载因子为0.75的hashmap。hashset的值放在hashmap的key上,value为PRESENT。

      1. hashSet如何实现数据唯一
        先计算add对象的hashcode来确定对象存储的位置,如果该位置没有其他对象,则将add对象存放到该位置。如果有其他对象,则通过equals判断两个对象是否相同,相同则存储失败,不同则重新计算存储位置
    2. TreeSet:红黑树

  2. Map:kv键值对,通过key获取value,key唯一,value不唯一

    1. HashMap:初始容量16,负载因子0.75,阈值为负载因子*容量

      1. JDK1.8之前:数组+链表
      2. JDK1.8之后:数组+链表+红黑树,链表长度大于8时,将链表转换为红黑树,当红黑树节点小于6时转换为链表
    2. HashMap扩容:阈值为负载因子*容量,当元素数量大于阈值时,会扩容2倍的数组代替原数组

      1. 1.8之前:头插法,链表元素顺序发生改变,多线程情况下会出现循环链表问题
      2. 1.8之后:尾插法,链表元素顺序没有变化
    3. HashMap的put:JDK1.8之后:数组+链表+红黑树

      1. 先判断数组是否为空,如果为空,则新建数组,长度16
      2. 使用hash算法计算key的索引,如果索引处没有元素,则将kv存入table[idx]处,如果table[idx]处已经有元素,如果table[idx]是树节点,则按照红黑树结构存入kv键值对,如果是链表节点,则插入链表尾端
      3. 如果插入后链表长度大于8,则转换为红黑树
      4. 插入成功后检测是否需要扩容
    4. 哈希冲突:在计算key的hash值后,会对数组长度取余,然后得到idx位置,所以不同的key计算得到的idx是可能相同的,这就是hash冲突

      1. 拉链法:用链表的形式,将Node节点(kv键值对)挂在table[idx]
      2. 红黑树:如果数据多,hash冲突严重,导致链表长度过长,当链表长度大于8时,转换为红黑树,提高查询效率
    5. HashMap长度为什么是2的幂次方:因为hashmap存放kv时会先对key进行hash值计算,然后对得到的hash值进行数组长度取余,最终得到key存放的位置idx。而数组下标计算的方法是(length-1)&hash,长度为2的幂次方的话,等同于hash%length,提高了计算效率

    6. 为什么线程不安全

      1. JDK1.8之前,扩容后转移链表元素,采用头插法,多线程情况下可能出现循环链表问题
      2. JDK1.8之后,多线程情况下put元素,出现数据覆盖
    7. HashMap和HashTable的区别

      1. HashMap初始容量16,扩容2倍。HashTable初始容量11,扩容2倍+1
      2. HashMap线程不安全,HashTable线程安全(get和put使用synchronized)
      3. HashMap可以接受key和value为null,当key为null时,存放在table[0]的链表,HashTable的kv不能为null
    8. TreeMap:是有序的kv集合,对传入的key进行大小排序

      1. floorEntry:返回小于等于
      2. ceilingEntry:返回大于等于
    9. LinkedHashMap:每次put会将entry插入到链表的尾部,实现有序的存储,遍历时能根据元素存入的顺序遍历

  3. Queue:队列,后进前出(用作聊天记录,设置记录条数上限,add最新的一条会把最旧的一条顶掉)

  4. ConcurrentHashMap:线程安全的hashMap

    1. put

      1. 1.8之前,采用分段锁+Entry节点实现,每个分段锁维护一段数组,多个线程可以同时访问不同的分段锁,并发提高
      2. 1.8之后,Cas + synchronized + Node节点实现,锁住Node节点,锁粒度小。如果table[idx]位置为空,则通过CAS方式存入元素。如果不为空,则取出node节点,synchronized加锁,如果是链表节点则插入链表尾部,如果是红黑树节点则存入红黑树
    2. 扩容:在transfer转移方法中设置一个长度,表示一个线程处理的数组长度,最小值是16,在长度范围内只会有一个线程对其进行复制转移操作

    3. 跟HashTable的区别

      1. hashtable通过synchronized修饰,会锁住整个数组,而concurrenthashmap通过锁node节点,降低了锁的粒度,提高了性能
      2. hashtable初始容量11,扩容2倍+1。concurrenthashmap初始容量16,扩容2倍
  5. CopyOnWriteArrayList:线程安全的List

    1. add方法加锁处理(reentrantlock),保证了多线程写入是不会出现线程问题
    2. 使用Arrays.copyOf()将数据复制到新数组
    3. 内存占用,写时复制机制,在写入数据时,内存中存在两个对象的内存
    4. 不能保证数据一致性,可能会读到旧数据

3. 多线程

1.线程池

2. 线程

  1. 进程是程序的一次执行过程,是系统运行的基本单位。

  2. 线程是比进程更小的执行单位,一个进程可以包含多个线程

  3. 并行:单位时间多个处理器同时处理任务

  4. 并发:单个处理器处理多个任务,按照时间片轮流处理

  5. 即使是单核的处理器也支持多线程,处理器会给每个线程分配CPU时间片,线程根据拿到的时间片去执行任务,因此多线程会经常进行线程切换,当切换到下一个线程时,当前线程会保存当前任务的执行状态,等待再次拿到时间片再继续执行任务

  6. 多线程的优缺点

    1. 优点:当一个线程进入阻塞或者等待状态时,CPU可以先去执行其他线程,提高了CPU的效率
    2. 缺点:
      1. 频繁进行线程切换,上下文切换,影响执行速度
      2. 死锁问题
  7. 死锁如何产生,如何避免

    1. 产生:两个或两个以上的线程互相竞争对方的资源,而且同时不释放自己持有的资源时,发生死锁,导致所有线程同时阻塞
    2. 条件:
      1. 互斥条件:一个资源在同一时刻只能由一个线程持有
      2. 请求与保持状态:一个线程在请求获取资源时发生阻塞,同时它持有的资源不释放
      3. 循环等待条件:发生死锁时,所有线程一致阻塞
      4. 不剥夺条件:线程已获得的资源在未使用完时不能被其他线程剥夺,自能由自己使用完后释放
    3. 避免:破环死锁产生的条件
      1. 互斥条件无法被破坏,因为锁的作用就是使线程互斥
      2. 破坏请求与保持条件:一次性请求所有的资源
      3. 破坏循环等待条件:按顺序来申请资源
      4. 破坏不剥夺条件:在申请不到资源时,释放自己持有的资源
  8. 线程的生命周期

    1. 初始:线程被创建,还没有调用start()
    2. 运行
    3. 阻塞:一般是被动的,在竞争资源时得不到资源,被动挂起在内存,等待资源被释放将其唤醒。
    4. 等待:进入该状态的线程需要等待其他线程的动作(通知或中断)
    5. 超时等待
    6. 终止:执行完毕
  9. 线程中断:线程在运行过程中被其他线程打断

    1. interrupt():给目标线程发送中断信号
    2. interrupted():判断目标线程是否被中断
  10. 创建线程的方式

    1. 继承Thread类,重写run()方法,调用start()方法
    2. 实现Runnable接口,重写run()方法,创建实例对象,将实例对象作为参数创建Thread对象,调用start()方法
    3. 使用Callable和Future
      1. 创建Callable接口的实现类,重写call()方法
      2. 使用实现类的实例化对象创建FutureTask对象
      3. 使用FutureTask对象作为参数创建Thread对象
      4. 调用start()方法
    4. 线程池
  11. Runnable接口和Callable接口

    1. 相同点:都是接口,都需要调用Thread.start()启动线程
    2. 不同点:Callable是call()方法,有返回值。Runnable是run()方法,没有返回值
  12. start()方法和run()方法

    1. run()方法定义执行的逻辑,start()方法启动线程
    2. run()方法可以多次被执行,start()方法只能调用一次
  13. 线程的其他方法:wait()、sleep()、notify()、notifyAll()、join()、yield()

  14. sleep()方法和yield()方法

    1. sleep()方法会使当前线程暂停指定的时间,没有消耗cpu时间片
    2. sleep()方法使线程进入阻塞状态,yield()对cpu进行提示,使得上下文进行切换,线程进入就绪状态
    3. sleep()一定会完成指定的休眠时间,yield()不一定
    4. sleep()需要抛出InterruptException
  15. sleep()方法和wait()方法

  1. 线程通信方式

    1. 锁和同步
    2. wait()、notify()、notifyAll()
    3. 信号量
    4. 管道
  2. 为什么wait()、notify()、notifyAll()是在Object类中

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容