hangscer

Scala类与java类的关系

2017/02/11
1
2
3
4
5
class Counter{
private var value=0
def increment()={value+=1;this}
def current=value
}

以上scala书写的Counter类,对应的java类为:

1
2
3
class Person{
var age=0
}

这个简单的Person对应的java类为

1
2
3
4
5
6
7
8
9
public class Person{
private int age=0;
public int age(){
return this.age;
}
public void age_$eq(int x$1){
this.age=x$1;
}
}

可以看出scala类中的公用字段var age=0面向JVM生成的字节码中,生成私有字段,以及公有的settergetter方法(age()age_=(int))。换句话说,scala为每个字段都提供了gettersetter。对于Person而言,settergetter分别为ageage_=。(=翻译为$eq)。


重新定义gettersetter

统一访问原则:通过存储还是计算来实现的,从访问方式上无从获知。在Scala中,o.age的调用者不知道age是通过字段还是方法实现的。
将以上的Person类字节码反编译后得到java类如下:

privateAge是类的私有字段,依然会生成私有的setter和getter方法。


  • 字段是私有的,则setter和getter是私有的
  • 字段是val,则getter被生成。
  • 如果不需要任何getterseter,可以加以private[this]

有时候只要一个只读属性,有getter没有setter。如果属性的值在对象构建完成后不再改变,则可以使用val字段。

字节码反编译后得到:


总结一下,实现属性有四个选择:

  • var foo,Scala自动合成getter和setter方法
  • val foo,自动合成getter方法
  • 程序员自己定义foofoo_=方法
  • 程序员自己定义foo方法

何为Bean属性?
JavaBean规范把java属性定义为一对getFoo和setFoo方法。许多java工具都依赖这样的命名习惯。使用@BeanProperty

反编译后得到:

生成了两套setter和getter方法。


辅助构造器

  • 构造器名称为this
  • 每一个辅助构造器都必须以先前定义的辅助构造器或者主构造器调用开始

以上Person反编译得到:


主构造器

反编译得到:

val nameval age只生成公有的getter,但是本身字段仍是私有的。

主构造器会执行类定义中所有语句,例如:

上图中val str="haha"在主构造器中,依然会生成对应的字段以及getter方法。
反编译得到:

问题,当构造参数是普通方法参数时,不带valvar,这样的参数取决于它们在类中如何使用:

反编译字节码得到:

可以看出,构造器中没有var和val声明的参数,只是字节码中只是普通的参数而已,不是字段。


构造参数是普通函数参数时,但在构造体内被使用或者类的方法使用该变量时,该变量升级为字段,并辅以getter方法。(同val字段)。
反编译得到:

对于参数是否保存为字段,还是仅仅是被构造器访问到的普通参数。(是scala编译器的优化手段)

注:将主构造器私有,用private字段: