第一个代码段(简化):
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation")
}
test()
fun test() = println("test function")
test()
}
从字节码反编译到Java如下:
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
<undefinedtype> test = new Object() {
public final void invoke() {
String var1 = "test invocation";
System.out.println(var1);
}
};
((<undefinedtype>)test).invoke();
<undefinedtype> test$ = null.INSTANCE; // <---
test$.invoke(); // <---
}
我们不要过早下结论,让我们颠倒声明的顺序:
fun main(args: Array<String>) {
fun test() = println("test function")
test()
val test = object {
operator fun invoke() = println("test invocation")
}
test()
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
<undefinedtype> test$ = null.INSTANCE; // <---
test$.invoke();
Object var10000 = new Object() {
public final void invoke() {
String var1 = "test invocation";
System.out.println(var1);
}
};
test$.invoke(); // <---
}
invoke
当它们都在同一个作用域(类作用域、函数作用域)中声明时。然后我们显式地调用
援引
运算符而不是
()
语法:
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation")
}
fun test() = println("test function")
test.invoke() // calls object's invoke function
test() // calls local function
}
如果你想调用对象的
函数,用
x.invoke()
语法。如果要调用函数,请使用
语法。
另一件事是,当您在内部作用域中定义对象/函数/类,而在外部作用域中已经定义了一个同名的对象/函数/类时,就会发生名称阴影。因此在你的例子中:
fun test() = println("test function")
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation")
}
test() // Prints "test invocation"
}
局部变量
test
阴影函数
测试
在类范围中定义。如果我们只声明同一事物两次,一次在外部范围内,然后在内部范围内,就可以更好地看到这一点:
val test = object {
operator fun invoke() = println("test invocation 1")
}
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation 2")
}
test() // Prints "test invocation 2"
}
在这里,如果它是函数阴影或属性,则没有什么不同。如果外部作用域不是类作用域,我不知道如何访问外部作用域。但是,如果所有这些都发生在一个类中,那么很简单:
class SomeClass {
fun test() = println("test function 1")
fun main(args: Array<String>) {
val test = object {
operator fun invoke() = println("test invocation 2")
}
test() // Prints "test invocation 2"
this@SomeClass.test() // Prints "test invocation 1"
}
}
类声明的问题,如以下(简化示例)所示:
class test {} // Does not compile
fun test() = println("test function")
就是不能区分函数调用和对象构造。与具有函数的对象一样
()
或
invoke()
test.contruct()
),以上是允许的,但不是。
最后,伴随的问题是:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
}
fun main(args: Array<String>) {
test() // Prints: "test constructor"
}
你要记住这点
companion object
SomeClass.propertyInCompanion
事实上你打电话来了
SomeClass.Companion.propertyInCompanion
. 在这里,如果有冲突,外部类总是获胜。如果你需要打电话
Companion
的
援引
函数,则必须显式指定它:
fun main(args: Array<String>) {
test() // Prints: "test constructor"
test.Companion() // Prints: "test companion invocation"
}
最后两个代码段是上述所有代码(名称阴影、外部类>伴随)和局部变量阴影的组合:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
}
fun main(args: Array<String>) {
test() // class wins with companion, no local variable introducted
val test = object { // local variable test shadows outer scope "test"
operator fun invoke() = println("test invocation")
}
test() // calls local variable invoke function
fun test() = println("test function") // local function shadows local variable
test() // calls local function
}
第二个代码段:
class test {
constructor() {
println("test constructor")
}
companion object {
operator fun invoke() = println("test companion invocation")
}
operator fun invoke() = println("test invocation overload")
}
fun main(args: Array<String>) {
val test = test() // class wins with companion. Also local variable shadows outer scope.
val test1 = test() // calls invoke function of local variable
}
希望这能回答你的问题。