• 设计模式面试点汇总


    设计模式面试点汇总

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

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

    • 单例模式

    单例模式

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

    五种单例模式实现方式

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

    饿汉式

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

    /*饿汉式*/
    
    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> {
            INSTANCE;
    
            @Override
            public int compare(Comparable c1, Comparable c2) {
                return c1.compareTo(c2);
            }
    
            @Override
            public Comparator> 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  NavigableMap emptyNavigableMap() {
            return (NavigableMap) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
        }
    
        /**
         * @serial include(内部类)
         */
        private static class EmptyMap
            extends AbstractMap
            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 keySet()                     {return emptySet();}
            public Collection values()              {return emptySet();}
            public Set> 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(BiConsumersuper K, ? super V> action) {
                Objects.requireNonNull(action);
            }
    
            @Override
            public void replaceAll(BiFunctionsuper 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,
                    Functionsuper K, ? extends V> mappingFunction) {
                throw new UnsupportedOperationException();
            }
    
            @Override
            public V computeIfPresent(K key,
                    BiFunctionsuper K, ? super V, ? extends V> remappingFunction) {
                throw new UnsupportedOperationException();
            }
    
            @Override
            public V compute(K key,
                    BiFunctionsuper K, ? super V, ? extends V> remappingFunction) {
                throw new UnsupportedOperationException();
            }
    
            @Override
            public V merge(K key, V value,
                    BiFunctionsuper V, ? super V, ? extends V> remappingFunction) {
                throw new UnsupportedOperationException();
            }
    
            // Preserves singleton property
            private Object readResolve() {
                return EMPTY_MAP;
            }
        }
        
    }
    
    

    结束语

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

    附录

    参考资料:

    1. 黑马Java八股文面试题视频教程:基础篇-56-单例模式_方式1_饿汉式_哔哩哔哩_bilibili
  • 相关阅读:
    主要开源WebGIS介绍、自由及开源GIS软件、组件产品
    ping使用
    用Abp实现两步验证(Two-Factor Authentication,2FA)登录(三):免登录验证
    从React源码来学hooks是不是更香呢
    1. 带你玩转Java之Java基本概括
    g2o的hessian矩阵、b怎么存储
    变量名命名的艺术
    数据mock和node.js的安装与下载
    【Axure高保真原型】图片手电筒效果
    Redis 非关系型数据库学习(一) ---- Redis 的安装
  • 原文地址:https://www.cnblogs.com/qiuluoyuweiliang/p/16940332.html