构造器

1. 回顾 
先来回顾一下有关构造器的知识 
 
构造器执行步骤之简要概述: 
(1) binding 绑定参数 
(2) this() 
(3) super() --> 直到Object终止 
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
这里完成了上行过程,由于这个过程完全是系统自动完成的,所以我们可以忽略 
但是一定要记住,到此为止所有的成员变量均已初始化为默认值 
然后由Object自顶向下,下衍执行 
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
(4) 执行域变量的赋值语句 
(5) 执行构造器内的语句 
 
关于这个过程,我们很熟悉了 
如果只把上行的过程简略的看作是初始化所有成员变量的过程,那么我们完全可以忽略它 
(不过不要忘了 super() 过程的存在,这也是考点之一),而将精力放在下衍的过程 
毕竟我们的代码都在这个过程中执行。 
 
因此,我们可以将构造器的初始过程看作为从 Object 顶端逐步向下一级一级执行构造 
器的过程(Marcus Green 语,参考  http://www.jchq.net) 
 
现在再来看一些优秀的题目吧: 
 
2. 范例讨论 
 
(1) Q22 from Hardest Mock Exam 
What will be written to the standard output 
when the following program is run? 
class Base { 
    int i; 
    Base() { 
        add(1); 
    } 
 
    void add(int v) { 
        i += v; 
    } 
 
    void print() { 
        System.out.println(i); 
    } 

class Extension extends Base { 
    Extension() { 
        add(2); 
    } 
 
    void add(int v) { 
        i += v*2; 
    } 

public class Qd073 { 
    public static void main(String args[]) { 
        bogo(new Extension()); 
    } 
 
    static void bogo(Base b) { 
        b.add(8); 
        b.print(); 
    } 

 
1) 9 
2) 18 
3) 20 
4) 21 
5) 22 
 
这个题目不仅考察了构造器的构造过程,同时考察了关于多态的知识 
bogo(new Extention()); 这里 new 了一个 Extention 对象 
明显的调用了构造器并初始化了一个对象,bogo() 将它绑定为 Base 类传入 bogo 方法 
所以说实际上执行了类似下面的这个语句:Base v = new Extention(); bogo(v); 
 
因此,Extention() 初始化的过程是: 
上行 -- 初始化所有实例变量,此时,i=0 
下衍 -- 自顶执行构造器,(Object 构造器为空,所以继续下衍) 
先执行父类 Base 的构造器 add(1),注意,由于多态和动态绑定的原因 
add(1) 将虚拟调用 Extention 类的 add() 方法,而不是 Base 类的 add() 方法 
因此执行完 add(1) 之后,i = 2; 
继续执行子类构造器 add(2),仍然是调用 Extention 类的 add() 方法, 
执行完后,i = 6 
构造器执行完毕 
运行 b.add(8)之后,i = 22 
答案是 5 
 
(2)  
What is the output of the following program  
 
public class Test { 
    private int i = giveMeJ(); 
    private int j = 10; 
 
    private int giveMeJ() { 
        return j; 
    } 
 
    public static void main(String args[]) { 
        System.out.println((new Test()).i); 
    } 

 
Select one correct answer 
a. Compiler error complaining about access restriction of private variables  
of AQuestion. 
b. Compiler error complaining about forward referencing. 
c. No Compilation error - The output is 0; 
d. No Compilation error - The output is 10; 
e. No Compilation error, but Runtime error; 
 
这个题目稍微简单一些,不过域变量由方法赋值很容易迷惑人 
如果你不坚定自己的信念,就会困惑下去 
分析步骤同前面的例子一样: 
上行 -- 初始化全部成员变量 i = 0 , j = 0 
下衍 -- 这里用到了构造器执行过程的第4步,就是执行显式的为域变量赋初值代码 
i 调用 giveMeJ() 方法为自己赋值,此时 j = 0,因此,i = 0 
然后 j 赋初值为 10 ;然后,执行 new 过程的最后一步,执行构造器 
由于构造器是默认构造器,没有代码执行,new 过程结束。 
 
所以答案是 c  
 
 
(3)  
将上面的例子中 i 赋值语句部分修改一下,改为: 
private int i = new Test().giveMeJ();  
 
以同样的步骤分析,你会发现,在构造过程的第4步为 i 指定值的时候 
又 new 了一个 Test 对象,因此需要进入一个新的 new 过程 
而新的过程在同样的步骤同样的地方又进入了一个新的 new 过程………… 
 
好像没有尽头?没错,这个程序因为在堆栈中重复 new 自身 
将导致堆栈溢出 
 
所以答案是 e  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值