层次分明 主次清晰 慢条斯理
String为什么设计为不可变?
安全性:
字符串底层使用private final修饰的 char数组,保证对象不会被修改。可以适用于url,hashMap的 key等。
缓存哈希值:字符串的哈希值被缓存,提高了散列集合的性能。
字符串池:字符串常量池可以共享相同的字符串对象,节省内存空间并提高性能。
总结来说,不可变的String对象在并发环境下更安全、更高效,提供了更好的性能和安全性,同时利用字符串池可以节省内存。因此,String被设计成不可变的。
接口和抽象类的区别?
相同点:
都是不断向上抽取而来的,都是父类,都包含抽象方法,都不能被实例化。
不同点:
- 接口使用的是interface关键字修饰,抽象类使用的是 abstract关键字修饰。
- 接口的属性都是 public static final 修饰的。
抽象类的属性成员可以是各种类型。
- 接口可以多继承,但不可能实现多个接口。
抽象类不可以多继承,但可以实现多个接口。
- 一个类只能继承一个抽象类,但一个类可以 实现多个接口。
- 抽象类被类继承,体现的是 is-a的关系。是对类的增强。
接口被类实现,体现的是 like-a的关系。是对方法的增强。
ArrayList 和 LinkedList 和 Vector 的区别:
Arraylist:
1.ArrayList底层实现是数组,采用的是懒汉式。在对象创建时不会初始化容量, 而是在第一次添加元素时才会初始化数组容量,默认10。
扩容时在原容量上扩充0.5倍。
2.查询相对较快,因为数组是连续的内存。
3.增删较慢,因为数组的元素需要向前或者向后位移。
4.占用内存相对较少。
Vector:
1.Vector底层实现也是数组,采用的是饿汉式,在对象创建时就立即初始化数组 容量。默认容量也是10。扩容为原来的0.5。
2.查询和 增删与 ArrayList 相同。
3.Vector的方法含有synchronized 同步锁,可以保证安全性。
LinkedList:
1.LinkedList 底层实现是 双向链表。
2.查询慢,但增删较快。
3.占用内存相对较大
HaspMap的底层结构 为什么使用的是 数组、链表、红黑树?
- 使用数组是因为可以根据 key的hash值快速定位到哪个槽位。
- 链表是为了解决hash冲突。
- JDK1.8使用红黑树代替超过8个节点的链表,主要是提高查询性能。从原来的O(n) 到O(logn)。
HashMap 和 Hashtable的区别?
- Hashtable底层是哈希表(数组+链表),HahsMap底层是哈希表+红黑树。
- Hashtable在不指定容量的情况下默认是11,不要求底层数组的容量一定要为2的 整数次幂。扩容时将容量变为原来的2倍加1.
HashMap 在不指定容量的情况下默认容量是16,要求一定为2的整数次幂;扩容时, 将容量变为原来的2倍。
- HashMap 是线程不安全的。
Hashtable 是线程安全的 其方法上都加了synchronized的锁。
- HashMap 的 KV 可以是 null。
Hashtable 的 KV 不能是null会报空指针异常。
- 两者通过hash值散列到哈希表的算法不一样。
Hashtable 使用的是除留余数法,直接使用hashCode。
HashMap 是 强制容量为2的次幂,重新根据hashCode计算hash值,
hash & (容量-1),这样可以使得奇数、偶数、分步更均匀。
- HashMap 剔除了Hashtable包含的contains方法,改成了containsKey, containsValue
什么是反射?
反射在运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,都可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能都能成为java反射机制。
Java反射需要借助与四个类class,Constructor,Field,Method;
什么是 java序列化?
序列化是一种用来处理对象流的机制,所谓对象流就是将对象的内容进行流化,将数据分解成字节流,以便存储在文件中或在网络上进行传输。 可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
使用序列化需要实现serializable 标记接口,使用ObjectOutputStream的writeObject 将对象序列化。恢复时使用ObjectInputStream 的readObject 将对象反序列化。
Http常见的状态码 有哪些?
200 OK //客户端请求成功
301 (永久移除),请求的 URL 已移走。
302 临时重定向
400 客户端请求有语法错误,不能被服务器所理解
401 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务。
404 Not Found //请求资源不存在。
500 服务器发生不可预期的错误。
503 服务器当前不能处理客户端的请求,一段时间后可能恢复正常
GET 和POST 的区别?
- Get请求的请求信息在url后,请求信息以?隔开,参数使用&相连。
Post请求将请求信息放置在报文体中。
- Get请求由于是通过URL提交数据的,而URL长度受浏览器限制,所以get请求 大小有限制。
Post请求的数据理论上不受限制。
- 使用场景不同,get是从 服务器上获取数据,post 是向服务器传送数据。
- POST 的 安全性更高。
Cookie和 Session的区别?
Cookie 和session 都是用于跟踪用户会话的技术,它们在存储位置、使用方式、安全性等方面存在差异。
- 存储位置:
Cookie 数据存放在客户端的浏览器上。当用户首次访问某个网站时,服务器会向用户的浏览器发送一段包含用户信息的数据(即Cookie)。浏览器接收并存储这些数据,以便在用户下次访问该网站时将其发送回服务器。
Session 数据放在服务器上。当用户访问网站时,服务器会为该用户创建一个唯一的Session ID,并将其发送给用户的浏览器。浏览器将这个Session ID存储在Cookie中(注意这里的Cookie仅用于存储Session ID,而非用户信息)。之后,每当用户与服务器进行交互时,浏览器都会将这个Session ID发送给服务器。服务器根据这个Session ID查找对应的Session数据,从而识别用户并提供服务。
- 安全性:
Cookie 由于存储在客户端的浏览器中,因此容易受到跨站脚本攻击(XSS)等安全威胁。攻击者可以通过窃取或篡改Cookie中的信息来冒充用户或窃取用户的敏感信息。
Session 相对更为安全,因为数据存储在服务器端,相对较难被攻击者直接访问或篡改。
3.存储内容与大小限制:
Cookie 只能存储简单的字符串数据,如用户名、密码等,且大小受浏览器限制,一般限制在4K的大小。
Session 可以存储更多的数据,没有明确的大小限制,理论上只受内存限制。
4.生命周期的控制:
Cookie 的生命周期可以通过设置过期时间来控制,如果设置了过期时间,那么即使关闭了浏览器,Cookie仍然会保存在本地硬盘中,直到过期时间到达才会被删除;如果没有设置过期时间,那么关闭浏览器时Cookie就会被删除。
Session 的过期取决于服务器的设定,例如可以设置超时限制为10分钟,用户持续请求访问,一直在限制时间内进行保活,那Session就永远不会过期。
详情在CSON 网站搜 :彻底了解Cookie和Session的区别
HashMap 的底层原理?
JDK1.8 之前 HashMap 由 数组+链表 组成。
JDK1.8 后 HashMap 由 数组+链表+红黑树 组成。
使用数组存储KV 键值对,使用链表解决哈希冲突,将发生哈希冲突的节点存储在同一 桶中,形成链表。当链表长度超过8,为了提高查询性能,会将链表转换为红黑树。
HashMap 的put流程?
hashMap添加元素的流程,hashMap在第一次添加元素时会进行扩容,默认容量为16。之后添加的元素,根据该key 的hash值与数组的容量进行按位与计算,定位到该元素的存储位置。然后插入元素的key 和之前的元素相同会替换为新值,返回旧值。
如果插入的元素的数量超过了 hashMap的临界值,会进行扩容。扩容为原来的2倍。并根据新数组容量重新计算所有元素的位置。
临界值为 默认容量 * 0.75加载因子的结果。
如果发生了hash冲突,将该元素插入到桶的末尾。当桶也就是链表的长度大于8并且数组的容量大于等于64时,会将链表转换为红黑树。如果桶中的数量小于6又将红黑树退化为链表。
HashMap为什么不一开始就使用红黑树?
因为成本问题,红黑树的空间消耗是 链表的两倍。
HashMap的转换阈值8是怎么来的?
通常如果 hash 算法正常的话,那么链表的长度也不会很长,那么红黑树也不会带来明显 的查询优势,反而会增加空间负担。所以通常情况下,并没有必要转为红黑树,所以就选择了概率非常小,小于千万分之一概率,也就是长度为 8的概率,把长度 8 作为转化的默认阈值。
链表长度符合泊松分布,各个 长度的命中概率依次递减,当长度为 8 的时候,概率仅为 0.00000006。
HashMap 为什么选择 使用 0.75 作为加载因子?
如果加载因子较大,那么只有当元素填满数组长度时才会选择去扩容,虽然加载因子较大时会提高空间的利用率,但会导致hash碰撞形成链表,导致查询效率变慢。
如果加载因子较小,虽然可以最大程度减少hash冲突,链表长度减少,频繁扩容,空间浪费比较大。
应该是为了空间以及时间上的平衡,才选择0.75作为加载因子。
HashMap初始容量为什么是2的次幂 以及 扩容为什么是2倍的形式?
因为容量是2的次幂可以均匀的分布在数组上、减少hash碰撞,避免形成链表以
降低查询效率。
HashMap 什么情况下会导致内存泄漏的问题?
HashMap 在使用对象作为key时,存入数组后,由于对象的成员被修改了,而hashCode的计算与修改的成员相关,也让hashCode也发生了变化,导致无法再次通过hashCode 取出。这样就造成了内存泄漏。
如何解决?
- 使用不可变对象作为hashMap 的key。
- 如果要使用一个类作为key,保证hashCode 的计算只与 不可变成员相关。
Comparable 和 Comparator 的区别?
Comparable 和 Comparator 都是用来实现集合中元素的比较、排序的。
Comparable 属于java.lang包,Comparable是在集合内部实现的比较、排序方式。
Comparator 属于java.util包,Comparator 是集合外部实现的比较、排序方式。 Comparator体现了一种策略模式。策略模式就是不改变对象自身,而用一个策略对象 来改变它的行为。
什么是泛型?
泛型是JDK1.5以后出现的安全机制。
泛型:是一种将数据类型明确的工作推迟到创建对象或调用方法时,才明确的特殊类型
在类、接口、方法上申明,可以应用在变量、形参、方法、类、接口上。
泛型的擦除和补偿?
泛型擦除是指在编译时将泛型加上的类型参数剔除。泛型擦除是为了 兼容运行时的类装载器。因为在jdk1.5之前是不认识泛型的,所以为了避免jvm重构 在编译时检查完泛型类型是否匹配后,就对泛型进行了擦除。
泛型补偿是指 对迭代出来的元素自动进行了强制转换。因为在编译时就已经确定了泛型的类型。
sleep 和 wait 有什么区别?
1.sleep 定义在Thread类中,是类方法。Wait定义在Object类中,属于实例方法。
2.在同步代码块中 sleep不会释放锁,wait会释放锁。
3.sleep必须指定参数。
4.sleep(0) 代表当前线程放弃CPU执行权,重新参与争抢Cpu执行权。
wait(0) 代表当前线程进入等待状态,不参与Cpu执行权。
并发的三大特性?
有序性、原子性、可见性。
为什么要使用线程池?
1.降低资源消耗
对已创建的线程重复利用,减少频繁创建和销毁线程。
2.提高响应速度
线程池预先创建一定数量的线程,任务到来时,立马执行任务。
- 提高线程的可管理性。例如:线程在一定时间内没有执行任务,就销毁了。
线程池的底层原理?
1.七大参
2.线程池的五大状态
3.线程池如何执行任务的
线程池的工作原理?
1.线程池刚创建时没有任何线程,等任务到来时才会创建线程,当然也可以调用
prestartAllCoreThreads() 或者 prestartCoreThread() 方法预创建
corePoolSize个 线程。
2.调用execute提交一个任务时,如果当前工作线程数小于核心线程,就创建线程执行 任务。
3.如果工作线程数 大于等于核心线程数,之后的任务都会进入等待队列中缓存。
4.如果等待队列中的任务满了,
有哪些拒绝策略?
AbortPolicy:终止策略,直接抛出异常。
CallerRunsPolicy:由当前线程(main)执行该任务。
DiscardPolicy:忽略此任务(最新的任务),没有处理方式,空实现方法。
DiscardOldPolicy:忽略等待最久的任务。
Synchronized 与 lock 有什么区别?
1.Lock是一个接口,Synchronized是关键字,java的内置实现。
2,Lock 可以感知有没有获取锁,正在获取锁的线程可以响应中断。
Synchronized 不能感知有没有获取锁,如果线程没有获取锁,会一直等待下去。
3.lock 可实现公平锁、锁可以绑定多个条件。提供更丰富 的 对锁的操作方法。
4.lock可以实现读读共享。
什么是ThreadLocal ?
TreadLocal是一个用于线程范围内共享的变量。线程内使用的变量,线程外独立。
ThreadLocal底层原理?
ThreadLocal底层实现基于它的内部类ThreadLocalMap,每个线程都维护了一个ThreadLocalMap,它是一个基于KV键值对的entry数组,entry对象继承了弱引用,使用threadlocal对象作为他的key,它是弱引用,传递进来的值作为它的value,使用的是强引用。
Thread的set方法,判断当前线程的ThreadLocalMap 是否为null,如果是null则进行初始化。
如果不是null,就将threadlocal对象作为key,传递进来的值作为value,封装到 entry对象并存入到数组中,根据key的hash值按位与 数组长度,得到下标位置。
什么是内存泄漏?
内存泄漏是指 无效对象还在占用着内存。
ThreadLocal 会发生内存泄漏吗?
ThreadLocal内存泄漏是指 当外部强引用被置为null,此时由于entry中的threadLocal对象是弱引用,又被gc回收,导致entry对象中的threadlocal对象变为null,无法访问到entry对象中的value。
为什么ThreadLocal对象设计成弱引用?
ThreadLocal 被设计为弱引用的原因是为了避免内存泄漏。
如果threadLocal的key 被设计为 强引用,那么计时线程执行完毕,ThreadLocal 对象及其对应的value值也可能因为强引用的存在而无法被垃圾回收器回收,从而导致内存泄漏。
什么是强引用、软引用、弱引用、虚引用?
强引用:为变量赋值一个对象,这个引用变量就是强引用。强引用的对象不会被垃圾回收器回收。 当内存空间不足时,就算java虚拟机抛出OutOfMemoryError错误,也不会回收这个对象。
软引用:软引用的对象在内存充足时不会被回收,但在内存不足时,会被垃圾回收器回收。
弱引用:弱引用的对象无论内存是否充足,都可能被垃圾回收器回收。
虚引用:虚引用是最弱的引用类型,一个对象无论是否有其他类型的引用指向它,只要仅仅被一 个虚引用关联,那么它随时可能被垃圾回收。虚引用主要用于跟踪对象被垃圾回收的活动, 它不会对对象的生存周期构成影响,也不能通过它来访问对象。
了解volatile关键字吗?
- volatile 是java提供的轻量级的同步机制。保证共享变量的可见性。被volatile修饰的变量,它的值发生变化时,其他线程立即可见, 避免了脏读。
- volatile 禁止了指令重排,可以保证程序的有序性。但由于进制指令重排,所以jvm相关的优化没了,性能偏弱。
Volatile 与 Synchronized 有什么区别?
- volatile本质是告诉JVM需要从主存中读取变量的值。 synchronized则是锁定当 前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile 只能用于修饰变量,Synchronized 可以修饰方法、代码块。
- Volatile只能保证变量的可见性,不能保证原子性;而synchronized则可以保证 变量的可见性和原子性。
- Volatile 不会造成线程阻塞。
- Volatile标记的变量不会被编译器优化。
synchronized标记的变量可以被编译器优化。
什么是死锁?
死锁是指2个或2个以上的线程在执行过程中,因为争抢资源,导致互相等待的现象。
死锁产生的四个必要条件:
1.互斥,锁资源只能有一个线程拥有。
2.不可抢占,线程持有锁,别的线程不能占有,需要等当前线程主动释放。
3.线程在持有一个锁资源的同时,请求另一个锁资源。
4.循环等待。
如何解决死锁?
死锁发生了是不可逆的,只有在之前设置一些预防死锁发生的解决方案。
1.注意加锁的顺序,保证每个线程按同样的顺序进行加锁。
2.为锁 设置过期时间。
SpringMVC 的核心组件:
DispatcherServlet
HandlerMapping
HandlerAdapter
ModelAndView
ViewResolver
View
SpringMVC 的工作流程?
Spring 和 SpringMVC 的常用注解有那些?
SpringMVC 常用的注解有 @RequestMapping 。
- @Component 标识一个受spring管理的组件。
- @Controller 标识一个为 表示层的组件
- @Service 标识一个业务层的组件
- @Repository 标识一个为 持久层的组件
- @AutoWired 自动装配。
- @Qualifier("") 具体指定要装配的组件的id值,和AutoWired一起使用。
- @RequestMapping 完成请求映射。
Mybatis的${} 和#{} 有什么区别?
MQ 是什么? 有什么作用?
MQ是在应用程序之间进行通信的一种方式。它通过消息传递队列发送和接收消息数据。
设计模式有哪些类型?
常见的设计模式有23种。这些模式可以分为三大类:
创建型:
单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
结构性:
适配器模式、装饰者模式、代理模式、桥接模式、外观模式、享元模式、组合模式。
行为性:
观察者模式、模版方法模式、命令模式、状态模式、责任链模式、解释器模式、
中介者模式、访问者模式、策略模式、备忘录模式、迭代器模式。