大家都喜欢的八股文

3 篇文章 0 订阅
3 篇文章 0 订阅

一、基础

1.基本数据类型
  • 整型:byte(8)、short(16)、int(32)、long(64)
  • 浮点型:float(32)、double(64)
  • 布尔型:boolean(8)
  • 字符型:char(16)
2.String、StringBuffer、StringBuilder
  • String 由 char[] 数组构成,使用了 final 修饰,是不可变对象,可以理解为常量,线程安全;对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。
  • StringBuffer 线程安全;StringBuiler 线程不安全。
  • 操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer。

二、集合

1.List(线性结构)
  • ArrayList Object[] 数组实现,默认大小为 10 ,支持随机访问,连续内存空间,插入末尾时间复杂度 o(1),插入第 i 个位置时间复杂度 o(n - i)。扩容,大小变为 1.5 倍,Arrays.copyOf(底层 System.ArrayCopy),复制到新数组,指针指向新数组。
  • Vector 类似 ArrayList,线程安全,扩容默认增长为原来的 2 倍,还可以指定增长空间长度。
  • LinkedList 基于链表实现,1.7 为双向链表,1.6 为双向循环链表,取消循环更能分清头尾。
2.Map(key-value键值对)
  • HashMap

    • 底层数据结构,JDK 1.8 是数组 + 链表 + 红黑树,JDK 1.7 无红黑树。链表长度大于 8 时,转化为红黑树,优化查询效率。
    • 初始容量为 16,通过 tableSizeFor 保证容量为 2 的幂次方。寻址方式,高位异或,(n-1)&h 取模,优化速度。
    • 扩容机制,当元素数量大于容量 x 负载因子 0.75 时,容量扩大为原来的 2 倍,新建一个数组,然后转移到新数组。
    • 基于 Map 实现。线程不安全。
  • HashMap (1.7) 多线程循环链表问题

    • 在多线程环境下,进行扩容时,1.7 下的 HashMap 会形成循环链表。
    • 怎么形成循环链表: 假设有一 HashMap 容量为 2 , 在数组下标 1 位置以 A -> B 链表形式存储。有一线程对该 map 做 put 操作,由于触发扩容条件,需要进行扩容。这时另一个线程也 put 操作,同样需要扩容,并完成了扩容操作,由于复制到新数组是头部插入,所以 1 位置变为 B -> A 。这时第一个线程继续做扩容操作,首先复制 A ,然后复制 B ,再判断 B.next 是否为空时,由于第二个线程做了扩容操作,导致 B.next = A,所以在将 A 放到 B 前,A.next 又等于 B ,导致循环链表出现。
  • HashTable

    • 线程安全,方法基本全用 Synchronized 修饰。
    • 初始容量为 11 ,扩容为 2n + 1 。
    • 继承 Dictionary 类。

三、多线程

volatile

在这里插入图片描述

  • 在多线程环境下,保证变量的可见性。使用了 volatile 修饰变量后,在变量修改后会立即同步到主存中,每次用这个变量前会从主存刷新。
  • 禁止 JVM 指令重排序。
  • 单例模式双重校验锁变量为什么使用 volatile 修饰? 禁止 JVM 指令重排序,new Object()分为三个步骤:申请内存空间,将内存空间引用赋值给变量,变量初始化。如果不禁止重排序,有可能得到一个未经初始化的变量。

四、JAVA虚拟机

1.内存模型

在这里插入图片描述

  • 堆 由线程共享,存放 new 出来的对象,是垃圾回收器的主要工作区域。
  • 栈 线程私有,分为 Java 虚拟机栈和本地方法栈,存放局部变量表、操作栈、动态链接、方法出口等信息,方法的执行对应着入栈到出栈的过程。
  • 方法区 线程共享,存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等信息,JDK 1.8 中方法区被元空间取代,使用直接内存。
2.类加载机制

在这里插入图片描述

  • 双亲委派模式
    当一个类需要加载时,判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为 null 时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。
3.可以作为GCRoot的对象
  • a) 虚拟机栈中引用的对象(栈帧中的本地变量表)
  • b) 方法区中类静态属性引用的对象
  • c) 方法区中常量引用的对象
  • d) 本地方法栈中 Native 方法引用的对象

五、数据库

1.聚簇索引和非聚簇索引

在这里插入图片描述

  • 都使用 B+ 树作为数据结构
  • 聚簇索引中数据存在主键索引的叶子结点中,得到 key 即得到 data ;非聚簇索引的数据存在单独的空间。
  • 聚簇索引中辅助索引的叶子结点存的是主键;非聚簇索引中叶子结点存的是数据的地址;
  • 聚簇索引的优势是找到主键就找到数据,只需一次磁盘 IO ;当 B+ 树的结点发生变化时,地址也会发生变化,这时非聚簇索引需要更新所有的地址,增加开销。
2.为什么使用B+树作为索引

磁盘 IO 的次数是衡量索引数据结构好坏的重要指标
B+树作为数据库索引:
1.单一节点存储更多的元素,使得树更加矮胖,查询的IO次数更少
2.所有数据都放在叶子节点,所有查询都要查找到叶子节点,查询性能稳定
3.由于叶子节点形成有序链表,便于范围查询。

3.什么情况下可以用到 B 树索引
  • 主外键需要添加索引
  • 经常查询的数据列最好建立索引
  • 对于需要在指定范围内快速或频繁查询的数据列,因为索引已经排序,其指定的范围是连续的,查询可以利用索引的排序,加快查询的时间
  • 经常用在 where 子句中的数据列,将索引建立在 where 子句的集合过程中,对于需要加速或频繁检索的数据列,可以让这些经常参与查询的数据列按照索引的排序进行查询,加快查询的时间。
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值