泛型最常用于集合当中,如set,Map,以及单个元素的勇气,例如ThreadLocal和AtomicReference,在所有的这些用法中,每个容器都有固定数量的泛型,Set有一个,Map有两个,但是有些情况我们希望有多个,例如数据库的行可以有任意数量的列,可以用参数的Class对象为key,传入的实例为V传入参数,类Class其实是被泛型化了,应该写为Class<?>。例如下面的代码,如果只是使用泛型,那么map中k和v的类型是固定的,这里使用Class<?>作为key,可以存储任意类型的对象。

    1. package item33;
    2. import java.util.HashMap;
    3. import java.util.Map;
    4. /**
    5. * @author: qujundong
    6. * @date: 2020/12/5 下午6:50
    7. * @description:
    8. */
    9. public class Favorities {
    10. private Map<Class<?>, Object> map = new HashMap<>();
    11. public <T> void putFavorite(Class<T> type, T instance){
    12. map.put(type, instance);
    13. }
    14. public <T> T getFavorite(Class<T> type){
    15. return type.cast(map.get(type));
    16. }
    17. public static void main(String[] args) {
    18. Favorities favorities = new Favorities();
    19. favorities.putFavorite(String.class, "123");
    20. favorities.putFavorite(Integer.class, 123);
    21. String sres = favorities.getFavorite(String.class);
    22. Integer ires = favorities.getFavorite(Integer.class);
    23. }
    24. }

    Favorities就是所说的类型安全的异构容器,所谓的类型安全是指当你请求一个String的时候,不会返回一个Integer类型的对象,所谓异构是指,map中所有的key类型都是不同的。

    Favorities有两个局限性(第一条没太懂)
    首先,恶意客户可以通过使用原始形式的Class对象,轻松破坏Favorites实例的类型安全。 但生成的客户端代码在编译时会生成未经检查的警告。 这与正常的集合实现(如HashSet和HashMap)没有什么不同。 通过使用原始类型HashSet(条目 26),可以轻松地将字符串放入HashSet <Integer>中。 也就是说,如果你愿意为此付出一点代价,就可以拥有运行时类型安全性。 确保Favorites永远不违反类型不变的方法是,使putFavorite方法检查该实例是否由type表示类型的实例,并且我们已经知道如何执行此操作。只需使用动态转换:

    1. // Achieving runtime type safety with a dynamic cast
    2. public <T> void putFavorite(Class<T> type, T instance) {
    3. favorites.put(type, type.cast(instance));
    4. }

    <br />
    Favorites类的第二个限制是它不能用于不可具体化的(non-reifiable)类型(条目 28)。 换句话说,你可以保存你最喜欢的StringString [],但不能保存List <String>。 如果你尝试保存你最喜欢的List <String>,程序将不能编译。 原因是无法获取List <String>的Class对象。 List <String> .class是语法错误,也是一件好事。 List <String>List <Integer>共享一个Class对象,即List.class。 如果“字面类型(type literals)”List <String> .classList <Integer> .class合法并返回相同的对象引用,那么它会对Favorites对象的内部造成严重破坏。 对于这种限制,没有完全令人满意的解决方法。
    总之,泛型API的通常用法(以集合API为例)限制了每个容器的固定数量的类型参数。 你可以通过将类型参数放在键上而不是容器上来解决此限制。 可以使用Class对象作为此类型安全异构容器的键。 以这种方式使用的Class对象称为类型令牌。 也可以使用自定义键类型。 例如,可以有一个表示数据库行(容器)的DatabaseRow类型和一个泛型类型Column <T>作为其键。