A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 吴小东 中级黑马   /  2012-7-9 02:00  /  1767 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 吴小东 于 2012-7-9 12:28 编辑

//下面这个程序,大家来看看,目测会报一个怎样的错误?
//第一问题点,static中有this的引用,第二个地方是show()方法中少了一个连接字符串的加号
  1. class Demo2
  2. {
  3.         private String name;
  4.         private int age;
  5.         static
  6.         {
  7.                 this.name = "未知";
  8.                 this.age = 0;
  9.         }

  10.         public String show()
  11.         {
  12.                 return "姓名:"this.name+"年龄:"+this.age;
  13.         }
  14. }
复制代码
/*经过测试,如果两个问题同时存在的情况下,那么报的错误将是语法错误
如果把show()方法中的加号加上的话,那么才会提示静态代码块中的引用错误
那里这里有一个小疑问,就是系统在编译class文件的过程中,他的编译步奏应该是这样的呢?
比如上面,是先编译语法错误,再编译具体引用错误,求解
*/

4 个回复

倒序浏览
本帖最后由 刘煜 于 2012-7-9 05:23 编辑

你必须必须了解java的编译机制,这里是关于java编译机制的详细介绍,你想知道的编译步骤在下边最后一部分能够找到,希望对你有帮助:
1.编译机制
JVM规范中定义了class文件的格式,但并未定义Java源码如何编译为class文件,各厂商在实现JDK时通常会将符合Java语言规范的源码编译为class文件的编译器,例如在Sun JDK中就是javac,Eclipse中也有自带的编译器。主要步骤如下:
源码文件->分析和输入到符号表(Parse and Enter)->注解处理(AnnotationProcessing)->语义分析和生成class文件(Analyse andGenerate)->class文件
Java代码编译通过Java源码编译器来完成,流程图如下所示
                              
Java字节码的执行是由JVM执行引擎来完成,流程图如下所示:

下面简单介绍以上三个步骤:
1.1 分析和输入到符号表(Parse and Enter
Parse过程所做的为词法和语法分析。词法分析(com.sun.tools.javac.parser.Scanner)要完成的是将代码字符串转变为token序列(例如Token.EQ(name:=));语法分析(com.sun.tools.javac.parser.Parser)要完成的是根据语法由token序列生成抽象语法树 。
Enter(com.sun.tools.javac.comp.Enter)过程为将符号输入到符号表,通常包括确定类的超类型和接口、根据需要添加默认构造器、将类中出现的符号输入类自身的符号表中等。
1.2 注解处理(AnnotationProcessing
该步骤主要用于处理用户自定义的annotation,可能带来的好处是基于annotation来生成附加的代码或进行一些特殊的检查,从而节省一些共用的代码的编写,例如当采用Lombok 时,可编写如下代码:
1.   public class User{
2.   private @Getter String username;
3.   }
编译时引入Lombok对User.java进行编译后,再通过javap查看class文件可看到自动生成了public StringgetUsername()方法。
此功能基于JSR 269 ,在Sun JDK 6中提供了支持,在AnnotationProcessing进行后,再次进入Parse and Enter步骤。
1.3 语义分析和生成class文件(Analyse andGenerate
Analyse步骤基于抽象语法树进行一系列的语义分析,包括将语法树中的名字、表达式等元素与变量、方法、类型等联系到一起;检查变量使用前是否已声明;推导泛型方法的类型参数;检查类型匹配性;进行常量折叠;检查所有语句都可到达;检查所有checkedexception都被捕获或抛出;检查变量的确定性赋值(例如有返回值的方法必须确定有返回值);检查变量的确定性不重复赋值(例如声明为final的变量等);解除语法糖(消除if(false) {…} 形式的无用代码;将泛型Java转为普通Java;将含有语法糖的语法树改为含有简单语言结构的语法树,例如foreach循环、自动装箱/拆箱等)等。
在完成了语义分析后,开始生成class文件(com.sun.tools.javac.jvm.Gen),生成的步骤为:首先将实例成员初始化器收集到构造器中,将静态成员初始化器收集为<clinit>();接着将抽象语法树生成字节码,采用的方法为后序遍历语法树,并进行最后的少量代码转换(例如String相加转变为StringBuilder操作);最后从符号表生成class文件。
上面简单介绍了基于javac如何将java源码编译为class文件 ,除javac外,还可通过ECJ(Eclipse Compilerfor Java) 或Jikes 等编译器来将Java源码编译为class文件。
class文件中并不仅仅存放了字节码,还存放了很多辅助jvm来执行class的附加信息,一个class文件包含了以下信息。
● 结构信息。包括class文件格式版本号及各部分的数量与大小的信息。
● 元数据。对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池。
● 方法信息。对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息。

评分

参与人数 1技术分 +1 收起 理由
蒋映辉 + 1 虽然是网上的答案,鼓励一下新童鞋.

查看全部评分

回复 使用道具 举报
本帖最后由 贾存双 于 2012-7-9 04:54 编辑

因为静态代码块优先于构造代码块,所以在编译的时候 static 代码块先通过编译,就像下面这段代码:
class Demo{
        {       // 直接在类中编写代码块,称为构造块
                System.out.println("1、构造块。") ;
        }
        static{       // 使用static,称为静态代码块
                System.out.println("0、静态代码块") ;
        }
        public Demo(){        // 定义构造方法
                System.out.println("2、构造方法。") ;
        }
};
public class DemoTest{
        static{                // 在主方法所在的类中定义静态块
                System.out.println("在主方法所在类中定义的代码块") ;
        }
        public static void main(String args[]){
                new Demo() ;                // 实例化对象
        }
};




这样看,就说明你语法错误:return "姓名:" + this.name + "年龄:" +this.age;  少了一个加号。

评分

参与人数 1技术分 +1 收起 理由
职业规划-刘倩老师 + 1 新手报到,鼓励鼓励,加加油!!!.

查看全部评分

回复 使用道具 举报
class Demo2

{

        private String name;

        private int age;

        static

       {
                new Demo2().name = "未知";

              new Demo2().age = 0;
              System.out.println("静态代码块");

       }



        public String show()

       {

               return "姓名:"+new Demo2().name+"年龄:"+new Demo2().age;

        }
}
因为静态代码块优先于构造代码块,所以在编译的时候 static 代码块先通过编译不不管有多少相同的静态代码块都只执行一次,所以不能使用this的方法调用必须使用new Demo2().name 这种方法类实现
回复 使用道具 举报
一楼的哥们很给力,差不多明白了,简单总结一下
1.先进行符号书写方面的编译检查,比如少括号,少分号之类的书写错误
2.再对注解进行编译检查
3.然后才是对符号书写错误之外的错误进行便已检查,比如变量的赋值,引用错误,泛型转化,异常处理等等
学习了

另外二楼和三楼的哥们,也要认真看我问的问题到底是什么啊!!表示有点小纠结
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马