(29):优先考虑类型安全的异构容器

泛型常用于以及一些单元素容器。但一般来说一个set只有一个类型参数,表示他的元素类型,一个Map有两个类型参数,表示键和值。

考虑这么一种情况,数据库中的字段都是不同类型,怎么将一条数据加入到容器中。我们需要一个容器能够容纳不同类型的值。

简单一想我们用Map<Object,Object>不就行了,但这样有个缺点,我们无法通过键来确定值得类型,也就是说我们取值的时候是无法获得值得类型的。还有一种想法我们是不是可以制定一个规范,让键是什么类型,值就是什么类型。但这样也有问题,我们无法确保用户可以严格按照这个规范来输入数据。

幸运的是,我们有一个方法可以轻松做到这一点。请看如下代码:

public class Favorites {  
    private Map<Class<?>, Object> favorites =   
            new HashMap<Class<?>, Object>();  
    public <T> void putFavorite(Class<T> type, T instance) {  
        if (type == null)  
            throw new NullPointerException("Type is null");  
        favorites.put(type, instance);  
    }  
    public <T> T getFavorite(Class<T> type) {  
        return type.cast(favorites.get(type));  
    }  
}  
  
// Demo: Typesafe heterogeneous container pattern - client  
public static void main(String[] args) {  
    Favorites f = new Favorites();  
    f.putFavorite(String.class, "Java");  
    f.putFavorite(Integer.class, 0xcafebale);  
    f.putFavorite(Class.class, Favorites.class);  
    String favoriteString = f.getFavorite(String.class);  
    int favoriteInteger = f.getFavorite(Integer.class);  
    Class<?> favoriteClass = f.getFavorite(Class.class);  
    System.out.printf("%s %x %s%n", favoriteString, favoriteInteger,  
                                    favoriteClass);  
}  
这个Favorites类允许客户端从任意多的其他类中获取最喜欢的实例,放入到容器中,最后也能正确的获取最喜欢的实例。这个例子,值得类型就是多种类型的。

将类的Class类作为键,并且使用Class<T> 能够识别 Class 是哪种类型的。类Class在Java 1.5后就被泛型化了,也就是说String.class属于Class<String>。这种传达类型的方法就叫做type token。通过这个我们首先了类型安全,也就是我们可以通过Class的类型来判断值的类型,从而返回正确的值类型。

那么异构是哪里来的呢?答案是无限制通配符的键Class<?>,在这里它仅代表是某种class,因此允许将不同类的class放入同一个Map,这就是异构的原因。因为它只是个键,所以不存在使用无限制通配符后就无妨把任何东西放到map中这个问题。

Favorites类有两种局限:一是恶意用户可以通过使用原生态形式的Class来破坏年Favorites实例的类型安全。比如利用原生态类型HashSet中添加String类型来破坏HashSet<Integer>.这种方式可以通知在putFavorite中进行类型检查来确保实例对象进行检查。

public <T> void putFavorite(Class<T> type, T instance) {  
    if (type == null)  
        throw new NullPointerException("Type is null");  
    favorites.put(type, type.cast(instance));  
}  
 第二个局限性在于它不能用在不可具体化的类型中。比如说可以存储喜爱的String,String[],但是不能存储List<String>。因为 List<String>.class是语法错误。因为在运行时他们的类型会被擦除,所在List<String>与List<Integer>实际上是共用一个Class。如果需要限制些可以传递给方法的类型,则可以使用有限制的通配符类型。



    


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值