0

我有一个使用 Map 作为字段变量的类:

private Map<String, ?> posts;

在同一个类中,我有一个通用方法:

public <T> void log(T message) {
   if (isEnabled) {
        Date time = Calendar.getInstance().getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss:SS");
        posts.put(sdf.format(time.getTime()), message);
    }
}

但是,我在 posts.put 语句中收到编译器错误,说:

The method put(String, capture#2-of ?) in the type Map<String,capture#2-of ?> is not 
applicable for the arguments (String, T)

我对通配符和通用方法有点陌生,所以我做错了什么?

4

2 回答 2

4

Map<String, ?>并不意味着您可以将任何内容放入该地图中。这意味着值类是未知的。但它可以是例如 Foo 或 Bar。而且 Foo 可能与任何类型都不兼容T,因此编译器会抱怨。改用Map<String, Object>或使您的T参数类级别,然后用它参数化您的地图:Map<String, T>

于 2013-09-23T08:48:20.103 回答
4

当您Map使用无界通配符类型声明您的时:

private Map<String, ?> posts;

你将无法将任何东西null放入其中。因为?是任何类型的替代品。基本上,您Map是所有实例化的超类型MapwithString作为键和任何类型的值。?可以是DateNumberCatTiger,任何东西。

假设您的地图是这样实例化的:

private Map<String, ?> posts = new HashMap<String, Date>();

并且您的方法中的类型参数被推断为String,那么您的put方法正在执行:

posts.put(String, String);

...因此尝试在需要Stringa 的地方添加类型Date。当然,这会在运行时失败。泛型类型通过为此发出编译器错误来避免这些问题。


您可以通过使您的类本身泛型来解决此问题,从而在方法和映射中使用相同的类型参数:

class YourClass<T> {
    private Map<String, T> posts;

    public void log(T message) {
        if (isEnabled) {
            Date time = Calendar.getInstance().getTime();
            SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss:SS");
            posts.put(sdf.format(time.getTime()), message);
        }
    }
}

同样如评论中所述,您应该避免使用timeas 键。由于Date#getTime()只有毫秒精度,因此您在单个毫秒内覆盖的时间间隔内放置的任何内容都将存储为相同的键,从而覆盖该键的旧值。

于 2013-09-23T08:49:19.197 回答