重回Hello World

Hello World

public class First {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

在这里插入图片描述
以Java类型的文件,虚拟机并不能识别这种写法,需要通过Javac编译后得到:

在这里插入图片描述

在这里插入图片描述
Javac是Java编译器,通过学习编译原理,可以知道编译器的作用的基本就是:

  1. 词法分析
  2. 语法分析
  3. 语义分析
  4. 代码优化
    源代码经过词法分析产生Token流,在经过词法分析器得到语法树/抽象语法树,通过字节码生成器得到JVM字节码。
    经过编译器翻译后得到.class文件,如果编写的.java文件中存在多个内部类相应的编译后也会有多个.class文件。
    .class文件可以被java虚拟机所运行,执行
    在这里插入图片描述
    可以得到Hello World的输出。
    Java代码编译和执行的整个过程包含了一下三个重要的机制:
    1.Java源码编译机制
    2.类加载机制
    3.类执行机制

最后生成的class文件由以下部分组成:
1.结构信息。包括class文件格式版本号及部分的数量与大小关系
2.元数据。对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池
3.方法信息。对应Java源码中语句和表带式对应的信息。

而Java虚拟机即是Java跨平台的秘密所在,通过虚拟机.class文件可以被虚拟执行再转化为机器码文件实现在cmd中输出字符串。
而虚拟机的作用远不止于此:
虚拟机作为一个虚拟的计算机,应该像正常的计算机一样拥有自己的指令集、内存分区、处理器、调度算法等,这又涉及到操作系统原理。
JVM是基于栈的体系结构来执行class字节码的。线程创建后,会产生程序计数器PC和栈STACK,程序创建后,都会存放程序计数器PC和栈STACK,程序计数器存放下一条要执行的指令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应的每个方法的每次调用,而栈帧又是有局部变量区的操作数栈两部分组成,局部变量区用于存放方法中的局部变量和参数,操作数用于存放方法执行过程中产生的中间结果。
所以看似简单的输出,涉及到内容却并不简单。
在这里插入图片描述
再看新的hello word可知:

public class Test {
    public static String hello="龙与虎";
    public String word="yyds";
    public static void main(String[] args) {
        Test test=new Test();
        int j=1024;
        System.out.println(hello);
        System.out.println(test.word);
        System.out.println(j);
    }
}

从JVM的角度去理解:
程序计数器:
内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成
Main方法实际相当于一个主线程,在main方法中顺序的执行代码依赖于程序计数器来完成。
Java 虚拟机栈:
线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。
在上述方法中,int h=1024就是一个方法内部的局部变量,main方法之外是调用不到的,当运行main方法时,j存储在虚拟机栈中
本地方法栈:
区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。
点开System的源码
在这里插入图片描述
通过翻译注释:
通过静态初始值设定项注册本地项。VM将调用initializeSystemClass方法来完成该类的初始化与clinit分离。
调用System.out.println在windows的运行效果为在控制台窗口中输出文字,此时使用的println方法实际上是通过JavaIO的wirte方法将数据写入并调用Native本地方法显示。
Java 堆:
对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。
新建的Test对象就存储与此处。
方法区:
属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
static类型的Hello存储与此处
运行时常量池:
属于方法区一部分,用于存放编译期生成的各种字面量和符号引用。编译器和运行期(String 的 intern() )都可以将常量放入池中。内存有限,无法申请时抛出 OutOfMemoryError。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值