特殊的Map实现IndentityHashMap

IndentityHashMap的特殊性在于它的键值比较使用”key1==key2”,而Map实现的常规约束的键值比较使用”key1.equals(key2)”。这样设计的主要目的是适用引用对象比较级别的应用场景。

简单示例

其中一个应用场景就是使用IndentityHashMap维护代理对象,可以为每个对象创建一个关联对象,例如为每个对象创建一个日志实例。

Map<Teacher, Logger> loggers = new IdentityHashMap<>();
		
Teacher t1 = new Teacher("小李");//重名的小李老师
Teacher t2 = new Teacher("小李");
		
loggers.put(t1, new Logger("info"));
loggers.put(t2, new Logger("debug"));
		
//******
loggers.get(t1).log("吃饭");//不同对象使用不同Logger对象
loggers.get(t2).log("睡觉");

Public class Logger {
	private String level;
		
	public Logger(String level) {
		this.level = level;
	}
	public void log(String msg) {
		System.out.println(level + ":" + msg);
	}
}
public class Teacher{
	private String name;
	public Teacher(String name) {
		this.name = name;
	}
	******
}

实际应用

维护代理对这种场景的实际应用可以在netty源码中找到,netty中定义了一个参数类型匹配器(TypeParameterMatcher),用来验证某个对象是否创建自某个类。

我们验证对象类型的普通方法可能是instanceof关键字或获取对象的Class对象,调用Class对象的isAssignableFrom方法,再或者直接调用目标ClassisInstance方法:

Teacher o1 = new Teacher();
System.out.println(o1 instanceof Teacher);
System.out.println(o1.getClass().isAssignableFrom(Teacher.class));
System.out.println(Teacher.class.isInstance(o1));
//输出 true,true,true

但是如果考虑到类加载器,不同的类加载器加载的Class会创建不同的Class对象,类似下面的样例:

FileSystemClassLoader cl = new FileSystemClassLoader("D:\\bin\\test");
Class<Teacher> tClass = (Class<Teacher>)cl.findClass("map.Teacher");
Teacher o1 = new Teacher();
System.out.println(o1 instanceof Teacher);
System.out.println(o1.getClass().isAssignableFrom(tClass));
System.out.println(tClass.isInstance(o1));
//输出true, false, false

FileSystemClassLoader是自定义的一个类加载器,上面的输出结果并不难理解,因为o1这个Teacher对象并不是创建自tClass这个类对象。

NettyInternalThreadLocalMap类中定义了一个IndentityHashMap类型的变量存储类与类型比较器的映射关系。

Map<Class<?>, TypeParameterMatcher> cache;
cache = new IdentityHashMap<Class<?>, TypeParameterMatcher>();

Netty中使用IndentityHashMap也并非那么有必要,因为Class类的equal方法继承自Object对象,默认使用的this==object等值比较,使用HashMap和使用IndentityHashMap效果一样。但是IndentityHashMap还有一个特定,就是对于基本操作,它的效率是恒定的(constant-time performance,因为其内部使用System.identityHashCode(Object)计算哈希值。

其他特点

IndentityHashMap对象被创建时可以指定maximum属性,空间不够的情况下会自动扩展,但扩展空间很影响效率,而最初指定的maximum过大可能会造成空间浪费,需要在实际应用中找到的合理的初始大小。

IndentityHashMap可以支持Null值的keyvalue。它也是非线程安全的,如果想在多线程中使用它,可以借助Collections 帮助类:Map m = Collections.synchronizedMap(new IdentityHashMap(...));

拓展思考

  1. 自定义类加载器
public class FileSystemClassLoader extends ClassLoader {
	private String rootDir;

	public FileSystemClassLoader(String rootDir) {
		this.rootDir = rootDir;
	}

	protected Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] classData = getClassData(name);//class文件流转为byte数组
		if (classData == null) {
			throw new ClassNotFoundException();
		} else {
			return defineClass(name, classData, 0, classData.length);
		}
	}

	private byte[] getClassData(String className) {
		String path = classNameToPath(className);
		try(InputStream ins = new FileInputStream(path)) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			int bufferSize = 4096;
			byte[] buffer = new byte[bufferSize];
			int bytesNumRead = 0;
			while ((bytesNumRead = ins.read(buffer)) != -1) {
				baos.write(buffer, 0, bytesNumRead);
			}
			return baos.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private String classNameToPath(String className) {
		return rootDir + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
	}
}

2.如何区分使用接口和泛型?

泛型的最大好处是让类实例可以处理未知类型的对象。一个对象被创建必定有它的职责,它的职责就是处理某些业务逻辑。对象履行自己的职责过程中可能需要其他对象的辅助,如果这些关联对象属于同一类型,可以抽象成接口类。

比如老师对象平时需要教导学生学习知识,同时也要向教导主任汇报工作,学生和主任都是他的关联对象,可以抽象Person接口,老师的关联人使用List<Person>定义。

如果老师类上定义了一个“审阅”方法,可以审阅试卷,也可以审阅日常作业,试卷和日常作业不能抽象同一类,可以借助泛型来定义。

public class Teacher {
	public <T> T comment(T context) {
		return context;
	}
}

 

参考资料:

https://www.cnblogs.com/kakaxisir/p/5723260.html   ClassLoader 学习笔记

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值