八股打卡(三)

news/2025/3/1 21:47:52/

八股打卡三

  • 保证数据库和缓存一致性(回顾复习)
  • String, StringBuilder, StringBuffer区别
  • 接口和抽象类的区别
  • Java常见的异常类
  • Java三大特性
    • 继承
    • 封装
    • 多态
  • Java多态
  • 重写和重载的区别
  • final关键字的作用
  • == 和 equals区别
  • Java中的集合类
    • 线程不安全的集合类
    • 线程安全的集合类
  • ArrayList vs. Array
  • ArrayList vs. LinkedList
  • ArrayList的扩容机制
  • HashMap的底层实现
  • 解决hash冲突的方法
  • HashMap的put流程

保证数据库和缓存一致性(回顾复习)

  1. Cache Aside:先从缓存中取数据,如果命中则返回,不命中则访问数据库,并将该数据放入缓存中。对于修改的数据,先将数据持久化到数据库中,再使缓存失效。
  2. Read / Write Through:将更新数据库的操作给缓存代理。
  • Read Through:查询时更新缓存。当缓存失效时,缓存自己加载数据库中的数据,而Cache Aside需要调用方加载数据到缓存。
  • Write Through:更新数据时,若缓存未命中,则直接更新数据库中的数据,若命中,则先更新缓存,再更新数据库。
  1. Write Behind:在更新数据时,只更新缓存,不更新数据库,缓存会异步批量更新数据库。好处是数据IO很快,缺点是数据无法保证强一致性。

String, StringBuilder, StringBuffer区别

三者都是Java中处理字符串的类。

  1. 可变性:
  • String内部的字符数据是用final关键字修饰的,所以在定义后这个String是不可变的。当对该String对象进行修改时,实际上是新创建了一个String对象,旧的String会被JVM回收。
  • StringBuilder和StringBuffer都是可变的。这意味着它们都可以修改字符串,且不会创建新的对象。
  1. 线程安全:
  • String是不可变的,线程安全。
  • StringBuffer的方法是用synchronized关键字修饰的,线程安全。
  • StringBuilder是线程不安全的。
  1. 性能
  • 对于复杂的字符串操作(拼接,插入,删除)StringBuffer和StringBuilder的效率要比String高,因为它们可变。
  1. 使用场景
  • String 用于字符串很少变化的场景,如常量的定义和少量的变量运算。
  • StringBuffer用于频繁的字符串操作(拼接,替换,删除),且运行在多线程,例如XML文件解析,HTTP参数解析和封装。
  • StringBuilder用于频繁的字符串操作,且运行在单线程,例如SQL语句的拼接,JSON的封装。

接口和抽象类的区别

  1. 定义
  • 接口是一个抽象类型,定义了一组抽象方法,它里面只能包含常量(static final)和抽象方法。
  • 抽象类是一个类,它既能包含抽象方法也能包含具体方法,既能包含常量也能包含成员变量。抽象类不能直接实例化,通常需要子类继承并实现抽象类的抽象方法。
  1. 继承
  • 接口是多继承,一个类可以继承多个接口。
  • 抽象类是单继承,一个类只能继承一个抽象类。
  1. 构造器
  • 接口没有构造器,不能被实例化,一个类继承接口必须实现接口中所有方法。
  • 抽象类有构造器,用于初始化抽象类的实例,子类继承抽象类后,子类实例化会调用父类的构造方法。
  1. 访问修饰符
  • 接口:接口中变量默认public static final修饰,方法默认public abstract修饰。
  • 抽象类:其中的抽象方法默认是protected,具体方法public, private, protected都可以。
  1. 实现限制
  • 接口:一个类可以继承多个接口,但必须实现接口中所有方法。
  • 抽象类:一个类只能继承一个抽象类,必须实现抽象类中所有抽象方法。
  1. 设计目的
  • 接口:提供一种规范。
  • 抽象类:用于代码复用,提供基础功能和通用实现。

Java常见的异常类

Java中的异常类都是派生于Throwable类的实例,继承于Throwable。
Java中的异常分为两种:RunTimeException(运行时异常)和其他异常。运行时异常是由程序错误引起的,其他异常程序本身没有问题,外部导致。

  • 运行时异常
    编译器不会处理,如数组索引越界(ArrayIndexOutOfBoundsException),访问对象为空(NullPointException),强制类型转换错误,除0等等,程序内部引起的。
  • 其他异常
    又称为编译时异常,编译器要求必须处理这些异常。一般是由外部环境导致的,如打开一个不存在的文件,会抛出文件不存在异常。编译器要求java程序要捕获或声明所有的编译时异常,并对可能出现的异常做准备工作。

Java三大特性

继承

一个类继承另一个类的方法和属性,子类能够重用父类的代码,并且新增方法或者修改已有方法实现功能的拓展。一个类只能继承一个父类。

封装

将对象的属性和方法结合在一起,隐藏内部的实现细节,对外暴露一个可以访问的接口,通常使用public, private, protected关键字来设置访问权限,以实现封装。

多态

方法的重载和重写。

Java多态

当把一个子类对象赋值给父类引用变量,调用该引用变量的方法,其方法表现出子类方法的行为特征,而不是父类方法的行为特征。也就是收,对于相同的变量。调用同一个方法会表现出不同的特征,这就是多态。

  1. 编译时多态:编译器在编译阶段就会决定调用哪个方法。通过方法的重载来实现,根据参数的类型、数量和顺序决定调用哪个方法。
  2. 运行时多态:程序运行阶段会根据实际对象类型来选择调用的方法,通过方法的重写来实现,运行时多态依赖实际的对象类型而非引用类型。

重写和重载的区别

  • 重载:编译时多态,在一个类中允许有多个同名的方法,但是它们的参数列表不同(类型,个数,顺序),可以有不同的返回值和访问修饰符,通过静态绑定实现。
  • 重写:运行时多态,子类可以重新定义父类中已有的方法,方法名,参数列表和返回值都必须相同。重写的方法访问级别不能低于被重写的父类方法。虚拟机在运行时会根据实际对象的类型决定调用哪个方法。

总而言之,重载关注方法多样性,重写关注方法一致性,子类有其独特的实现。

final关键字的作用

不可变,可以用来修饰类,方法和变量。

  • 类:被final修饰的类不能被继承。
  • 方法:被final修饰的方法不能被子类覆盖。
  • 变量:
    (1)基本数据类型:被final修饰表示定义好后不可修改
    (2)引用数据类型:被final修饰后不能指向其他对象,即地址不可变,但是对象的内容可变。

== 和 equals区别

  1. ==运算符对于基本数据类型是比较值,对于引用类型比较在内存中的位置。
  2. equals()方法在Object类中被定义,默认与==类似。但是在子类中通常被重写,如String, Integer中重写equals()用于比较引用类型的内容。
  3. == 一般用于比较对象的地址,equals比较对象的内容。
  4. 在重写equals方法时也要重写hashCode方法,保证两者一致性。

Java中的集合类

Java中的集合类分为Collection和Map。Colleaction又派生出了List, Set, Queue三个类。Java中的集合类都是由这四个类派生的。

  1. List:有序元素的集合,允许重复值。有ArrayList, LinkedList。
  2. Set:无序元素的集合,不允许重复值,有HashSet, LinkedHashSet, TreeSet。
  3. Queue:用于队列的数据结构,有LinkedList, PriorityQueue。
  4. Map:键值对集合,有HashMap, LinkedHashMap和TreeMap。

线程不安全的集合类

以上都是线程不安全的,在多线程场景下,可能会出现不确定的结果。

线程安全的集合类

  1. Vector:类似于ArrayList,方法都是同步的来实现线程安全。
  2. HashTable:类似于HashMap,通过同步对象实现线程安全。
  3. ConcurrentHashMap:提高并发性能,通过锁分离技术实现线程安全。
  4. Collections.synchronizedList, Collections.synchronizedMap, Collections.synchronizedSet:将非线程安全的集合类包装成线程安全的集合类。

ArrayList vs. Array

  1. ArrayList底层是动态数组,Array是固定数组。
  2. ArrayList提供了强大的功能,如自动扩容、增加、删除,而Array没有。
  3. Array能够存放基本数据类型和对象,而ArrayList只能存放对象。对于基本数据类型,ArrayList只能存放它们的包装类(Integer, Double)。
  4. 在随机访问中,Array由于连续的内存存储,访问性能优于ArrayList。

ArrayList vs. LinkedList

  1. ArrayList底层是动态数组,LinkedList底层是双向链表。
  2. 随机访问:ArrayLsit随机访问的效率比LinkedLsit高,因为LinkedList要从头或尾部遍历链表,时间复杂度为O(n)。
  3. 插入删除操作:向ArrayList尾部插入元素很快,但是向中间或者头部插入元素,需要移动后续的元素,复杂度为O(n),而LinkedList只需要修改节点的引用。
  4. 扩容:当元素数量到达容量时会自动扩容,扩容设计新数组的建立和将旧数组内容复制到新数组,有一定的性能开销。
  5. 使用场景:随机访问操作多的用ArrayList,插入删除多的用LinkedList。

ArrayList的扩容机制

指的是计算出新扩容的数据的大小,并实例化,将旧数组中的数据复制到新数组。

  1. 创建一个ArrayLsit对象,系统会分配给它初始容量,默认为10,以节约数组空间。
  2. 当元素数量到达当前容量时,会自动扩容。调用其中的grow()函数,该方法会尝试将容量扩大为原来的1.5倍。
  3. 若新容量满足需求,那么调用Arrays.copyOf函数将旧数组的内容复制到新数组中;若不满足,则新容量大小为当前所需容量+1。

HashMap的底层实现

JDK1.8之前,HashMap是由数组和链表组成的,当发生哈希冲突的时候,多个元素会以链表的形式存储在同一个数组位置;JDK1.8以后引入红黑树,当链表长度超出默认长度(8)时会自动转换成红黑树,以提高查询效率。

  1. 为什么链表长度>=8成为红黑树,<=6成为链表?
    根据泊松分布,当负载因子默认为0.75时,单个hash槽的元素个数等于8的概率小于百万分之一,所以以7作为分水岭,等于7不转换,大于等于8转为红黑树,小于等于6转为链表。
  2. 为什么引入红黑树?
    因为红黑树具有以下性质:
  • 不追求绝对的平衡,允许一定的局部不平衡。相比于AVL(平衡二叉搜索树)树追求绝对的平衡,减少了很多性能开销;
  • 红黑树是一种自平衡的二叉搜索树,插入和删除的时间复杂度都是O(logn)。
  1. HashMap的读写时间复杂度?
  • 读:最好情况直接通过数组下标读取O(1);最坏情况发生哈希冲突,链表O(n),红黑树O(logn)。
  • 写:O(1),发生冲突O(n)。

解决hash冲突的方法

  1. 链地址法:在数组的每一个位置维护一个链表,当发生哈希冲突时,新的元素会被添加到链表的尾部。
  2. 开放寻址法:发生哈希冲突时,通过某种检测算法在哈希表中寻找下一个空闲的存储位置。
    HashMap采用链地址法。

HashMap的put流程

  1. 判断键值对数组是否为空,为空则扩容;
  2. 不为空,根据key计算hash值找到插入数组的索引i,判断table[i]是否为空,为空说明map里面这个位置没有键值对,那么新建节点插入,判断是否需要扩容,结束;
  3. 若table[i]不为空,说明这个位置有键值对节点了,判断它的首个元素的hashCode和equals是否与key相等,相等,那么直接覆盖掉value;
  4. 若不相等,发生了哈希冲突,首个元素也不是这个键值对,那么判断table[i]是否为TreeNode,是则说明形成了红黑树,直接插入树中;
  5. 如果不是TreeNode。说明table[i]现在还是个链表,遍历判断链表长度是否大于等于8,是则先转为红黑树,不是那就在链表中插入。注意遍历链表的过程中如果找到key,那么覆盖它的value。

http://www.ppmy.cn/news/1575874.html

相关文章

AI 时代下,操作系统如何进化与重构?

AI 时代下&#xff0c;操作系统如何进化与重构&#xff1f; AI时代服务器操作系统技术挑战2024 龙蜥操作系统大会最关注的是哪些议题分享与讨论&#xff1f;对于操作系统未来的发展趋势&#xff0c;有哪些观察和建议 2024 龙蜥操作系统大会&#xff08;OpenAnolis Conference&a…

linux上搭建Lago并部署

1. 系统更新 sudo apt update sudo apt upgrade -y 2. 安装必要的依赖 安装 Git sudo apt install git -y安装 Docker sudo apt install apt-transport-https ca-certificates curl software-properties-common -y curl -fsSL https://download.docker.com/linux/ubuntu/g…

【文献阅读】A Survey on Model Compression for Large Language Models

大语言模型模型压缩综述 摘要 大语言模型&#xff08;LLMs&#xff09;已成功变革了自然语言处理任务。然而&#xff0c;其庞大的规模和高昂的计算需求给实际应用带来了挑战&#xff0c;尤其是在资源受限的环境中。模型压缩已成为应对这些挑战的关键研究领域。本文对大语言模…

HTTPS 与 HTTP 的区别在哪?

HTTP与HTTPS作为互联网数据传输的核心协议&#xff0c;其通信机制与安全特性深刻影响着现代网络应用的可靠性与用户体验。本文将解析两者的通信流程、安全机制及核心差异。 一、HTTP的通信机制 先来看看HTTP是什么吧。 HTTP基于TCP/IP协议栈&#xff0c;采用经典客户端-服务…

DeepSeek-R1本地部署保姆级教程

一、DeepSeek-R1本地部署配置要求 &#xff08;一&#xff09;轻量级模型 ▌DeepSeek-R1-1.5B 内存容量&#xff1a;≥8GB 显卡需求&#xff1a;支持CPU推理&#xff08;无需独立GPU&#xff09; 适用场景&#xff1a;本地环境验证测试/Ollama集成调试 &#xff08;二&a…

go设计模式

刘&#xff1a;https://www.bilibili.com/video/BV1kG411g7h4 https://www.bilibili.com/video/BV1jyreYKE8z 1. 单例模式 2. 简单工厂模式 代码逻辑&#xff1a; 原始&#xff1a;业务逻辑层 —> 基础类模块工厂&#xff1a;业务逻辑层 —> 工厂模块 —> 基础类模块…

PYQT学习笔记-从简单窗口到多功能主窗口的实现

PyQt5学习笔记&#xff1a;从简单窗口到多功能主窗口的实现 1. 环境准备2. 创建第一个PyQt窗口2.1 代码实现2.2 代码解析2.2.1 创建应用程序2.2.2 创建窗口2.2.3 创建布局2.2.4 添加复选框和按钮2.2.5 信号与槽2.2.6 显示窗口 3. 关键点解释3.1 arg 是什么&#xff1f;3.2 lamb…

在PyCharm中集成AI编程助手并嵌入本地部署的DeepSeek-R1模型:打造智能开发新体验

打造智能开发新体验&#xff1a;DeepSeekPycharmollamaCodeGPT 目录 打造智能开发新体验&#xff1a;DeepSeekPycharmollamaCodeGPT前言一、什么是ollama&#xff1f;二、如何使用1.进入ollama官方网站:2.点击下载ollama安装包3.根据默认选项进行安装4.安装成功5.打开命令提示符…