Scala:seqAsJavaList的一个奇怪的行为

时间:2014-09-02 05:22:11

标签: scala

给出以下代码:

import collection.JavaConversions._

def j(x: java.util.List[java.lang.Integer]): Unit = 
    // the function body here can be any valid code
    println (x)

val a = List(1)

我在调用时遇到类型不匹配错误:

j (seqAsJavaList(a))

以下是REPL的错误

 <console>:13: error: type mismatch;
 found   : List[Int]
 required: Seq[Integer]
          f (seqAsJavaList(a))
                           ^

但是,我可以在没有错误的情况下调用它:

 j(seqAsJavaList(List(1)))

我使用2.11.2。

有人可以向我解释为什么seqAsJavaList的行为有所不同吗?感谢。


为我原来的问题添加更多背景/说明:

我要问的是&#34;为什么seqAsJavaList在预定义变量a上操作时的行为与在原位值List(1)上的行为不同相同的类型?&#34;此外,seqAsJavaList(a)seqAsJavaList (List(1))会返回完全相同的签名java.util.List[Int]。使用替换模型,可以期望j (seqAsJavaList(a))j (seqAsJavaList (List(1)) )都成功。然而,只有后者才有效。当seqAsJavaList(a)seqAsJavaList (List(1))都是java.util.List[Int]时,为什么一个用法处理Int很好而另一个用不处理?


另一个注意事项:

我刚试过collection.JavaConverters,结果并不理想,但至少是一致的:

// The definitions of j & a are the same as above. I repeat them here to save some page scrolling.
// BTW, instead of f, I use j to indicate it is supposed to be a Java static method.
// I mock it in Scala so that this can be easily run in REPL.
def j ( ls: java.util.List [java.lang.Integer] ): Unit = println (ls)
val a = List( 1 )
// new code here
import collection.JavaConverters._
// Both require the explicit casting to work
j ( a.map (i => i: java.lang.Integer).asJava )
j ( List(1).map (i => i: java.lang.Integer).asJava )

// These fail with the same error.
j( a.asJava )
j( List(1).asJava )
// <console>:12: error: type mismatch;
// found   : java.util.List[Int]
// required: java.util.List[Integer]
//          j ( List(1).asJava )
//                      ^

1 个答案:

答案 0 :(得分:4)

此处的问题不在于List,而在于Int类型。例如,这有效:

scala> j ( seqAsJavaList (a.map(x => x:Integer)) )
[1]

j期望参数类型为java.util.List [java.lang.Integer]。但是,您的seqAsJavaList的返回类型为java.util.List [Int]

上面的示例有效,因为现在seqAsJavaList将List [java.lang.Integer]并返回java.util.List[java.lang.Integer]。因此它有效。

或者你可以:

scala> implicit def toJavaIntegerList(ls:List[Int]):java.util.List[Integer] = seqAsJavaList(ls.map(x => x:Integer))

scala> j(List(1,2,3))
[1, 2, 3]

<小时/> 解释其原因:

j (seqAsJavaList(List(1)))

这相当于:

scala> val temp:List[Integer] = List(1)
temp: List[Integer] = List(1)

scala> j (seqAsJavaList(temp))
[1]

或更好:j (seqAsJavaList(List(1:Integer)))

类型推断在这里工作。有隐含的功能

implicit def int2Integer(x:Int):java.lang.Integer

Predef中定义。当您执行j(seqAsJavaList(List(1)))时,类型推断通过使用转换Int => java.lang.Integer的隐式函数来预测这可以合法地成功。它看到如果这个隐含用于List的所有元素,那么调用将合法地成功。因此,List(1)实际上构建为List[Integer]而不是List[Int]

通过检查确认

object Temp extends App{
        import collection.JavaConversions._

        def j(x: java.util.List[java.lang.Integer]): Unit =  println (x)
        j(seqAsJavaList(List(1)))
}

jatinpuri@jatin:~/Desktop$ scalac -Xprint:typer Temp.scala 
[[syntax trees at end of                     typer]] // Temp.scala
package <empty> {
  object Temp extends AnyRef with App {
    def <init>(): Temp.type = {
      Temp.super.<init>();
      ()
    };
    import scala.collection.JavaConversions._;
    def j(x: java.util.List[Integer]): Unit = scala.this.Predef.println(x);
    Temp.this.j(scala.collection.JavaConversions.seqAsJavaList[Integer](immutable.this.List.apply[Integer](scala.this.Predef.int2Integer(1))))
  }
}

注意(immutable.this.List.apply[Integer](scala.this.Predef.int2Integer(1)))。因此,List(1)实际上构建为List[Integer]而不是List[Int]

这在原始情况下不起作用,因为在执行val a = List(1)时,a设置为List[Int]。将其更改为List[Integer]的唯一方法是将所有内容映射到Integer(因为scala lib中没有隐式可用的转换List[Int] => List[Integer]