所谓向前引用,就是在定义类、接口、方法、变量之前使用它们,例如,

class MyClass
{void method(){System.out.println(myvar);}String myvar = "var value";
} 

myvar在method方法后定义,但method方法可以先使用该变量。在很多语言,如C++,是需要提前定义的,而Java已经允许了向前引用。不过在使用向前引用时可能会容易犯一些错误。例如,下面的代码。

class MyClass {int method() {return n; }int m = method();int n = 1;
}

如果简单地执行下面的代码,毫无疑问会输出1.

    System.out.println(new MyClass().method());

不过使用下面的代码输出变量m,却得到0.

    System.out.println(new MyClass().m);

那么这是真么回事呢?

实际上,从java编译器和runtime的工作原理可以得知。在编译java源代码时只是进行了词法、语法和语义检测,如果都通过,会生成.class文件。不过这时MyClass中的变量并没有被初始化,编译器只是将相应的初始化表达式(method()、1)记录在.class文件中。

当runtime运行MyClass.class时,首先会进行装载成员字段,而且这种装载是按顺序执行的。并不会因为java支持向前引用,就首先初始化所有可以初始化的值。首先,runtime会先初始化m字段,这时当然会调用method方法,在method方法中利用向前引用技术使用了n。不过这时的n还没有进行初始化呢。runtime为了实现向前引用,在进行初始化所有字段之前,还需要将所有的字段添加到符号表中。以便在任何地方(但需要满足java的调用规则)都可以引用这些字段,不过由于还没有初始化这些字段,所以这时符号表中所有的字段都使用默认的值。int类型的字段默认值自然是0了。所以在初始化int m = method()时,method方法访问的n实际上是在进行正式初始化之前已经被添加到符号表中的字段n,而不是后面的int n = 1执行的结果。但将MyClass改成如下的形式,结果就完全不同了。

class MyClass {int method() {return n; }int n = 1;int m = method();
}

现在执行下面的代码,会输出1.

    System.out.println(new MyClass().m);

究其原因,是引用初始化m时调用method方法,该方法中使用的n已经是初始化完的了,而不是最初放到符号表中的值。

综合上述,runtime在运行.class文件时,每个作用域(方法、接口、类等带语言元素都有自己的作用域)的符号表都会被至少访问两次,第一次会将所有的字段(这里只考虑类的初始化)放到符号表中,暂时不考虑初始化只,放到符号表中只是相当于一个索引,好让其他地方引用该字段时可以找到它们,例如,method方法中引用n时就会到符号表中寻找n,不过这时的n只是int类型的默认值。等到第二次访问n就是真正初始化n的时候(int n = 1)。这是将符号表中存储的字段n的值更新为实际的初始化值(1)。所以如果引用n放生在正式初始化n之前,当然输出的是0。

那么可能有人会问,先访问一下n,再访问m,这时m的值是否为1呢?答案仍然是0。因为在创建MyClass对象时m和n的初始化工作已经完成,它们的值已成事实,除非再次设置,否则不可改变了。

   MyClass myClass = new MyClass();System.out.println(myClass.n);  //  输出1System.out.println(myClass.m);  //  仍然输出0

对于静态成员,仍然符合这一规则。

class MyClass {static int method() {return n; }static int m = method();  //  直接访问m,仍然会输出0static int n = 1;
}

转载于:https://www.cnblogs.com/snake-hand/p/3157157.html

Java向前引用容易出错的地方相关推荐

  1. java 它 引用(基本类型的包装,构造函数和析构函数c++不同)

      一个:java 和c++参考控制 他提到引用,我们会想到java它不喜欢c++里面的指针.当然java内引用和c++里面的引用是不同的. 比如: 比方C++中,我对某一个函数的声明.int a(i ...

  2. java二级选择题要对一半吗_据说一半以上的java程序员会出错的题

    大三即将结束,经过一段时间的较为系统的自学java, 突然看到一个自称一半以上的java程序员都会出错的程序尤为感兴趣.便深究了一番 程序代码如下: package com.longpo; class ...

  3. java 指针 引用_java中的引用与c中的指针

    指针 首先要弄清楚指针和c中的指针是不一样的,前者是概念,后者是具体实例. 换句话说,C中的指针只是指针中的一种,其他语言也有指针,比如C++.但是我们同别人交流的时候,大都不会从概念上去交流,一般会 ...

  4. java c 引用区别_Java的引用c++的引用和C指针的区别

    Java的引用本质上就是C中的指针,而c++的引用则完全不同:有一个类 class Point { int x; int y; } 同样的一个Point p; 在Java中p表示一个引用,它等同于C语 ...

  5. Java import javax.servlet 出错

    Java import javax.servlet 出错 Error: The import javax.servlet cannot be resolved The import javax.ser ...

  6. Java 基础 | Java 中引用与指针的关系

    前言:关键字包含 #指针,java 引用,空指针,地址访问,引用类型,在 Java 编程语言中,程序员不需要担心程序的内存使用.Java 语言的自动垃圾收集器会不时地清理那些变成垃圾的对象. 如果垃圾 ...

  7. 【XML和Java】手写Java程序引用xsd验证xml

    一.首先要有一个xml文件和xsd文件 (1) database.conf.xml <?xml version="1.0" encoding="UTF-8" ...

  8. java 弱引用 集合_java 弱引用集合类WeakHashMap

    java 弱引用集合类WeakHashMap Java集合框架中的WeakHashMap类是Map接口的一种特殊实现.它实现了Map接口,继承了AbstractMap抽象类.它实现了对key的弱引用. ...

  9. python不需要定义函数后使用_python自定义函数可以向前引用不用声明

    原博文 2017-01-31 16:35 − #有些编程语言不够"聪明",向这类向前引用的方式会导致报错,但Python足够"醒目",这段代码是正确的! def ...

最新文章

  1. 检查型异常(Checked Exception)与非检查型异常(Unchecked Exception)
  2. 第三天2017/03/30(上午:二级指针的(输入)内存模型:(共三种模型))
  3. C# DataGrid 控件在winform里显示行号
  4. 如果在这样的环境中写代码,会不会很高效
  5. 小猴子蓝裤黄袄的局域网聊天
  6. 【SGU】SGU每日练1·Little shop of flowers【DP】
  7. ES6新特性_ES6语法糖_class静态成员---JavaScript_ECMAScript_ES6-ES11新特性工作笔记034
  8. MongoDB 在windows shell环境下的基本操作和命令的使用示例(一)
  9. 恒生电子笔试题数据库及算法整理记录
  10. oracle 7天密码过期,oracle密码过期ORA-28002: 7天之后口令将过期的解决方法
  11. Android 中指纹识别的使用
  12. 兔子生兔子java_用Java编程计算兔子生兔子的问题
  13. 随身WIFI安装Debian流程记录
  14. Unity3D架构设计NavMesh寻路
  15. 新兴职业背后的认知逻辑
  16. Vision.CascadeObjectDetector-VJ算法学习
  17. SQL 校验身份证号格式
  18. 怎样检测计算机硬件是否正常,怎么检查电脑硬件是否有问题
  19. Python Tutorial中英双语对照文档5
  20. 方方格子access_有什么好用的办公软件推荐?

热门文章

  1. Mysql数据库的使用总结之ERROR 1146 (42S02)
  2. C#.net技术内幕04-集合
  3. Will it finally: 关于 try/catch 的一些细节
  4. linux环境 phpstudy集成环境中设置php永久环境变量
  5. 新建Exchange服务器 Outlook端收发邮件报错:0x80040201
  6. java中io与nio复制文件性能对比
  7. 修改ubuntu系统默认语言(linux中文乱码)
  8. [转]脏读,不可重复读,幻读的理解
  9. 用幻灯片做完整的“一站到底”抢答器
  10. 5.VMware View 4.6安装与部署-安装view agent与模版