关于向前引用的问题

Marburger 2013-04-30 05:00:46

public class Test{
int count = 20 ;
{
count = 12;
}
public Test(){
System.out.println(count);
}
public static void main(String[] args) {
new Test();
}

}

这段代码输出是12;通过javap 可知编译器处理后的类 初始化快没了,count的定义也没有了指定的初始值,
对count的赋值被提取到了构造函数中。就如同下面的代码

public class Test{
int count;
public Test(){
count = 20;
count = 12;
System.out.println(count);
}
public static void main(String[] args) {
new Test();
}
}

我的问题是下面的代码为什么不会如同上面一样是等效的

public class Pro{
int count = age;
int age = 10;
{
count = 12;
}
public Pro(){
System.out.println(count);
}
public static void main(String[] args) {
new Pro();
}
}


public class Pro{
int count;
int age;
public Pro(){
count = age;
age = 10;
count = 12;
System.out.println(count);
}
public static void main(String[] args) {
new Pro();
}

}

第一段Pro编译提示向前引用的错误
第二段Pro正常,输出12
之前我还能理解第一段Pro是错的,但是今天看到上面的Test的例子,我又困惑了,
如果说Test那个例子编译器能把第一段Test代码处理后等效于第二段Test代码,
为什么第一段Pro代码不行
...全文
126 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
ZZZ5512536 2013-04-30
  • 打赏
  • 举报
回复
这个就是个类的初始化顺序问题。 父类 -- 静态变量 父类 -- 静态初始化块 子类 -- 静态变量 子类 -- 静态初始化块 父类 -- 变量 父类 -- 初始化块 父类 -- 构造器 子类 -- 变量 子类 -- 初始化块 子类 -- 构造器 你这个没有继承和静态的情况,就可以忽略相关。 所以你的程序执行情况是这样:

public class Pro{
    int count = age;    // 变量-1  age还没定义,所以报错
    int age = 10;       // 变量-2
    {
        count = 12;     // 初始化块-3 
    }
    public Pro(){
        System.out.println(count);   // 构造器-4
    }
    public static void main(String[] args) {
        new Pro();
    }
}



public class Pro{
    int count;   // 变量-1  
    int age;     // 变量-2
    public Pro(){
    	count = age;   // 构造器-3 这里因为age和count都初始化了,默认为0,正确
    	age = 10;      // 重新赋值age为10
    	count = 12;    // 重新赋值count为12,所以最后结果打印为12
    	System.out.println(count);
    }
    public static void main(String[] args) {
    	new Pro();
    }
 // 打了半天字。。
}
fei1710 2013-04-30
  • 打赏
  • 举报
回复
{ count = 12; } 编译器会最提到构造函数的开头执行。 对象初始化的顺序是先初始化成员变量,在调用构造函数。
lcf 2013-04-30
  • 打赏
  • 举报
回复
因为{..}和成员变量声明不是同一个级别的,你可以把它看成一个成员函数,只不过调用的时机是构造函数…哦?这已经是运行时的事情了。函数跟其内部引用变量的定义顺序无关 实际上非法前向引用的范围很窄,几乎只有在变量声明的时候才会出现。
Marburger 2013-04-30
  • 打赏
  • 举报
回复
引用 1 楼 lcf 的回复:
编译器首先分析代码的文本,这一步得先正确,才会再做优化和翻译。它并不会看你代码实际上是什么效果来解决语法错误

public class Test{
    {
        count = 12;
    }
    int count = 20 ;
    public Test(){
        System.out.println(count);
    }
    public static void main(String[] args) {
        new Test();
    }
 
}
这样是正确的,为什么呢
lcf 2013-04-30
  • 打赏
  • 举报
回复
编译器首先分析代码的文本,这一步得先正确,才会再做优化和翻译。它并不会看你代码实际上是什么效果来解决语法错误

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧