一、手写源程序
我们打开任何一本Java学习的书籍,都会告诉我们用记事本或者其他的文本编辑器写一个简单的小程序,然后javac 类名,进行编译,会在同一文件下生成一个同名的.calss文件;我们这里先怒写一个HelloWorld.java,代码如下:
public class HelloWorld { public static void main(String[] args){ System.out.println("Hello World!"); } }
|
.class文件反序列化,代码如下:
package com.tao.study.one; public class HelloWorld { public HelloWorld() { } public static void main(String[] args) { System.out.println("Hello World!"); } }
我们用cmd命令打开我们编译后的.class文件,cmd的命令为:javap -v 类名,HelloWorld.class的内部代码如下:
Classfile /E:/DataBase/Idea/JavaStudy/out/production/JavaStudy/com/tao/study/one/HelloWorld.class Last modified 2017-12-3; size 570 bytes MD5 checksum e34e8917fa1c76751b4ea9a2f491d17a Compiled from "HelloWorld.java" public class com.tao.study.one.HelloWorld minor version: 0 //副版本号 major version: 52 //编译器版本号 == jdk1.8 flags: ACC_PUBLIC, ACC_SUPER //常量池 Constant pool: #1 = Methodref #6.#20 // java/lang/Object."<init>":()V #2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #23 // Hello World! #4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #26 // com/tao/study/one/HelloWorld #6 = Class #27 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/tao/study/one/HelloWorld; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = Utf8 args #17 = Utf8 [Ljava/lang/String; #18 = Utf8 SourceFile #19 = Utf8 HelloWorld.java #20 = NameAndType #7:#8 // "<init>":()V #21 = Class #28 // java/lang/System #22 = NameAndType #29:#30 // out:Ljava/io/PrintStream; #23 = Utf8 Hello World! #24 = Class #31 // java/io/PrintStream #25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V #26 = Utf8 com/tao/study/one/HelloWorld #27 = Utf8 java/lang/Object #28 = Utf8 java/lang/System #29 = Utf8 out #30 = Utf8 Ljava/io/PrintStream; #31 = Utf8 java/io/PrintStream #32 = Utf8 println #33 = Utf8 (Ljava/lang/String;)V { public com.tao.study.one.HelloWorld(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 6: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/tao/study/one/HelloWorld; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World! 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 8: 0 line 9: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String; } SourceFile: "HelloWorld.java"
二、提出疑问
看到上面的结果,我们的第一感觉肯定是,woc,怎么这么神奇,这里面都发生了什么呢?那我们就要带着这些疑问去探究他们了,在百度上一顿操作之后,我们知道了javac是java自带的编译器,将java语言规范转化成JVM能够识别的字节码文件(.class文件);这是就更加懵了,甚至有点想跳过,一个过来人告诉你,不要这样子哦。下面我们来 总结一下这里面的问题,然后去探究一下java的世界到底是一个怎样的存在。
问题有:
1、 什么是javac编译器?它又有什么作用?它又是怎样工作的呢?
2、 为什么要把字节码文件加载到JVM中呢?字节码文件又是如何加载到JVM中的?
3、 JVM是什么?它是如何工作的呢?
三、解决疑问
看到这些疑问你是不是有点兴奋了,原来java可以学习的东西有这么多的啊,那我们就开始我们的探索之旅吧。问题要一个个的解决,我们就按顺序进行研究吧!
编译原理
1.1 javac是java语言自带的一种编译器,我们都知道java有自己的语言规范,写错了一小处代码,整个项目都会无法运行,这就是规范的魅力,无规矩不成方圆,代码世界中同样如此,每一门语言都是一个王国,我们都是它的臣民;但是java语言不是机器语言,我们的机器是无法识别的,于是我们的java国王大手一挥创建了外交部,让javac负责这个部门,让它负责对外交流,但是javac这个小伙发现一个人的力量是有限的,要充分发挥自己的部长身份,于是他找到自己的得力干将JVM,让他负责与机器王国进行交流;每当国王发布新的命令的时候(.java文件),javac就将其编译成字节码文件,然后直接丢给自己的小弟JVM,自己只负责与国王(java类)对话交流;
1.2 Java的编译环节分为四个步骤,绝大部分的编译器也是这样设计的,四个步骤依次为:
- 词法解析
- 语法解析
- 语义解析
-
生成字节码
编译器的功能就是将java代码翻译成JVM规范下的字节码文件,最重要的点是符合jvm规范,我们的翻译过程也主要是围绕着从一个规范到另一个规范的过程展开;
1.2.1 词法解析:
词法解析的作用就是生成符合java语法规范的Token序列;注释:
Token序列就是一组对应源码字符集合的单词序列,其实上就是一个枚举类型,内部定义了许多符合java语法规范并与源码字符集合相对应的枚举常量;
这时我们肯定会非常好奇,java源码是如何转换成Token序列的呢?java的源码又是如何和已经生成的Token序列保持一个长久的对应关系呢?
词法解析器在将源码翻译成Token序列之前,会先把这个源码字符集合转化为一个Name对象,每一个源码字符集合都是一个Name对象;Keywsords这个类(这里可以把它理解为一个工具类,名字不重要)会把所有的枚举常量转换为一个Name对象,然后将其存储在Name对象的内部类Table中,这时候Name对象就与Token序列建立了一个映射关系;每当我们传进来一个源码字符集合的Name对象的时候,词法解析器就会先找到Name类的内部类Table,在里面获取到对应的Token对象后,将源码字符集合与对应的Token对象的关系存储在Keywords类的Token key[]数组中;我们可以用一张图来表示这个过程,如下:
1.2.2 语法解析:
语法解析的作用就是把匹配得到的Token序列整合成一个语法树;
1.2.3 语义分析:
语义分析就是将语法分析产生的语法树进一步完善,例如给类 添加的默认构造函数,检查变量在使用前是否初始化,将一些常量进行合并处理,检查操作变量类型是否匹配,检查所有的操作语句是否可达,检查异常是否已经捕获或者抛出,解除java语法糖,等。
1.2.4 生成字节码:
遍历语法树,生成最终的字节码。
Java虚拟机(JVM)
1、大家都知道Java是一门可以跨平台的语言,就是因为java源代码的编译结果字节码文件,而字节码文件是在JVM上面运行的,JVM是java技术的真正核心,俗话说得好,一个人对java理解的深度取决于他对JVM的理解深度,由此可以看出,JVM是我们的重中之重;
2、字节码文件加载到JVM中又是经历了一个怎样的过程呢,那我们就读一下下面的这一篇文章吧!
畅谈类加载的过程
3、java王国的国王想知道JVM这个小伙是怎么做的这么优秀的,谁先彻底研究清除,重重有赏,无数谋士纷纷前往,但又有几个真的了解了这个城府如此之深的小伙呢;但我们不能放弃,下面就让我们一起去剖析一下JVM到底是一个什么东西,他是如何做到外交部长交给他的任务的:
绑架JVM
相关推荐
当在 catch 子句中再次引发当前异常对象时,它被省略。 (3)try –catch语句 try-catch 语句由一个 try 块和其后所跟的一个或多个 catch 子句(为不同的异常指定处理程序)构成。try-catch 语句采用下列形式之一: ...
同时,这也引发了对人工智能在前端开发中作用的深入思考,探讨其是否真的能替代或增强人类开发者的工作。 总之,人工智能技术在前端开发中的应用,尤其是神经网络的使用,预示着一个潜力巨大的变革。尽管目前还存在...
3. 程序员练习书法却写下“helloworld”这个经典的编程入门语句,这体现了编程文化与传统艺术的碰撞。"Hello, World!"是许多编程语言的第一个示例,用于介绍基本语法。这表明程序员在追求个人兴趣时,也可能将编程...
10.7 Hello World 引发的新问题/ 124 10.8 文件忽略/ 125 10.9 文件归档/ 129 第11章 历史穿梭/ 130 11.1 图形工具:gitk/ 130 11.2 图形工具:gitg/ 131 11.3 图形工具:qgit/ 135 11.4 命令行工具/ 140 11.4.1 ...
这篇文档主要包含两部分,一部分是一段英文自我介绍,另一部分是关于互联网影响的英语小短文。...同时,它还引发了对互联网影响的思考,提示我们在享受技术便利的同时,不应忽视网络行为的道德和伦理。
$user->addAtri(['userRealName' => 'helloworld']); next($user); } } ``` 以及在Teacher类中,不应假设User类包含userRealName属性,而是应该通过添加方法实现: ```php class Teacher extends User { public ...
需要注意的是,Python对语法的严谨性要求很高,缺少括号或引号会导致语法错误,例如`print('Hello,world!)`就是一个典型的例子,会引发SyntaxError。 为了更好地掌握Python,建议按照以下步骤进行实践: 1. 了解...
例如,一件T恤可能会印上"Hello, World!",这是许多程序员学习编程时接触的第一个程序;或者印上二进制数字,这是计算机语言的基础。这些设计既展示了程序员的专业知识,又透露出他们对这份工作的热爱和幽默感。 ...
在Java入门阶段,第一个程序通常是"Hello, World!"。这段简单的代码展示了如何在Java中定义一个类并输出一条信息。`public class Hello`定义了一个公共类,`main`方法是程序的入口点,`System.out.println`则用于...
strcpy(str, "helloworld"); printf(str); } ``` - **解答与分析:** - `GetMemory`函数内的`p = (char*)malloc(100);`改变了局部变量`p`的值,但并未影响到外部的`str`指针。 - **改进方案:** - 将`...
在这个例子中,CSS样式#content已经成功应用,JavaScript函数(如`alert('Hello World')`)也能正常执行。虽然在设计视图中可能无法预览样式,但在运行时,页面会呈现出预期效果。 总之,为了在使用母版页时处理...
7. **设问**:提出问题,引发读者思考。 8. **反问**:用疑问形式表达确定的意思,增强表达强度。 9. **引用**:引入他人的言论,增加说服力。 10. **借代**:以相关事物代替原事物,简化表达。 11. **反语**:用...
- 为了实现链式表达式,例如 `int length = strlen( strcpy( strDest, "hello world") );`。 #### 6. 类 `String` 的构造函数、析构函数和赋值函数 - **普通构造函数**: - 如果输入的字符串为空,则分配一个字符...
my_variable = "Hello, World!" ``` 此外,Python支持多种数据结构,如列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set)。这些数据结构为处理各种复杂问题提供了便利。例如,你可以创建一个包含数字的...
**5.1 在Linux下用汇编写Hello World** 本节通过一个简单的示例程序介绍了如何在Linux环境下使用汇编语言编写代码。 **5.2 再进一步,汇编和C同步使用** 这一部分介绍了如何将汇编语言和C语言结合起来使用,为...