《剑指offer》各编程题Java版分析 -- 面试语言的基础支持

212 阅读2分钟

面试题1 -- 赋值运算符函数

题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。

自定义了一种字符串类,实现字符串的拷贝。其中关键点在于涉及到C++的内存回收与申请的顺序问题,Java由于内存回收通过JVM自动处理,不会有相关问题,此题忽略。

面试题2 -- 实现Singleton模式

题目:设计一个类,我们只能生成该类的一个实例。

单例模式实现代码少,是面试过程中常见的考察设计模式功底的题目。

不好的解法一:只适用于单线程环境

public class Singleton1 {

    private Singleton1(){}

    private static Singleton1 instance = null;

    /**
     * 线程不安全
     */
    public static Singleton1 getInstance() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }

}

不好的解法二:虽然在多线程环境中能工作,但效率不高

在Java的实现中,需要将instance增加volatile修饰,防止在 instance = new Singleton3() 这行的执行过程中new=的执行顺序被JMM优化打乱。

public class Singleton2 {
    
    private Singleton2() { }
    
    private static volatile Singleton2 instance = null;

    /**
     * 低效率
     */
    public static Singleton2 getInstance() {
        synchronized (Singleton2.class) {
            if (instance == null) {
                instance = new Singleton2();
            }
            return instance;
        }
    }
}

可行的解法:加同步锁前后两次判断实例是否已存在

此方法即Double-Check-Lock,与书中不同的是,在Java的实现中,需要将instance增加volatile修饰,防止在 instance = new Singleton3() 这行的执行过程中new=的执行顺序被JMM优化打乱。

public class Singleton3 {
    
    private Singleton3(){}
    
    private static volatile Singleton3 instance = null;

    /**
     * Double check lock
     */
    public static Singleton3 getInstance() {
        if (instance == null) {
            synchronized (Singleton3.class) {
                if (instance == null) {
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

强烈推荐的解法一:利用静态构造函数

即饿汉模式。

public class Singleton4 {
    
    private Singleton4(){}
    
    private static Singleton4 instance = new Singleton4();

    public static Singleton4 getInstance() {
        return instance;
    }
}

强烈推荐的解法二:实现按需创建实例

也是Java版最推荐的懒汉模式单例模式的实现方式,通过JVM类加载的内置同步性保证线程安全,只有在调用 getInstance 方法的时候才会加载Nested内部类,实现懒加载。

public class Singleton5 {
    
    private Singleton5(){}

    private static Singleton5 getInstance() {
        return Nested.instance;
    }

    private static class Nested {
        Nested() { }
        private static Singleton5 instance = new Singleton5();
    }
}