JAVA 面试笔记
java中的代理
- 静态代理
- JDK动态代理
- Cglib代理
设计模式
- 工厂模式
- 单例模式
- 适配器模式
- 观察者模式
- 策略模式
- 代理模式
spring-cloud组件
- Netflix Eureka 服务发现
- Netflix Ribbon 负载均衡
- Netflix Hystrix 断路器
- Netflix Zuul 网关
- Spring Cloud Config 分布式配置
事务四大特性
- A:原子性(Atomicity)
- C:一致性(Consistency)
- I:隔离性(Isolation)
- D:持久性(Durability)
分布式事务
CAP
- C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。
- A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。
- P (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。
BASE
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。是对CAP中AP的一个扩展
- 基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
- 软状态:允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是CAP中的不一致。
- 最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致。
BASE解决了CAP中理论没有网络延迟,在BASE中用软状态和最终一致,保证了延迟后的一致性。BASE和 ACID 是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。
创建对象的四种方式
- new
- clone
- 反射
- 序列化
Redis穿透
当反复查数据库和缓存中都没有的值的时候会出现穿透
-> 将查不到的值在缓存中设置为null
Redis雪崩
当Redis中key同一时间大量失效,会造成雪崩
-> 设置随机数,避免同一时间失效
HashCode 和 equals
重现equals时候必须重写HashCode
线程池常用参数
- corePoolSize:核心线程数量,会一直存在,除非allowCoreThreadTimeOut设置为true
- maximumPoolSize:线程池允许的最大线程池数量
- keepAliveTime:线程数量超过corePoolSize,空闲线程的最大超时时间
- unit:超时时间的单位
- workQueue:工作队列,保存未执行的Runnable 任务
- threadFactory:创建线程的工厂类
- handler:当线程已满,工作队列也满了的时候,会被调用。被用来实现各种拒绝策略。
ArrayList
可以用Collections.synchronizedList将ArrayList转化成线程安全的list
实例化的时候不指定初始化长度将会分配一个长度为0的数组
/**
* 空的数组
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 构造方法
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
初始化大小为10
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 当数据长度大于数组长度时扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩容到之前的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
comparable 和 comparator
comparable
接口需要类进行实现,需要实现compareTo
方法才能排序,又称自然排序
comparator
接口单独实现就好,需要实现compare
方法,在java1.8
中可以使用lambda
表达式简化代码
fail-fast 保护机制
在使用for in
或者forEach
对数组进行修改会出发fail-fast
保护机制,原因是在修改之后调用了checkForComodification
.
可以使用迭代器就可以避免fail-fast
保护机制
单例模式
- 懒汉式
/**
* 懒汉式单例模式在第一次调用的时候进行实例化。
*/
public class Singleton1 {
/**
* volatile 关键字避免重排
*/
private static volatile Singleton1 instance = null;
private Singleton1() {
}
/**
* 1、适用于单线程环境(不推荐)
*/
public static Singleton1 getInstanceA() {
if (null == instance) {
instance = new Singleton1();
}
return instance;
}
/**
* 2、适用于多线程环境,但效率不高(不推荐)
*/
public static synchronized Singleton1 getInstanceB(){
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
/**
* 3、双重检查加锁(推荐)
*/
public static Singleton1 getInstanceC() {
// 先判断实例是否存在,若不存在再对类对象进行加锁处理
if (instance == null) {
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
}
- 饿汉式
/**
* 饿汉式单例类:在类初始化时,已经自行实例化。
*/
public class Singleton2 {
private static final Singleton2 instance = new Singleton2();
private Singleton2() {
}
public static Singleton2 getInstance() {
return instance;
}
}
- 静态内部类
/**
*加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造
*器、静态方法等)被调用时发生。 由于在调用 StaticSingleton.getInstance() 的时候,
*才会对单例进行初始化,而且通过反射,是不能从外部类获取内部类的属性的;由于静态内部类的特
*性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性。
*总结:
*优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。
*劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象
*
*/
public class StaticSingleton {
/**
* 私有构造方法,禁止在其他类中创建实例
*/
private StaticSingleton() {
}
/**
* 获取实例
*/
public static StaticSingleton getInstance() {
return StaticSingletonHolder.instance;
}
/**
* 一个私有的静态内部类,用于初始化一个静态final实例
*/
private static class StaticSingletonHolder {
private static final StaticSingleton instance = new StaticSingleton();
}
/**
* 方法A
*/
public void methodA() {
}
/**
* 方法B
*/
public void methodB() {
}
public static void main(String[] args) {
StaticSingleton.getInstance().methodA();
StaticSingleton.getInstance().methodB();
}
}
- 枚举
/**
*创建枚举默认就是线程安全的,所以不需要担心double checked locking,而且还能防止反序列
*化导致重新创建新的对象。保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量)。
*/
public class Singleton {
public static void main(String[] args) {
Single single = Single.SINGLE;
single.print();
}
enum Single {
SINGLE;
private Single() {
}
public void print() {
System.out.println("hello world");
}
}
}
排序算法
- 快速排序
- 冒泡排序
- 希尔排序
- 归并排序
查找算法
- 顺序查找
- 二分查找
- 插值查找
- 斐波那契查找
- 二叉树查找
- 平衡查找树之2-3查找树
- 平衡查找树之红黑树
- B树
- B+树
数据结构
- 数组
- 链表
- Hash表
- 树
HashMap
LoadFactor(加载因子)默认为0.75
,当加载因子
越大,对空间利用就越充分,链表的就会越长,所以查询效率也就越低。反之,查询效率越高,但Hash表的数据就越疏松,空间也更加浪费。