设计模式面试点汇总

时间:2022-12-01 08:06:32

我们会在这里介绍我所涉及到的设计模式相关的面试点,本篇内容持续更新

我们会介绍下述设计模式的相关面试点:

  • 单例模式

单例模式

下面我们来介绍单例模式的相关面试点

五种单例模式实现方式

我们下面来介绍单例模式的五种实现方式

饿汉式

我们给出饿汉式构建单例模式的基本框架:

/*饿汉式*/

public class Singleton implements Serializable{
    
    // 首先我们需要拥有一个私有的构造方法(为了防止其他对象调用构造方法产生新对象)
    private Singleton(){
        
        // 这里我们需要做一个判断,如果已存在单例对象,且其他对象调用构造方法,直接报错(为了预防反射获得类然后新创对象)
        if( INSTANCE != null){
            throw new RuntimeException("单例对象不可重复创建");
        }
        
        System.out.println("private Singleton");
        
    }
    
    // 饿汉式:在加载类时就直接创建单例对象,我们这里直接用static创建一个静态单例对象(随着类加载创建单例对象)
    private static final Singleton INSTANCE = new Singleton();
    
    // 由于单例对象是private,我们需要一个公共方法获得对象
    public static Singleton getInstance(){
        return INSTANCE;
    }
    
    // 其他方法
    public static void otherMethod(){
        System.out.println("otherMethod");
    }
    
    // readResolve方法,用于阻止反序列化获得新对象
    public Object readResolve(){
        return INSTANCE:
    }
    
    // 需要注意:Unsafe类破坏单例对象是无法阻止的!!!
    
}

枚举饿汉式

我们给出枚举饿汉式构建单例模式的基本框架:

/*枚举*/

enum Sex{
    MALE,FAMALE;
}

/*枚举饿汉式*/

public enum Singleton{
    
    // 单例对象
    INSTANCE;
    
    // getStance方法
    public static Singleton getInstance(){
        return INSTANCE;
    }
    
    // 枚举方法自带 反射 反序列化 生成对象的阻止方法
    
    // 枚举方法也不能阻止Unsafe类生成对象
    
}

懒汉式

我们给出懒汉式构建单例模式的基本框架:

/*懒汉式*/

public class Singleton{
    
    // 首先我们需要一个构造方法
    private Singleton(){
        System.out.println("private Singleton");
    }
    
    // 懒汉式:该对象创建之后不赋值,等到使用时在进行赋值
    private static Singleton INSTANCE = null;
    
    // getStance:我们在获得 STANCE 对象时再进行赋值并且反馈(注意:需要加锁处理多线程问题)
    public static synchronized Singleton getStance(){
        // 首先判断是否存在,若不存在创建并返回,若存在直接返回
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
    
    // 其他方法
    public static void otherMethod(){
        System.out.println("otherMethod");
    }
    
}

DCL懒汉式

我们给出DCL懒汉式构建单例模式的基本框架:

/*DCL懒汉式*/

// DCL:Double Check Lock 双重检查锁

public class Singleton{
    
    private Singleton(){
        System.out.println("private Singleton");
    }
    
    // 这里需要加上volatile,为了保证语句的有序性
    // 在getStance的赋值操作中INSTANCE = new Singleton()语句属于init初始化和static初始化
    // 两者之间可能出现优化状态,可能导致先进行ISNTANCE赋值,再进行init初始化
    // 但是在这个间隙线程2可能会通过INSTANCE判断,然后直接返回INSTACE,这时返回的并不是完整体的INSTANCE,可能出错
    private static volatile Singleton INSTANCE = null;
    
    // 我们将这里的锁进行更改,之前我们将getStance方法上锁,所有进程调用均需要锁处理,效率较慢
    // 实际上,我们只有第一次创建时,需要上锁处理,所以我们采用双重检查锁,判定只有未赋值时进行锁处理
    public static Singleton getStance(){
        // 首先判断是否赋值,若没赋值,进入锁赋值判断阶段
        if(INSTANCE == null){
            // 需要锁处理:这里就是并发部分
            synchronized(Singleton.class){
                // 需要二次判断,因为当线程1进行赋值操作时,线程2可能已经通过了第一次null判断,到这里还需要重新判断
				if(INSTANCE == null){
                    // 赋值操作
            		INSTANCE = new Singleton();
        		}
            }
        }
        
        
        return INSTANCE;
    }
    
    public static void otherMethod(){
        System.out.println("otherMethod");
    }
    
}

内部类懒汉式

我们给出内部类懒汉式构建单例模式的基本框架:

/*内部类懒汉式*/

// 属于最简洁的一种懒汉式创建方式

public class Singleton{
    
    // 构造方法
    private Singleton(){
        System.out.println("private Singleton");
    }
    
    // 内部类,用于存储单例对象(static内部类会随着类加载而加载,其单例性由JVM控制)
    private static class Holder{
        // 内部元素只有当类使用时被创建
        static Singleton INSTANCE = new Singleton();
    }
    
    // get方法调用内部类的INSTANCE
    public static Singleton getInstance(){
        return Holder.INSATNCE;
    }
    
    public static void otherMethod(){
        System.out.println("otherMethod");
    }
    
}

五种单例模式JDK体现

我们简单介绍一下JDK中使用单例模式的类:

/*饿汉式Runtime*/

public class Runtime {
    
    // 单例对象,直接创建
    private static Runtime currentRuntime = new Runtime();

    // 直接返回单例对象
    public static Runtime getRuntime() {
        return currentRuntime;
    }
    
}

/*枚举饿汉式NaturalOrderComparator*/

class Comparators {
    private Comparators() {
        throw new AssertionError("no instances");
    }

    /**
     * Compares {@link Comparable} objects in natural order.
     *
     * @see Comparable
     */
    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
        INSTANCE;

        @Override
        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
            return c1.compareTo(c2);
        }

        @Override
        public Comparator<Comparable<Object>> reversed() {
            return Comparator.reverseOrder();
        }
    }
}

/*DCL懒汉式System.Console*/

class System{
    
    // Console
    private static volatile Console cons = null;
    
    // Console双检索
    public static Console console() {
         if (cons == null) {
             synchronized (System.class) {
                 cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
             }
         }
         return cons;
     }
    
}

/*内部类懒汉式Collections*/

class Conllections{
    
    // emptyNavigableMap对象
    public static final <K,V> NavigableMap<K,V> emptyNavigableMap() {
        return (NavigableMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
    }

    /**
     * @serial include(内部类)
     */
    private static class EmptyMap<K,V>
        extends AbstractMap<K,V>
        implements Serializable
    {
        private static final long serialVersionUID = 6428348081105594320L;

        public int size()                          {return 0;}
        public boolean isEmpty()                   {return true;}
        public boolean containsKey(Object key)     {return false;}
        public boolean containsValue(Object value) {return false;}
        public V get(Object key)                   {return null;}
        public Set<K> keySet()                     {return emptySet();}
        public Collection<V> values()              {return emptySet();}
        public Set<Map.Entry<K,V>> entrySet()      {return emptySet();}

        public boolean equals(Object o) {
            return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
        }

        public int hashCode()                      {return 0;}

        // Override default methods in Map
        @Override
        @SuppressWarnings("unchecked")
        public V getOrDefault(Object k, V defaultValue) {
            return defaultValue;
        }

        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            Objects.requireNonNull(action);
        }

        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            Objects.requireNonNull(function);
        }

        @Override
        public V putIfAbsent(K key, V value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean remove(Object key, Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V replace(K key, V value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }

        // Preserves singleton property
        private Object readResolve() {
            return EMPTY_MAP;
        }
    }
    
}

结束语

目前关于设计模式的面试点就到这里,该篇文章会持续更新~

附录

参考资料:

  1. 黑马Java八股文面试题视频教程:基础篇-56-单例模式_方式1_饿汉式_哔哩哔哩_bilibili