有时使用import
语句来访问对象的多个元素会更方便,更清晰。
例如,代码
x.y.z.a = 1
x.y.z.b = 2
x.y.z.c = 3
可以写成
{
import x.y.z._
a = 1
b = 2
c = 3
}
显然,当名字更长时,它会更有用。
是否所有工作都是在编译时完成的,还是以某种方式在运行时执行import语句?使用这种风格是否有任何成本,效率或其他方面的成本?
答案 0 :(得分:5)
您可以使用javap
查看自己。从这样的事情开始:
package x.y {
object z {
var a = "abc"
var b = "def"
var c = "ghi"
}
}
object Test {
def withImport: Unit = {
import x.y.z._
a = "zyx"
b = "wvu"
c = "rst"
}
def withoutImport: Unit = {
x.y.z.a = "zyx"
x.y.z.b = "wvu"
x.y.z.c = "rst"
}
}
使用scalac Test.scala
然后javap -c Test\$
:
public void withImport();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
3: ldc #20 // String zyx
5: invokevirtual #24 // Method x/y/z$.a_$eq:(Ljava/lang/String;)V
8: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
11: ldc #26 // String wvu
13: invokevirtual #29 // Method x/y/z$.b_$eq:(Ljava/lang/String;)V
16: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
19: ldc #31 // String rst
21: invokevirtual #34 // Method x/y/z$.c_$eq:(Ljava/lang/String;)V
24: return
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 this LTest$;
LineNumberTable:
line 13: 0
line 14: 8
line 15: 16
public void withoutImport();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
3: ldc #20 // String zyx
5: invokevirtual #24 // Method x/y/z$.a_$eq:(Ljava/lang/String;)V
8: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
11: ldc #26 // String wvu
13: invokevirtual #29 // Method x/y/z$.b_$eq:(Ljava/lang/String;)V
16: getstatic #18 // Field x/y/z$.MODULE$:Lx/y/z$;
19: ldc #31 // String rst
21: invokevirtual #34 // Method x/y/z$.c_$eq:(Ljava/lang/String;)V
24: return
...
完全相同的字节码。
答案 1 :(得分:4)
是的,所有名称和含义都在编译时解决,import
不会影响其他任何内容。
当然,执行的内容仍然是
x.y.z.a = 1
x.y.z.b = 2
x.y.z.c = 3
因此您将获取x.y.z
3次(在此示例中)。如果z
是
package x.y
object z { ... }
这又是名称解析;但如果你有类似的东西
object x {
val y = ... // some type which has val z
}
每次调用2次方法调用并将z
置于局部变量中会表现得更好(但如果此代码运行得足够频繁,JIT可能会对此进行优化)。