笔试面试(简答题)
整理高频笔试面试题,主要是简答题,有时间会不断补充,也当做自己的学习笔记,整理的过程中也会参考书籍和网上的一些资料,如果用到了您文章的内容,在此感谢。
-
接口和抽象类区别
相同点:
1)都不能被实例化
2)接口的抽象类或者抽象类的子类都只有实现了接口或者抽象类中的方法才能够实例化。
不同点:
1)接口只有定义,不能有方法的实现,而抽象类可以有定义与实现,其方法可以在抽象类中实现;
2)实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但是一个类只能继承一个抽象类,因此使用接口可以间接达到多重继承的目的;
3)接口强调特定功能的实现,设计理念是“like a”关系,而抽象类强调所属关系,其设计理念为“is a”关系;
4)接口中定义的成员变量默认为public static final,而且必须赋初值,其所有的成员方法都是public abstract的,而且只能被这两个关键字修饰;而抽象类可以有自己的数据成员变量,也可以有非抽象的方法,抽象类中成员变量默认为default,当然也可以被定义为public、protected、private,抽象类中的抽象方法不能用private、static、synchronized和native等访问修饰符修饰,必须以分号结尾,不能带{}。
总结当功能需要累计时,用抽象类;不需要累积时,用接口, -
实现多线程的方法
1)实现Runnable接口,并实现接口的run()方法;
2)继承Thread类,并重写run()方法;
3)实现Callable()接口,并重写call()方法;
4)通过线程池。
注意:以上三种方法,前两种方式线程执行完后是没有返回值的,只有最后一种是带返回值的。当需要实现多线程时,一般推荐实现Runnable接口的方式。因为一般来说我们认为一个类在它们需要被加强或者修改时才会被继承,所以如果没有必要重写Thread类中其它的方法,那么通过1)和2)实现多线程效果是相同的,这种情况下推荐使用实现Runnable接口方式来创建线程。实现接口的方式也可以避免单继承。
3.给出实现单例模式的方法(至少两种),并且说明优缺点。
- [饿汉式]
/**
* @description: 饿汉式(静态常量,线程安全,可用)
* 优点:写法简单,在类装载的时候就完成了实例化,避免线程同步问题
* 缺点:没有达到懒加载的效果,如果一直没有使用,会造成内存浪费
* @author: Liu Administrator
* @time: 2020/8/9 12:40
**/
public class Singleton {
/**
* 静态变量记录初始化的唯一实例,保证线程安全
*/
private static final Singleton INSTANCE = new Singleton();
/**
* 构造器私有化,只有类内才可以调用
*/
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
**[双重检验懒汉式,防止指令重排序,防止反射破坏]**
/**
* @description: 双重检查加synchronized关键字保证线程安全,并且实例代码只执行一次。
* 优点:做到了线程安全,延迟加载。效率高。volatile避免指令重排序,指令重排序的问题以后放在jvm学习部分记录
* 可以参考https://www.cnblogs.com/leefreeman/p/7356030.html
* @author: Liu Administrator
* @time: 2020/8/9 12:48
**/
public class SingletonLazy {
/**
* volatile保证singletonLazy在被初始化为实例时,内部不会有指令重排序,
* 多个线程能够正确处理变量
*/
private static volatile SingletonLazy singletonLazy;
private SingletonLazy() {
if(singletonLazy != null){
//解决反射破坏单例
throw new RuntimeException("非法创建对象!");
}
}
public static SingletonLazy getInstance() {
//检查实例,不存在才进入同步区,否则直接返回实例
if (null == singletonLazy) {
synchronized (SingletonLazy.class) {
//第二次检查,不存在则创建实例
if (null == singletonLazy){
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
/**
* 如果不在构造函数中加判断,在第二次创建对象跑出异常,单例就会被反射所破坏
* private SingletonLazy() {
* if(singletonLazy != null){
* //解决反射破坏单例
* throw new RuntimeException("非法创建对象!");
* }
* }
* 通过反射方式破坏了单例
* 《effective java》中说可以在进行第二次实例的时候抛出异常解决这个问题
*/
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
SingletonLazy singletonLazy = SingletonLazy.getInstance();
SingletonLazy singletonLazy2 = SingletonLazy.getInstance();
System.out.println(singletonLazy == singletonLazy2); //true
Constructor<SingletonLazy> constructor = SingletonLazy.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonLazy singletonLazyReflection = constructor.newInstance();
System.out.println(singletonLazy == singletonLazyReflection);//false 如果在进行第二次实例加上判断,则会抛出异常,防止反射破坏。
}
}
- [枚举实现单例]
/**
* @description
* 优点:避免线程安全,防止反序列化
* @author: Liu Administrator
* @time: 2020/8/9 13:07
**/
public enum SingletonEnum {
INSTANCE;
public SingletonEnum getInstance(){
return INSTANCE;
}
}
枚举类是JDK1.5才出现的,单元素的枚举类型已经成为实现Singleton的最佳方法。
总结:这三种实现方式我认为还是比较有代表性的,当然也可以用静态内部类来实现。
https://www.cnblogs.com/chiclee/p/9097772.html 枚举实现单例底层源码解释参考这篇博客