必须分配什么编译时类型来接收java.util.Map的返回值<textattribute,?=“”>

时间:2016-09-07 14:11:24

标签: java generics kotlin

我想用另一种字体制作一种字体。这就是我想要做的事情:

val font : Font = this.label.getFont();
val attributes : Map<TextAttribute, Any> = font.getAttributes();
attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
this.label.setFont(font.deriveFont(attributes));

然而,Kotlin编译器在线上抱怨:

val attributes : Map<TextAttribute, Any> = font.getAttributes();

显示消息:

 Type mismatch: inferred type is 
(Mutable)Map<TextAttribute!, *>! but 
Map<TextAttribute, Any> was expected

根据我对Java中泛型的有限理解,我理解font.getAttributes()返回java.util.Map<TextAttribute, ?>;后一个类型参数意味着当你从这个地图中创建一个有界/封闭的泛型类型时,请指定第二个类型参数,扩展java.lang.Object

所以,当我第一次尝试使用以下行时:

val attributes : java.util.Map<TextAttribute, Object> = font.getAttributes();

Kotlin编译器说:

  

此类不应在Kotlin中使用。改为使用kotlin.collections.Map或kotlin.collections.MutableMap。

它还说:

 Type mismatch: inferred type is 
 (MutableMap<TextAttribute!, *>..kotlin.collections.Map<TextAttribute!, *>?) 
 but java.util.Map<TextAttribute, Object> was expected

我不知道!符号的含义和通配符星号符号的含义。这是什么意思?

2 个答案:

答案 0 :(得分:3)

第一个问题是getAttributes方法返回一个可以保存空值的映射,而Map<TextAttribute, Any>声明它的值不能为空。 第二个问题是Kotlin中的Map接口不允许突变。

要解决问题,请将代码更改为例如:

val attributes : Map<TextAttribute, *> = font.getAttributes();
val updatedAttributes = attributes.plus(TextAttribute.UNDERLINE to TextAttribute.UNDERLINE_ON)

或者更简洁:

val updatedAttributes = font.attributes.plus(TextAttribute.UNDERLINE to TextAttribute.UNDERLINE_ON)

最后,由于Kotlin有方便的扩展方法,整个字体修改可以变成:

label.font = label.font.run { 
    deriveFont(attributes.plus(TextAttribute.UNDERLINE to TextAttribute.UNDERLINE_ON)) 
}

答案 1 :(得分:1)

我在Kotlin文档中查找了Star Projections,并且从快速阅读中可以看出,这是Kotlin将方差引入泛型类型的方式,所以*中的星号out {1}}位置表示out Any?,因此我将代码更改为此代码并且有效:

val attributesMap : Map<TextAttribute, Any?> = font.getAttributes();
val attributes : MutableMap<TextAttribute, Any?> = 
      attributesMap as MutableMap<TextAttribute, Any?>;

还有我使用的编译时类型是只读接口kotlin.collections.Map<K, V>,因为我正在将项目放入其中。但这是我注意到的事情,并且一旦我摆脱了前一行中的投射错误就要照顾好。