• OpenJDK源码研究笔记(十三):Javac编译过程中的上下文容器(Context)、单例(Singleton)和延迟创建(LazyCreation)3种模式


    在阅读Javac源码的过程中,发现一个上下文对象Context。

    这个对象用来确保一次编译过程中的用到的类都只有一个实例,即实现我们经常提到的“单例模式”。

    今天,特意对这个上下文容器进行解析,主要是讲解上下文容器、单例模式和延迟创建。

    通过对OpenJDK和Javac源码的一点点解析,希望自己能够搞懂JDK和Javac的实现。

    1.OpenJDK源码示例

    a.上下文容器

    public class com.sun.tools.javac.util.Context{
    
        //构造函数
    
        public Context() {
        }
    
    
        /**
         * 客户端创建这个类的实例,用作key。
         */
        public static class Key<T> {
            // 注意: 我们从Object继承身份相等性。we inherit identity equality from Object.
        }
    
        /**
         * 客户端注册这个工厂,实现实例的延迟创建。
         */
        public static interface Factory<T> {
            T make(Context c);
        };
        public <T> void put(Key<T> key, Factory<T> fac) {
            ft.put(key, fac); // cannot be duplicate if unique in ht
        }
        public <T> T get(Key<T> key) {
            Object o = ht.get(key);
            //如果通过key获取的是一个工厂类
            if (o instanceof Factory<?>) {
                Factory<?> fac = (Factory<?>) o;
                //根据工厂创建对象
                o = fac.make(this);
            }
    
            //类型转换
            return Context.<T> uncheckedCast(o);
        }
    
    }
    
    


    b.单例模式

    public class com.sun.tools.javac.util.Options{
    
    //如果上下文容器中存在,直接返回;否则,新创建一个对象,并且放到Context中。
    
    public static Options instance(Context context) {
            Options instance = context.get(optionsKey);
            if (instance == null){
                instance = new Options(context);
            }
            return instance;
        }
    
    }
    
    


    c.延迟创建

    public static final Context.Key<Log> logKey = new Context.Key<Log>();
    
     context.put(logKey, new Context.Factory<Log>();
    
     
    


    这个时候,put放进去的不是一个对象,而是一个工厂。

    当我们通过context.get(logKey)去获得对象的时候,先是获得了工厂对象,然后再根据工厂去创建相应的对象。

    2.代码示例

    a.上下文容器

    package sample.context;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Context {
    
        private Map<Key<?>, Object> map = new HashMap<Key<?>, Object>();
    
        public Context() {
        }
    
        /**
         * 客户端创建这个类的实例,用作key。
         */
        public static class Key<T> {
            // 注意: 我们从Object继承身份相等性。
        }
    
        /**
         * 客户端注册这个工厂,实现实例的延迟创建。
         */
        public static interface Factory<T> {
            T make(Context c);
        };
    
        public <T> void put(Key<T> key, Factory<T> fac) {
            map.put(key, fac);
        }
    
        public <T> void put(Key<T> key, T data) {
            map.put(key, data);
        }
    
        public <T> T get(Key<T> key) {
            Object o = map.get(key);
            // 如果通过key获取的是一个工厂类
            if (o instanceof Factory<?>) {
                Factory<?> fac = (Factory<?>) o;
                // 根据工厂创建对象
                o = fac.make(this);
                System.out.println("根据工厂延迟创建了一个对象,工厂类型:" + o.getClass());
            } else {
                if (o != null) {
                    System.out.println("直接获得了一个对象,对象类型:" + o.getClass());
                }
            }
    
            return (T) o;
        }
    
    }
    
    


    b.用户

    package sample.context;
    
    import sample.context.Context.Key;
    
    public class User {
    
        protected static final Key<User> userKey = new Key<User>();
    
        private String name;
    
        public User(Context context) {
            context.put(userKey, this);
        }
    
        public static User instanceOf(Context context) {
            User user = context.get(userKey);
            if (user == null) {
                user = new User(context);
            }
            return user;
    
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String toString() {
            return "User";
        }
    
    }
    
    


    c.博客

    package sample.context;
    
    import sample.context.Context.Key;
    
    public class Blog {
        protected static final Key<Blog> blogKey = new Key<Blog>();
    
        private String title;
    
        public Blog(Context context) {
            context.put(blogKey, this);
        }
    
        public static Blog instanceOf(Context context) {
            Blog blog = context.get(blogKey);
            if (blog == null) {
                return new Blog(context);
            }
            return blog;
    
        }
    
        public static void preRegister(Context context) {
            context.put(blogKey, new Context.Factory<Blog>() {
                public Blog make(Context c) {
                    return new Blog(c);
                }
            });
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String toString() {
            return "Blog";
        }
    
    }
    
    


    d.应用例子

    package sample.context;
    
    /**
     * OpenJDK源码研究笔记(十三):Javac编译过程中的上下文容器(Context)、单例(Singleton)和延迟创建(LazyCreation)3种模式
     *
     * @author LeiWen@FansUnion.cn
     *
     */
    public class ContextExample {
    
        public static void main(String[] args) {
            // 构造上下文容器
            Context context = new Context();
            // 预注册一个Blog工厂
            Blog.preRegister(context);
            // 获得一个User对象
            User user = User.instanceOf(context);
            user.setName("FansUnion");
    
            User user2 = User.instanceOf(context);
            //验证是否为单例
            if (user == user2) {
                System.out.println("user和user2是同一个对象,name:" + user2.getName());
            }
            // 获得一个Blog对象
            Blog blog = Blog.instanceOf(context);
    
        }
    
    }
    
    


    e.程序输出

    直接获得了一个对象,对象类型:class sample.context.User
    user和user2是同一个对象,name:FansUnion
    根据工厂延迟创建了一个对象,工厂类型:class sample.context.Blog

    相关阅读

    我的CSDN博客专栏  OpenJDK源码研究笔记

    OpenJDK源码研究过程中整理的学习笔记。 OpenJDK是GPL许可(GPL-licensed)的Java平台的开源实现。

    原文参见http://FansUnion.cn/articles/3099(小雷网-FansUnion.cn)

  • 相关阅读:
    L298 猴子进化过程
    L296 EST 科技英语翻译-美学取向 (上)
    L295 how to turn down a job but keep a good relationship with the hiring manager
    L293 给地球降温
    2019.3.16错过的计算题-应用统计学
    L291
    L290 英语中级班-3月上
    L275 Climate Change Is Having a Major Impact on Global Health
    L273 NCAA
    leetcode 87 Scramble String ----- java
  • 原文地址:https://www.cnblogs.com/qitian1/p/6463475.html
Copyright © 2020-2023  润新知