为了账号安全,请及时绑定邮箱和手机立即绑定

Java编译时提示非法向前引用

Java编译时提示非法向前引用

慕哥6287543 2019-05-22 21:25:02
问题背景:想了解Java类非静态成员变量以及静态成员变量的初始化过程。在代码块中使用System.out.println输出语句,输出成员变量的值,但是出现非法引用的提示。具体代码如下。具体代码:classA{publicA(){System.out.println("父类A的构造方法");System.out.println("静态成员变量="+staticStr+",非静态成员变量="+str);}{//System.out.println(str);//错误:非法前向引用str="123";System.out.println("父类A的构造代码块0");}static{staticStr="1234";//System.out.println(staticStr);System.out.println("父类A的静态代码块0");}privatestaticStringstaticStr=iniStaticStr();static{System.out.println(staticStr);System.out.println("父类A的静态代码块");}privateStringstr=iniStr();{System.out.println(str);System.out.println("父类A的构造代码块");}privatestaticStringiniStaticStr(){System.out.println("staticStr="+staticStr);System.out.println("静态成员变量显示初始化");return"iniStaticStr";}privateStringiniStr(){System.out.println("str="+str);System.out.println("非静态成员变量显示初始化");return"iniStr";}{//System.out.println(str);//错误:非法前向引用System.out.println("父类A的构造代码块1");}static{System.out.println("父类A的静态代码块1");}}classBextendsA{static{System.out.println("子类B的静态代码块");}publicB(){System.out.println("子类B的构造方法");}{System.out.println("子类B的构造代码块");}}publicclassJavaTest1{publicstaticvoidmain(String[]args){newB();}}输出结果:父类A的静态代码块0staticStr=1234静态成员变量显示初始化iniStaticStr父类A的静态代码块父类A的静态代码块1子类B的静态代码块父类A的构造代码块0str=123非静态成员变量显示初始化iniStr父类A的构造代码块父类A的构造代码块1父类A的构造方法静态成员变量=iniStaticStr,非静态成员变量=iniStr子类B的构造代码块子类B的构造方法具体问题描述:1、代码块与成员变量的执行顺序是怎样的?如果代码块先于成员变量执行,那此时的成员变量并没用被声明,那为什么能对成员变量进行赋值?2、假如是成员变量先于代码块执行,为什么代码块中使用System语句输出操作会提示非法向前引用?3、成员变量的初始化过程是否是一下过程?1)默认初始化2)显示初始化(包括代码块中的显示初始化)3)构造初始化
查看完整描述

2 回答

?
墨色风雨

TA贡献1853条经验 获得超6个赞

这种情况:
{
System.out.println("6666");
}
inta=10;
执行顺序由代码顺序决定。
这种情况:
{
a=10;
}
inta;
inta;
{
a=10;
}
等价,字节码指令一样
                            
查看完整回答
反对 回复 2019-05-22
?
繁星coding

TA贡献1797条经验 获得超4个赞

首先,关于执行顺序问题。主要有以下几个要点:
变量的声明在任意代码执行前发生(类似于privateStringstr这样的声明并不是可执行代码)
接下来是静态块、静态变量的声明时赋值语句,会被合并在一起执行,执行顺序就是它们在代码中的书写顺序
接下来是实例块、实例变量的声明时赋值语句、以及构造方法,前两者按照书写顺序执行,构造方法最后执行
关于执行顺序,你可以对照你程序的打印输出来看,应该就能明白了。
下面再来说说非法向前引用这个错误。
前面说过,所有变量的声明都是在任意代码执行前发生的,那么按道理来说并不存在“向前引用”一说,因为任一句代码执行时变量肯定已经存在了才对。
那么这个错误究竟是怎么出现的呢?答案是:
这是Java编译器强制进行的一个检查
其目的是避免循环初始化和其他非正常的初始化行为。
所以,虽然你的代码看起来没有问题,但是却无法通过编译器的强制检查,所以报错。
那么为什么类似于staticStr="1234";这样的代码可以呢?这是因为Java对其中的某些情况做了“特许”,其中有一条就是“通过简单名称引用的变量可以出现在左值位置,但不能出现在右值的位置”,所以前面的代码可以,但System.out.println(staticStr);不行,因为这是一个右值引用。
最后再简单提一下什么是循环引用,看一下下面这个例子:
privateinti=j;
privateintj=i;
如果没有前面说的强制检查,那么这两句代码就会通过编译,但是很容易就能看得出来,i和j并没有被真正赋值,因为两个变量都是未初始化的(Java规定所有变量在使用之前必须被初始化),而这个就是最简单的循环引用的例子。
                            
查看完整回答
反对 回复 2019-05-22
  • 2 回答
  • 0 关注
  • 1017 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信