Java-八股文
- hashcode()、equals()
- string、stringbuffer、stringbuilder
- extends、super
- == 、 equals
- 重载、重写
- 深拷贝与浅拷贝
- 字节码
- Java异常体系
- 什么时候抛异常?什么时候捕获异常?
- 类加载器
- 类加载器的双亲委派模型
- 什么是幂等性
- 如何实现接口幂等性
- 布隆过滤器原理及优缺点
- finally一定会执行吗?
- 为什么不能用浮点型表示金额
- 为什么GC的年轻代与老年代要以15来划分?能否改变?
- 依赖版本冲突问题如何解决?
- 什么时候需要用到序列化与反序列化?
- 从发请求到收响应,什么阶段需要用到序列化与反序列化?
- 实现序列化与反序列化为什么要实现serilizable接口?
- serilizable接口为什么要指定serialVersinUID?
- 为什么新版JDK要将string内部的char[]改为了byte[]?
- 如何优化提升接口性能?
- new string的时候创建了几个对象
- 反射机制的优缺点
- cookies与session的区别
- Integer与int的区别 为什么需要包装类
- JDK动态代理为什么只能代理有接口的类?
- API设计要素
- 资源路径(URI)
- HTTP动词(METHOD)
- 过滤信息(queryString)
- 状态码
- 错误信息
- 返回值
- HTTP状态码
- 2XX:成功,操作被成功接收并处理
- 3XX:重定向,需要进一步的操作以完成请求
- 4XX:客户端错误,请求包含错误或无法完成请求
- 5XX:服务端错误,处理请求的过程中发生了错误
- 202:请求已接受,但是未完成
- 201:成功请求并成功创建新资源
- 301:请求的资源已永久迁移至新的URI上
- 305:该资源必须通过代理访问
- 401:身份未认证
- 403:请求能理解,服务器拒绝执行访问,例如请求没有权限的资源
- 502:网关服务器收到无效请求
- 503:服务器暂时无法处理请求
- restful规范
- URI只能包含名词,不能包含动词,API的版本可以放到URI里面管理
- HTTP动词,不同的动词搭配相同的URI表示不同的意思:
- GET: 从服务器获取资源(一项或多项)(查)
- POST: 在服务器新建一个资源(增)
- PUT: 在服务器更新资源,服务器返回完整的属性(改)
- DELETE: 从服务器删除资源(删)【假删,逻辑删除】
- 状态码复用HTTP状态码即可
- 返回值统一使用JSON格式数据
- 字符流与字节流的区别
- JDK7与JDK8的区别
- Integer类的缓存机制
1.如果hashcode()不相同,两个对象一定不是同一个对象
2.如果hashcode()相同,两个对象不一定上同一个对象,需要进一步判别equals
3.如果equals相同,应当认为两个对象就是相同对象
由于hashcode方法仅返回一个值,equals里面有若干逻辑,因此,部分集合类的判断中,会优先判断hashcode,如果相同再继续equals判断
结论:如果改写了equals方法,则必须改写hashcode方法,以便于逻辑一致
string:常量,每次修改都会创建新的字符串常量
stringbuffer:线程安全的字符串变量
stringbuilder:不安全的字符串变量
<? extends T>:?是T的子类
<? super T>:?是T的基类
==:基本类型-看值;引用类型-看引用地址
euqals:看各种类的重写逻辑[逻辑里面也有可能复用==]
重载:针对单一类中,相同方法名,不同方法签名
重写:针对父子类,相同方法名,相同方法签名
重写:返回值类型、抛出异常都必须小于等于父类;访问修饰符大于等于父类
浅拷贝:基本数据类型拷贝了第二份,引用类型的变量全部都是拷贝了一份引用地址,指向了原来的地方。
深拷贝:所有数据类型都拷贝了第二份,不仅仅拷贝引用地址。
定义:字节码文件是Java源码编译过后的一种格式,各个平台上相同的源码编译出的字节码是相同的,但是,字节码转化的机器码不相同,这个转化上JDK(JRE)做的,因此,Java上跨平台语言
相当于编译过程所指的,中间代码[前有词法分析、语法分析、语义分析][后有代码优化、目标代码生成]
优点:实现了语言的跨平台;编译过程可以做代码优化,提高执行效率
graph TD;
Throwable
-->
Exception
Throwable
-->
Error
Exception
-->
RuntimeException
Exception
-->
非RuntimeException
error是非常严重的错误,程序已无法正常运行,没必要捕获
运行时异常,一般是逻辑问题,应尽量避免
非运行时异常,不处理无法正常运行,必须处理
抛:自身无法处理就往上抛,由上级处理
捕获:自身能处理就捕获,捕获走既定处理流程
graph TD;
bootstrapClassLoader负责加载JAVA_HOME下lib里面的jar包与类文件
-->
ExtClassLoader负责加载JAVA_HOME下lib下ext里面的jar包与类文件
-->
AppClassLoader负责加载classpath路径下的类文件
由16可知,类加载器共三个,AppClassLoader有两个父类
当AppClassLoader加载时,会优先调用父类的加载器,这种JVM机制叫做双亲委派模型
AppClassLoader.loadClass(){
ExtClassLoader.loadClass(){
bootstrapClassLoader.loadClass();
}
}
定义:多次重复执行与单次执行产生的效果应当一致,例如,相同的请求,请求一次与请求多次,产生的效果应当是稳定一致的
就请求类型而言,
删除、查询
1.通过请求里面带的ID,或者请求参数拼接计算出一个ID,将ID存入Redis等存储中间件,用ID来标识请求是否处理过
修改、新增
2.除了阻断请求到数据库处理以外,还可以通过在数据库处理的时候,加上乐观锁,保证如果有其他请求修改的话,就放弃修改
3.通过数据库的唯一约束来使得相同的修改失败也可以
4.可以在数据库之前加个监控层,监控服务器资源,线程池资源等等
5.网关是个好东西,可以针对性封ip,限流,鉴权,完全没有必要每个接口考虑这种事情,投入产出比太低
原理
存
1.每个key通过若干哈希算法,得到对应下标
2.对应下标的位置全部置为1
取
3.给定key计算对应下标,如果都为1,可能在里面,有0,肯定不在里面
优点:
1.占用空间小
2.速度快,耗时少,O(K),K为哈希算法数量
缺点:
1.仅能判断在或不在,拿不到原值
2.存在假阳性误判情况
正常情况 finally一定会执行
因此 接下来仅考虑什么情况不执行
1.进入try之前就报错 从而终止了
2.执行finally之前有system.exit(0) 退出JVM了 也不会执行finally
因为年龄是存在对象头里面的,总共就划分了4个bit位,最大值就是15,默认为什么是这个值,应该是当初发布GC的时候有实验过的经验值
能改变,但是,最大值就是15[只有4个bit位]
1.首先定位是哪个包出现了冲突?
IDEA可以进行依赖分析;或者mvn dependency:tree
2.判断为什么冲突?
2.1 单纯的只是自己引用了两个版本
移除其中一个;
采用dependencyManage统一管理版本号
2.2 由于子项目或者依赖,引入了其下的一个依赖 导致与自己引入的依赖冲突
子项目利用optional 将依赖不再传递至上级模块;
主项目采用exclusion 将子项目依赖或者依赖的依赖直接排除在外
1.将对象数据持久化到磁盘
2.深拷贝
3.网络传输只能用流
网络传输阶段需要用到序列化与反序列化
1.前端发请求到后台
2.后台返回响应给前端
后台处理过程中,如果需要用到深拷贝,也可能用到序列化与反序列化
后台处理过程中,如果需要持久化,也可能用到序列化
1.这个接口是个标记,当JVM发现了该类有实现这个接口的时候,底层就会自动实现序列化与反序列化
2.有了这个标记,应当可以确保不会对不可序列化的对象进行序列化
如果不指定,则JVM会依据对象生成对应ID来进行序列化与反序列化
如果类一旦修改,那么序列化与反序列化两阶段生层的ID就有可能不同,从而导致失败
因此,显式指定ID,可避免序列化与反序列化生成的ID不同
原本string内部有一个表示所有字符的char[],且string内部用的是UTF-16,即每个字符有2字节,共16bit位
因此,如果内容全部都是ASCII 字符,那么每个字符都仅需要1个字节就能表示,即一个byte的空间,
因此,string增加了compact string的优化,能尽量减少空间成本(char[]--->byte[])
但是,这个优化对开发者来说是透明的,不需要修改任何代码
接口:Java+SQL
Java:
1.减少重复计算,用空间换时间
2.利用布隆过滤器等方式,能尽早判断的东西提前,以便于更快返回,减少逻辑执行
3.能异步执行的操作尽量异步,不必同步一直等待
SQL:
1.热点数据采用缓存方式,减少数据库IO成本
2.SQL本身的分析优化
完全初始状态下,
字符串常量池,如果没有这个字符串,重新实例化一个常量对象,保存该常量
堆-实例化一个string对象,指向常量池中对应常量对象
常量池有对应常量对象
仅堆中实例化一个对象指向常量池中常量对象
优点:
1.可以在运行时,对类进行修改与操作
2.可以在运行时,轻松获得类的属性与方法,通过反射来动态调用
缺点:
1.清晰:反射机制多了以后,代码可读性降低
2.性能:反射调用类,比直接调用类,性能会降低
3.违反规范:使用反射可以绕过一些限制访问的属性与方法,从而破坏了原有的抽象性
1.cookies是客户端存储机制
2.session是服务端存储机制[又会引出分布式环境下的session不共享问题,要么抛弃状态,要么Redis,要么轮询就盯着一个,要么服务端就不要了存在客户端就好了每次验证就行]
graph TD;
客户端首次请求
-->
服务端将状态信息保存到session,并返回给客户端sessionID
-->
客户端保存到cookies
-->
携带sessionID请求服务端
定义:
Integer:包装类
int:基本数据类型
存储:
包装类一定上保存到堆上
基本数据类型如果是成员对象,保存到堆上,如果是局部变量,保存到栈
初始:
包装类初始为null
基本数据类型为0
本身:
包装类本身提供若干方法
基本数据类型本身不带任何方法
Java是面向对象的语言,因此,很多操作需要对象来处理,对开发人员用对象也更灵活
例如,集合必须保存对象
原因:
JDK动态代理的原理: 继承java.lang.reflect.Proxy类 然后实现对应的接口 生成一个动态代理类 $Proxy
由于Java仅支持单继承 所以这里只能是实现对应接口
为什么要这么设计?
1.动态代理的应用场景应该是针对原始实现的一个拦截,做功能的增强或者扩展,
2.且Java一直提倡的是面向接口开发
综上所述,从应用场景上来说,应该是合理的
如果有代理实现类的需要 可以选择cglib组件
通过继承对应的类 子类重写对应的方法 可以对原方法进行拦截
举例:
完整列表:https://zhuanlan.zhihu.com/p/608552648?utm_id=0
restful风格规范的初衷就是减少沟通障碍,所提出的一种API设计规范,因此,该规范主要是针对API设计要素提出了若干约束
1.处理类不同
inputStream outputStream是为了处理字节流存在的
reader writer 是为了处理字符流存在的
2.处理单元不同
Java里面用的UTF-16。因此 一个字符一般是用于处理两个字节的Unicode字符
字节流里面处理单元为一个字节
字符流里面处理单元为两个字节
3.处理格式不同
字节流可以处理所有格式数据
字符流仅能处理文本文件
4.缓冲区使用不同
字节流不会用到缓冲区
字符流在使用过程中会用到缓冲区
接口:
接口可以添加默认方法
新增函数式接口声明
方法:
新增lambda表达式支持
新增流式处理API
集合:
hashmap新增红黑树结构
所谓的Integer的缓存机制,就是Integer与String类似,也有常量池的概念
默认-128~127,这个范围内的整数值包装类,会取常量池里面的对象,从而保证其连地址都是一样的
参考:
- https://blog.csdn.net/liwenxiang629/article/details/109508530
- https://blog.csdn.net/weixin_43235210/article/details/90444710?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90444710-blog-109508530.235%5Ev38%5Epc_relevant_sort&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90444710-blog-109508530.235%5Ev38%5Epc_relevant_sort&utm_relevant_index=2
- https://blog.csdn.net/cst522445906/article/details/126723280
- https://www.bilibili.com/video/BV1MU4y1j7Kq/?spm_id_from=333.337.search-card.all.click&vd_source=5c5bc2d817741ded0db4f222d4a03a7c
- https://zhuanlan.zhihu.com/p/608552648?utm_id=0