java类型安全的异构容器

     2022-03-19     456

关键词:

转载自:http://blog.csdn.net/sh_c1991/article/details/45965743

 

我们的想法是用key自身的class 类型作为key。因为Class 是参数化的类型,它可以确保我们使Context方法是类型安全的,而无需诉诸于一个未经检查的强制转换为T。这种形式的一个Class 对象称之为类型令牌(type token)。

 

[java] view plain copy
 
  1. public class Context {  
  2.    
  3.   private final Map<Class<?>, Object> values = new HashMap<>();  
  4.    
  5.   public <T> void put( Class<T> key, T value ) {  
  6.     values.put( key, value );  
  7.   }  
  8.    
  9.   public <T> T get( Class<T> key ) {  
  10.     return key.cast( values.get( key ) );  
  11.   }  
  12.    
  13.   [...]  
  14. }  


请注意在Context#get 的实现中是如何用一个有效的动态变量替换向下转型的。客户端可以这样使用这个context:

 

 

[java] view plain copy
 
  1. Context context = new Context();  
  2. Runnable runnable ...  
  3. context.put( Runnable.class, runnable );  
  4.    
  5. // several computation cycles later...      
  6. Executor executor = ...  
  7. context.put( Executor.class, executor );  
  8.    
  9. // even more computation cycles later...  
  10. Runnable value = context.get( Runnable.class );  
这次客户端的代码将可以正常工作,不再有类转换的问题,因为不可能通过一个不同的值类型来交换某个键值对。

Bloch指出这种模式有两个局限性。“首先,恶意的客户端可以通过以原生态形式(raw form)使用class对象轻松地破坏类型安全。”为了确保在运行时类型安全可以在Context#put中使用动态转换(dynamic cast)。

 

 

[java] view plain copy
 
  1. public <T> void put( Class<T> key, T value ) {  
  2.   values.put( key, key.cast( value ) );  
  3. }  


第二个局限在于它不能用在不可具体化(non-reifiable )的类型中

 

换句话说,你可以保存Runnable 或Runnable[],但是不能保存List<Runnable>

这是因为List<Runnable>没有特定class对象,所有的参数化类型指的是相同的List.class 对象。因此,Bloch指出对于这种局限性没有满意的解决方案。

多条同类型容器条目

为了能够存储多条同类型容器条目,我们可以用自定义key改变Context 类。这种key必须提供我们类型安全所需的类型信息,以及区分不同的值对象(value objects)的标识。一个以String 实例为标识的、幼稚的key实现可能是这样的:

 

[java] view plain copy
 
  1. public class Key<T> {  
  2.    
  3.   final String identifier;  
  4.   final Class<T> type;  
  5.    
  6.   public Key( String identifier, Class<T> type ) {  
  7.     this.identifier = identifier;  
  8.     this.type = type;  
  9.   }  
  10. }  

我们再次使用参数化的Class作为类型信息的钩子,调整后的Context将使用参数化的Key而不是Class

 

 

[java] view plain copy
 
  1. public class Context {  
  2.    
  3.   private final Map<Key<?>, Object> values = new HashMap<>();  
  4.    
  5.   public <T> void put( Key<T> key, T value ) {  
  6.     values.put( key, value );  
  7.   }  
  8.    
  9.   public <T> T get( Key<T> key ) {  
  10.     return key.type.cast( values.get( key ) );  
  11.   }  
  12.    
  13.   [...]  
  14. }  


客户端将这样使用这个版本的Context

 

 

[java] view plain copy
 
  1. Context context = new Context();  
  2.    
  3. Runnable runnable1 = ...  
  4. Key<Runnable> key1 = new Key<>( "id1", Runnable.class );  
  5. context.put( key1, runnable1 );  
  6.    
  7. Runnable runnable2 = ...  
  8. Key<Runnable> key2 = new Key<>( "id2", Runnable.class );  
  9. context.put( key2, runnable2 );  
  10.    
  11. // several computation cycles later...  
  12. Runnable actual = context.get( key1 );  
  13.    
  14. assertThat( actual ).isSameAs( runnable1 );  

虽然这个代码片段可用,但仍有缺陷。在Context#get中,Key被用作查询参数。用相同的identifier和class初始化两个不同的Key的实例,一个用于put,另一个用于get,最后get操作将返回null 。这不是我们想要的……

[java] view plain copy
 
  1. Context context = new Context();  
  2.    
  3. Runnable runnable1 = ...  
  4. Key<Runnable> key1 = new Key<>( "same-id", Runnable.class );  
  5. Key<Runnable> key2 = new Key<>( "same-id", Runnable.class );  
  6. context.put( key1, runnable1 );//一个用于put  
  7.    
  8. context.get(key2); //另一个用于get --> return null;  


幸运的是,为Key设计合适的equals 和hashCode 可以轻松解决这个问题,进而使HashMap 查找按预期工作。最后,你可以为创建key提供一个工厂方法以简化其创建过程(与static import一起使用时有用):

[java] view plain copy
 
  1. public static  Key key( String identifier, Class type ) {  
  2.   return new Key( identifier, type );  
  3. }  











本周小贴士#144:关联容器中的异构查找(代码片段)

...器中查找元素需要等效键。通常,容器要求键是特定类型的,这会导致调用处的效率低下,需要在接近等效的类型(如std::string和absl::string_view)之间进行转换。为了避免这种不 查看详情

本周小贴士#144:关联容器中的异构查找(代码片段)

...器中查找元素需要等效键。通常,容器要求键是特定类型的,这会导致调用处的效率低下,需要在接近等效的类型(如std::string和absl::string_view)之间进行转换。为了避免这种不 查看详情

模型数据库中的异构类型

】模型数据库中的异构类型【英文标题】:ModelHeterogeneousTypeinDatabase【发布时间】:2009-02-0313:53:39【问题描述】:我正在尝试找出在我的系统中为一组“类”建模的最佳方法。请注意,我不是在谈论OO类,而是响应类(在调查中... 查看详情

swift中的异构集合文字

】swift中的异构集合文字【英文标题】:Heterogeneouscollectionliteralinswift【发布时间】:2018-10-1821:26:07【问题描述】:我正在尝试按如下方式读取嵌套数组,但出现错误。varinputArray=[1,[4,3],6,[5,[1,0]]]funcnestedArray(inputArray:[Any])错误:异... 查看详情

深度学习的异构加速技术:螺狮壳里做道场

...云、高速视觉感知等方向的构架设计和优化。“深度学习的异构加速技术”系列共有三篇文章,主要在技术层面,对学术界和工业界异构加速的构架演进进行分析。一、综述在“深度学习的异构加速技术(一)”一文所述的AI加... 查看详情

朴素贝叶斯:观察变量的异构 CPD

】朴素贝叶斯:观察变量的异构CPD【英文标题】:NaiveBayes:HeterogeneousCPDsforobservationvariables【发布时间】:2015-04-2208:27:14【问题描述】:我正在使用一个朴素贝叶斯模型进行二元分类,并结合使用离散变量和连续变量。我的问题是... 查看详情

云边端一体化的异构ai计算

...主要介绍阿里云AI异构计算编译框架HALO以及面向深度学习的异构硬件统一接口规范ODLA,通过具体的实例说明如何利用异构编译和硬件架构抽象实现上层应用在异构计算资源上的平滑迁移。后半部分介绍ODLA.CV(多媒体Pi 查看详情

NSArrayControllers 和 Core Data 对象的异构数组

】NSArrayControllers和CoreData对象的异构数组【英文标题】:NSArrayControllersandheterogeneousarraysofCoreDataobjects【发布时间】:2011-06-2014:39:22【问题描述】:我正在尝试创建一个MacOSCoreData应用程序,该应用程序具有一组父对象(称为级别)... 查看详情

深度学习的异构加速技术:ai需要一个多大的“心脏”?

...云、高速视觉感知等方向的构架设计和优化。“深度学习的异构加速技术”系列共有三篇文章,主要在技术层面,对学术界和工业界异构加速的构架演进进行分析。一、概述:通用=低效作为通用处理器,CPU(CentralProcessingU 查看详情

如何对可变参数模板函数的异构参数包进行通用计算?

】如何对可变参数模板函数的异构参数包进行通用计算?【英文标题】:Howtomakegenericcomputationsoverheterogeneousargumentpacksofavariadictemplatefunction?【发布时间】:2012-12-2500:47:21【问题描述】:前提:在尝试了一些可变参数模板之后,我... 查看详情

如何处理存储库模式中的异构数据源?

】如何处理存储库模式中的异构数据源?【英文标题】:Howtodealwithheterogeneousdatasourcesinrepositorypattern?【发布时间】:2022-01-2109:51:58【问题描述】:假设您想实现一个存储库模式来处理应用程序的数据。映像您有两个数据源:本地... 查看详情

为什么说datax是目前最好的异构数据源数据交换工具(代码片段)

本文收录于JavaStarter,里面有我完整的Java系列文章,学习或面试都可以看看(一)什么是Datax以前我做过一个项目,其中有个需求就是每天定时把sqlserver中的数据同步到Mysql中,当时写了一段Java的代码来实... 查看详情

如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView

】如何使用基于字段值选择的异构委托制作QtQuickTableView/TreeView【英文标题】:howtomakeQtQuickTableView/TreeViewwithheterogeneousdelegatechosenbasedonfieldvalue【发布时间】:2020-04-0814:51:30【问题描述】:如何根据另一个单元格的值选择单元格委... 查看详情

C++如何创建异构容器

...value)的形式存储一系列数据点,其中的值可以采用不同的类型。我正在尝试为每个数据点使用一个类模板。然后对于我看到的每个数据点,我想创建一个新对象并将其推回向量中。对于每种新类型,我需要先从模板创建一个新类... 查看详情

java泛型和类型安全的容器

示例:1publicclassApple{2privatestaticlongcounter;3privatefinallongid=counter++;45publiclongid(){6returnid;7}8}1publicclassOrange{23}1publicclassApplesAndOrangesWithoutGenerics{2@SuppressWarnings({"rawty 查看详情

基于ga遗传算法的异构网络垂直切换优化算法的matlab仿真

目录一、理论基础二、案例背景1.问题描述2.思路流程三、MATLAB核心代码 查看详情

华为云ugo:醒醒!你的异构数据库迁移难题有救了

摘要:华为云推出的数据库和应用迁移UGO,正是一款专注于异构数据库结构迁移和应用SQL转换的专业云服务。数字化时代下,上云已成为企业管理者的基本共识,随着技术日新月异,上云也变得轻松简单起来,但异构数据库迁移... 查看详情

您如何定义具有异构值类型的 QHash?

】您如何定义具有异构值类型的QHash?【英文标题】:HowdoyoudefineaQHashwithheterogeneousvaluetypes?【发布时间】:2014-08-1900:17:34【问题描述】:我需要有一个QHash容器,它接受quint8键但将异构类型作为值,所有这些都是Qt容器或类。例如... 查看详情