`
zhouchaofei2010
  • 浏览: 1085943 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

scala 构造顺序与java 的构造顺序的区别

阅读更多
有如下scala代码 
ConstructionOrder.scala
package quickanswer.chapter8

class Creature {
  val range: Int = 10
  val env: Array[Int] = new Array[Int](this.range)///calls the range() 方法而不是对字段的的直接引用  和java 的区别
}

class Ant extends Creature {
  override val range = 2
}

object ConstructionOrder extends App {
  val ant= new Ant
   println(ant.range);
  println(ant.env.length);

}
 
执行结果是
2
0
 
有如下java 代码 ConstructionOrder.scala
CreatureJava.java
package quickanswer.chapter8;

class CreatureJava {
     int range=10;
     int[] env = new int[range];

     public int getRange() {
        return range;
    }

}
class AntJava extends CreatureJava {

     int  range = 2;

    @Override
    public int getRange() {
        return range ;
    }

}
public class ConstructionOrderJava {

    public static void main(String[] args) {
        AntJava a=new AntJava();
        System.out.println(a.range);
        System.out.println(a.env.length);

    }

}
 
执行结果是
2
10
 
太奇怪了,scala 输出的结果和java 的输出结果竟然不一样
为什么会这样?
 
通过反编译Creature.class(scala编译生成的) 文件 ,得到如下代码
 
public class Creature
{
  public int range()
  {
    return this.range;
  }

  private final int range = 10;

  public int[] env()
  {
    return this.env;
  }

  private final int[] env = new int[range()];
}
 
发现:private final int[] env = new int[range()];
原来scala 中,就算是代码中宿主类中对  range的字段的访问是直接访问的,但是是通过scala编译后却是通过方法range()  (相同于java中的getter)来访问的。
 
所以在如上对Ant类 生成对象的构造过程如下:
 

1. The Ant constructor calls the Creature constructor before doing its own construction.

2. The Creature constructor sets its range field to 10.

3. The Creature constructor, in order to initialize the env array, calls the range() getter.

4. That method is overridden to yield the (as yet uninitialized) range field of the Ant class.

5. The range method returns 0. (That is the initial value of all integer fields when an object is allocated.)

6. env is set to an array of length 0.

7. The Ant constructor continues, setting its range field to 2.

 
 
 
补充:
1、如上内容是对 《快学scala》8.10 构造顺序和提前定义  这一节的疑惑的测试与探究
 
 
2、对变量的访问,scala 和java 是不同的,通过javap发现,scala 是方法 invokemethod
,而java 是getField 
 

 

3、这里的教训是构造器内部不应该依赖val值。 可以用var 值来替换。因为scala在语法上子类不可以重载父类的var变量,如果子类重写了父类的var值, 编译就不能通过
 
4、对var类型的 range2 值的访问,scala 编译后也是通过方法range2 ()的访问的,但是scala 语法上限制了var 不能重写,所以父类的构造器初始化可以依赖var值
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics