在阅读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)
分享到:
相关推荐
java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包, java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包, java openJDK 源码, Hotspot, 未编译, 原始代码, 直接zip压缩包
主要是编译openjdk需要的包
openjdk源码1
OpenJdk源码包,
openjdk8源码,适合深入学习jdk源码的同学
openjdk 7u的源码,可以用来编译jvm(已编译成功),深入理解java虚拟机。由于资源上传限制,7u和6两个源码压缩为3个分卷,请下载3个分卷放在同一文件夹中再解压。自用资源,放心下载。
OPENJDK-7 windows编译之后版本
在openjdk开源源码站下载速度过慢,这里提供openjdk8u的完整可编译源码,供大家自己编译属于自己的jdk版本,已经阅读openjdk源码帮助学习。在openjdk开源源码站下载速度过慢,这里提供openjdk8u的完整可编译源码,供...
java jdk1.7源码包,用于centos7使用jdk1.7编译openjdk1.8的 1.7版本
openjdk-17源码(openjdk-17+35_src.zip)
openjdk hotspot源码,在研究JAVA虚拟机时,这个源码是必不可少的。
openjdk7的langtools源码,可以进行openjdk的编译调试
欢迎使用JDK! 有关构建说明,请参阅或以下文件之一: (html版本) (降价版) 有关OpenJDK社区和JDK的更多信息,请参见 。
在某种程度上,这个项目是在编译过程中在预先存在的类中注入新字段的概念证明。 在我的硕士论文的阐述过程中,它也使用了一个 javac 插件,在预先存在的类 AST 节点中注入新字段(变量声明)会在运行时崩溃 JVM。 ...
编译调试jvm, openjdk8源码, openjdk7, make3.81源码
OpenJDK源代码,便于程序员筒子们深入研究JDK运行机制
openjdk8 源码,openjdk8 源码,openjdk8 源码,openjdk8 源码
openjdk1.8 源码查看
openjdk jdk源码,在研究JAVA本地方法源码时,这个是必须的。
openjdk6 源代码,分开也上传一份,省得太大了。