内容简介:scala雾中风景(28): private?public?
记录前些天遇到的一个问题,scala里 protected
或 private
修饰的方法可能在编译为class时变成了 public
,这已经不是第一次遇到,最早遇到是在写一个 java 子类时要覆盖一些父类方法,父类是scala写的一个trait,里面的方法修饰为 protected
,当时IDE提示我override的方法必须声明为 public
感到奇怪反编译了一下父trait果然被声明为了 public
。
而这次遇到的稍有不同,跟继承没有关系,用下面的demo举例:
➜ cat A.scala class A { private[this] def foo() = { List(1,2,3).map(i => bar(i)) } private[this] def bar(i:Int):String = { "str:" + i } }
当我们编译上面类之后,里面的 foo
和 bar
方法的修饰符最终在class里会有所不同,反编译后可看到 bar
修饰符变成了 public
:
➜ cfr-decompiler A ... public class A { private List<String> foo() { return (List)List..MODULE$.apply((Seq)Predef..MODULE$.wrapIntArray(new int[]{1, 2, 3})).map((Function1)new scala.Serializable(this){ public static final long serialVersionUID = 0; private final /* synthetic */ A $outer; public final String apply(int i) { return this.$outer.A$$bar(i); } }, List..MODULE$.canBuildFrom()); } public String A$$bar(int i) { return new StringBuilder().append((Object)"str:").append((Object)BoxesRunTime.boxToInteger((int)i)).toString(); } }
终归scala在jvm上要做一些妥协,按上面的实现, foo
里面以闭包的方式使用 bar
的时候,如果保持scala private[this]
的控制粒度,底层的匿名类其实已经无法访问 bar
了。所以scala在编译器的explicitouter环节做了一些向现实妥协的事情
➜ scalac -Xshow-phases phase name id description ---------- -- ----------- parser 1 parse source into ASTs, perform simple desugaring namer 2 resolve names, attach symbols to named trees packageobjects 3 load package objects typer 4 the meat and potatoes: type the trees patmat 5 translate match expressions superaccessors 6 add super accessors in traits and nested classes extmethods 7 add extension methods for inline classes pickler 8 serialize symbol tables refchecks 9 reference/override checking, translate nested objects uncurry 10 uncurry, translate function values to anonymous classes tailcalls 11 replace tail calls by jumps specialize 12 @specialized-driven class and method specialization explicitouter 13 this refs to outer pointers erasure 14 erase types, add interfaces for traits posterasure 15 clean up erased inline classes lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs lambdalift 17 move nested functions to top level constructors 18 move field definitions into constructors flatten 19 eliminate inner classes mixin 20 mixin composition cleanup 21 platform-specific cleanups, generate reflective calls delambdafy 22 remove lambdas icode 23 generate portable intermediate code jvm 24 generate JVM bytecode terminal 25 the last phase during a compilation run
在这个阶段,当编译器发现一些 private
的方法会被内部类访问的话,就删除这些 private
修饰符:
➜ scalac -Xprint:explicitouter A.scala [[syntax trees at end of explicitouter]] // A.scala package <empty> { class A extends Object { def <init>(): A = { A.super.<init>(); () }; private[this] def foo(): List[String] = immutable.this.List.apply[Int](scala.this.Predef.wrapIntArray(Array[Int]{1, 2, 3})).map[String, List[String]]({ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1[Int,String] with Serializable { def <init>($outer: A.this.type): <$anon: Int => String> = { $anonfun.super.<init>(); () }; final def apply(i: Int): String = $anonfun.this.$outer.bar(i); <synthetic> <paramaccessor> <artifact> private[this] val $outer: A.this.type = _; <synthetic> <stable> <artifact> def $outer(): A.this.type = $anonfun.this.$outer }; (new <$anon: Int => String>(A.this): Int => String) }, immutable.this.List.canBuildFrom[String]()); final def bar(i: Int): String = "str:".+(i) } }
上面 bar
的 private[this]
在这个阶段被删除,而scala不同于java,缺省就是 public
,最终在class里变成了 public
。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Go程序设计语言
艾伦 A. A. 多诺万 / 李道兵、高博、庞向才、金鑫鑫、林齐斌 / 机械工业出版社 / 2017-5 / 79
本书由《C程序设计语言》的作者Kernighan和谷歌公司Go团队主管Alan Donovan联袂撰写,是学习Go语言程序设计的指南。本书共13章,主要内容包括:Go的基础知识、基本结构、基本数据类型、复合数据类型、函数、方法、接口、goroutine、通道、共享变量的并发性、包、go工具、测试、反射等。 本书适合作为计算机相关专业的教材,也可供Go语言爱好者阅读。一起来看看 《Go程序设计语言》 这本书的介绍吧!