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表的数据就越疏松,空间也更加浪费。

posted @ 2020-03-17 15:37  Jay·Chan  阅读(151)  评论(0编辑  收藏  举报