Вы можете легко проверить это с помощью javap -v
.Если вы скомпилируете следующий код (используя String.format
вместо "%s".format
на данный момент) с 2.12:
class Example1 {
val strings = Seq("foo")
def formatResult = String.format("%s", strings: _*)
}
Вы получите это:
public java.lang.String formatResult();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
0: ldc #21 // String %s
2: aload_0
3: invokevirtual #23 // Method strings:()Lscala/collection/Seq;
6: getstatic #29 // Field scala/reflect/ClassTag$.MODULE$:Lscala/reflect/ClassTag$;
9: ldc #31 // class java/lang/String
11: invokevirtual #35 // Method scala/reflect/ClassTag$.apply:(Ljava/lang/Class;)Lscala/reflect/ClassTag;
14: invokeinterface #41, 2 // InterfaceMethod scala/collection/Seq.toArray:(Lscala/reflect/ClassTag;)Ljava/lang/Object;
19: checkcast #43 // class "[Ljava/lang/Object;"
22: invokestatic #47 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
25: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 26 0 this LExample1;
Так что да, этопреобразую strings
в массив.
Если вы используете "%s".format
, но вот так:
class Example2 {
val strings = Seq("foo")
def formatResult = "%s".format(strings: _*)
}
Вы не увидите преобразования:
public java.lang.String formatResult();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
0: new #21 // class scala/collection/immutable/StringOps
3: dup
4: getstatic #27 // Field scala/Predef$.MODULE$:Lscala/Predef$;
7: ldc #29 // String %s
9: invokevirtual #33 // Method scala/Predef$.augmentString:(Ljava/lang/String;)Ljava/lang/String;
12: invokespecial #37 // Method scala/collection/immutable/StringOps."<init>":(Ljava/lang/String;)V
15: aload_0
16: invokevirtual #39 // Method strings:()Lscala/collection/Seq;
19: invokevirtual #43 // Method scala/collection/immutable/StringOps.format:(Lscala/collection/Seq;)Ljava/lang/String;
22: areturn
LineNumberTable:
line 14: 0
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this LExample2;
Это потому, что компилятор Scalaкодировка varargs отличается от кодировки Java-компилятора (который, конечно, ничего не знает о Seq
в Scala).Вы можете заставить компилятор Scala генерировать Java-совместимые методы varargs с аннотацией @varargs
:
class Example3 {
def foo(xs: String*): Unit = ()
@annotation.varargs
def bar(xs: String*): Unit = ()
val strings = Seq("foo")
def fooResult = foo(strings: _*)
def barResult = bar(strings: _*)
}
Обратите внимание, что при этом генерируется обе кодировки, хотя bar(strings: _*)
все еще выигралне требует преобразования массива, поскольку компилятор Scala в этом случае выбирает метод в кодировке Scala.
Итак, подведем итог: вызов методов Java varargs из Scala с seq: _*
всегда будет включать toArray
вызовна Seq
, хотя этого не произойдет при вызове методов Scala varargs из Scala (независимо от того, помечены они или нет @varargs
для совместимости с Java).