在地图中强制使用泛型(与键/值泛型有关) [英] enforce generic types in maps (in relation to key/value generics)

查看:106
本文介绍了在地图中强制使用泛型(与键/值泛型有关)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我想拥有一些类似于缓存的类似于

  Map< Class< T extends SomeBaseClass> ,List< T>> cache = new ... 

当我尝试这样做时会引发编译错误。我不想让他们成为我正在与之合作的类的泛型,因为他们不属于那里。我也会有很多不同种类的T。但我也不想使用< ;?扩展SomeBaseClass> ,因为您没有编译时间保证进入的列表与映射到它的类是相同的类型...



我在这里有什么选择?这些术语在这里和谷歌被滥用,我似乎无法搜索它们: - (


解决方案


我也会有许多不同类型的T。


如果我正确理解你,你想要的是使用泛型以某种方式保证地图中的每个条目都将一个Class对象与该类的某个对象相关联。



泛型不能这样做,我们引用您的代码片段:

  Map< Class< T extends SomeBaseClass>,List< T>> cache = new ... 

看起来您希望 Map 中的每个条目都将 Class >对象与该类的一个实例,那么泛型不能帮助你,因为类型参数 T Map< Class< T>,T> 中,只有一种类型被替换到特定的 T 。这意味着一个专门的 Map< Class< Foo>,Foo> 版本的类将会有一个带有这个签名的方法:

  public Set< Map.Entry< Class< Foo>,Foo>>条目(); 

以及 Map.Entry< Class< Foo>,Foo>>从 Set iterator 方法中引用引用将具有以下方法:

  public Class< Foo>信息getKey(); 
public Foo getValue();

在这种情况下, Class ; ,它是 Foo 类的类对象。但是如果我们使用你的例子并使用 Class< T extends SomeBaseClass> 并不真的增加太多; getKey()会为你带来一些 Class 对象,它的 newInstance 方法产生的东西可以转换为 Foo ,但不能保证 getValue()会为您提供一个值相同的运行时类,甚至是可以转换为与 getKey()返回的类相同的类的类。



编辑:您可能想要类似这样的东西(未经测试,甚至没有尝试过编译它): b
$ b

  public class InstanceTable {
private final Map< Class,Object> table =
新的ConcurrentHashMap< Class,Object>();

public< T> void put(Class< T> klass,T value)
throws ClassCastException {
table.put(klass.cast(value));
}

public< T> T get(Class< T> klass){
return klass.cast(table.get(klass))
}

}

如果您静态命名您正在使用的类,则仅提供编译时类型安全 源代码,使用 Foo.class 语法:

  InstanceTable t =新的InstanceTable(); 
t.put(String.class,foo); //编译
t.put(Integer.class,bar)//不编译
String foo = t.get(String.class); //编译
整数1 =新的整数(1);
Integer bar = t.get(one.getClass()); //不会编译

但是请理解,除此之外,它不使用类型系统在编译时执行你想要的不变量 - 它仍然在运行时检查它(调用 Class.cast() )。


Let's say I want to have some kind of a cache that did something like

Map<Class<T extends SomeBaseClass>, List<T>> cache = new ...

When I try to do this is throws compile errors. I don't want to make them generics of the class I'm working with, because they don't belong there. I also will have many different kinds of T there. But I also don't want to use <? extends SomeBaseClass> because you don't have a compile time guarantee that the list going in is of the same type the class that maps to it is...

What are my options here? These terms are so overused here and on google I can't seem to search for them :-(

解决方案

I also will have many different kinds of T there.

If I understand you correctly, what you want is to use generics to somehow guarantee that each entry in the map will associate a Class object with some object of the class in question.

Generics cannot do that. Let's quote your code snippet:

Map<Class<T extends SomeBaseClass>, List<T>> cache = new ...

It looks like you want each entry in the Map to associate a Class object with an instance of that class. Well, generics can't do anything to help you there, because the type parameter T in Map<Class<T>,T> will have one and only one type substituted for it when the type is specialized to a particular T. This means a specialized Map<Class<Foo>,Foo> version of the class will have a method with this signature:

public Set<Map.Entry<Class<Foo>,Foo>> entries();

And the Map.Entry<Class<Foo>,Foo>> references you get out of the Set's iterator method would have these methods:

public Class<Foo> getKey();
public Foo getValue();

In this case, well, there is only one value for Class<Foo>, which is the class object for the Foo class. But if we go with your example and use Class<T extends SomeBaseClass> doesn't really add much; getKey() will get you some Class object whose newInstance method produces something that can be cast to Foo, but there is no guarantee that getValue() will get you a value of the same runtime class, or even of a class that can be cast to the same class as the one returned by getKey().

EDIT: You probably want something like this (untested, not even tried to compile it):

public class InstanceTable {
    private final Map<Class,Object> table =
        new ConcurrentHashMap<Class,Object>();

    public <T> void put(Class<T> klass, T value)
        throws ClassCastException {
        table.put(klass.cast(value));
    }

    public <T> T get(Class<T> klass) {
        return klass.cast(table.get(klass))
    }

}

This offers compile-time type-safety only in the case where you statically name the classes you're using in the source code, using the Foo.class syntax:

InstanceTable t = new InstanceTable();
t.put(String.class, "foo");          // compiles
t.put(Integer.class, "bar")          // doesn't compile
String foo = t.get(String.class);    // compiles
Integer one = new Integer(1);
Integer bar = t.get(one.getClass()); // doesn't compile

But understand that beyond this, it isn't using the type system to enforce the invariant you want at compilation time —it's still checking it at runtime (the calls to Class.cast()).

这篇关于在地图中强制使用泛型(与键/值泛型有关)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆