了解过Scala的同学应该都知道,Scala中“取消”了许多关键字的使用,例如public,static等;但是这也为我们带来了一些困惑,本文将对其中的一个困惑进行解答:为什么说Scala中public的底层还是private?
- 类中的属性不用加范围限定符就表示为“public”
上面这段话,或许在学习Scala的过程中我们都会听过,例如下面这段代码:
object TestClass {
def main(args: Array[String]): Unit = {
val instance = new C_0
println(instance.name) // hello
}
}
class C_0() {
val name: String = "hello"
}
上面这段代码中,对于类C_0的属性name我们没有加任何限定符,但是在主程序中,通过创建的对象我们仍然可以通过.name的方式对对象的属性进行直接的访问,这样看起来与Java中的public限定的属性似乎是没有区别的。但事实果真如此吗?
- Scala对public的理解:
对上面那段代码的类C_0进行反编译,我们可以得到如下内容:
//decompiled from C_0.class
package com.PinkGranite.sparkCore;
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "\u0006\u0001\u00152A\u0001B\u0003\u0001\u0019!)1\u0003\u0001C\u0001)!9q\u0003\u0001b\u0001\n\u0003A\u0002B\u0002\u0013\u0001A\u0003%\u0011DA\u0002D?BR!AB\u0004\u0002\u0013M\u0004\u0018M]6D_J,'B\u0001\u0005\n\u0003-\u0001\u0016N\\6He\u0006t\u0017\u000e^3\u000b\u0003)\t1aY8n\u0007\u0001\u0019\"\u0001A\u0007\u0011\u00059\tR\"A\b\u000b\u0003A\tQa]2bY\u0006L!AE\b\u0003\r\u0005s\u0017PU3g\u0003\u0019a\u0014N\\5u}Q\tQ\u0003\u0005\u0002\u0017\u00015\tQ!\u0001\u0003oC6,W#A\r\u0011\u0005i\tcBA\u000e !\tar\"D\u0001\u001e\u0015\tq2\"\u0001\u0004=e>|GOP\u0005\u0003A=\ta\u0001\u0015:fI\u00164\u0017B\u0001\u0012$\u0005\u0019\u0019FO]5oO*\u0011\u0001eD\u0001\u0006]\u0006lW\r\t"
)
public class C_0 {
private final String name = "hello";
public String name() {
return this.name;
}
}
从这里我们就可以看出一些端倪了,事实上,name属性仍然是private类型,但是同时还增加了一个name()方法,该方法实现的功能类似于get方法(也就是传回name属性的值),而我们又知道,在Scala中,如果方法没有参数可以直接省略括号,这样的话就变成了instance.name
,表现出了该属性为public的错觉!
- 进一步探究Scala中对private属性的解读:
请看下面这一段代码:
class User_(age: Int) {
private var myAge: Int = age
}
对它进行反编译,得到如下结果:
//decompiled from User_.class
package com.PinkGranite.sparkCore;
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "\u0006\u0001!2AAB\u0004\u0001\u001d!AQ\u0003\u0001B\u0001B\u0003%a\u0003C\u0003\u001a\u0001\u0011\u0005!\u0004C\u0004\u001f\u0001\u0001\u0007I\u0011B\u0010\t\u000f\u0001\u0002\u0001\u0019!C\u0005C!1q\u0005\u0001Q!\nY\u0011Q!V:fe~S!\u0001C\u0005\u0002\u0013M\u0004\u0018M]6D_J,'B\u0001\u0006\f\u0003-\u0001\u0016N\\6He\u0006t\u0017\u000e^3\u000b\u00031\t1aY8n\u0007\u0001\u0019\"\u0001A\b\u0011\u0005A\u0019R\"A\t\u000b\u0003I\tQa]2bY\u0006L!\u0001F\t\u0003\r\u0005s\u0017PU3g\u0003\r\tw-\u001a\t\u0003!]I!\u0001G\t\u0003\u0007%sG/\u0001\u0004=S:LGO\u0010\u000b\u00037u\u0001\"\u0001\b\u0001\u000e\u0003\u001dAQ!\u0006\u0002A\u0002Y\tQ!\\=BO\u0016,\u0012AF\u0001\n[f\fu-Z0%KF$\"AI\u0013\u0011\u0005A\u0019\u0013B\u0001\u0013\u0012\u0005\u0011)f.\u001b;\t\u000f\u0019\"\u0011\u0011!a\u0001-\u0005\u0019\u0001\u0010J\u0019\u0002\r5L\u0018iZ3!\u0001"
)
public class User_ {
private int myAge;
private int myAge() {
return this.myAge;
}
private void myAge_$eq(final int x$1) {
this.myAge = x$1;
}
public User_(final int age) {
this.myAge = age;
}
}
可以看到,属性的类型仍然为private类型,但是对应的get类方法myage()
的限定符同样变为了private,也就是我们不能直接对其进行引用,差别就发生在这里了!!