java特性(一)之如何理解java的平台无关性

(一)一次编译,到处运行,平台无关性。

1. Compile Once,Run Anyway如何实现?

      首先,创建一个java类。代码如下:

package interview.javabasic;

/**
 * java特性之Compile Once,Run Anyway
 *
 * @author kimtian
 */
public class CodeByteSample {
    public static void main(String[] args) {
        int i = 5, j = 5;
        i++;
        ++j;
        System.out.println(i);
        System.out.println(j);
    }
}

   通常把java分为编译时和运行时。

          (1) 编译时使用javac命令,编译的是java的源码,即将源码编译生成字节码,并存入对应的.class文件中。

              编译时会检查语法、句法等错误。编译完成后会生成一个class文件,class文件保存我们java文件翻译成的二进制字节码,java类文件中的属性、方法,以及类中的常量信息都会被分别存储在.class文件中。

               

          (2)然后再使用java XXX.class文件执行该程序。

         注意:使用java执行时,要在包头路径下,并带上包路径。否则会报错找不到或无法加载主类。

没带上包路径报错:

所在目录层级不对,不在包头路径下:

正确使用方式及返回结果:

         (3) javap  是jdk自带的反汇编器,可以查看java编译器为我们生成的字节码,通过比较字节码和源代码可以发现很多问题,一个很重要的作用是了解很多编译器内部工作的机制。

  •         javap -help  寻求帮助文档。
  •         javap -c       对代码进行反汇编

真正加载class文件去执行的java虚指令(字节码):

Compiled from "CodeByteSample.java"                   表示从CodeByteSample.java编译而来。

public interview.javabasic.CodeByteSample();        无参构造函数。

invokespecial #1                                                       调用父类Object类方法super()。

return                                                                        退出构造函数

可以看出当我们不指定类的构造函数的时候,编译器会默认为我们生成一个不带参数的构造函数。

 0: iconst_5                   把常量5放入栈顶
 1: istore_1                   将栈顶元素放入局部变量1当中
 2: iconst_5                   把常量5放入栈顶
 3: istore_2                   将栈顶元素放入局部变量2当
 4: iinc          1, 1           调用inc函数,将变量1加上1
 7: iinc          2, 1           调用inc函数,将变量1加上1
 10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;      获取PrintStream的静态域对象,将其压入栈顶
 13: iload_1                   将本地变量1(i)的值推送至栈顶
 14: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V                   调用PrintStream的prinltl去打印该值
 17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;      获取PrintStream的静态域对象,将其压入栈顶
  20: iload_2                  将本地变量2(j)的值推送至栈顶
  21: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V                  调用PrintStream的prinltl去打印该值
  24: return                     退出整个方法

(4)编译过程

总结:

Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

2.为什么JVM不直接将源码解析成机器码去执行

(1)每次执行都需要各种语法、句法、语义的检查。都要重新编译,重新分析,性能受到影响。

         引入中间字节码,能够保证被编译成字节码后,多次执行程序不需要各种校验和补全。

(2)脱离java的束缚。由scala,ruby这些语言生成字节码,同样可以被JVM进行调用、执行,进而也能增加平台的兼容、扩展能力。这符合软件设计的中庸之道。

3.JAVA虚拟机

(1)Java虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真、模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆、栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得java程序只需生成在java虚拟机上运行的目标代码及字节码,就可以在多种平台上不加修改的运行。

所以一般情况下我们不需要知道虚拟机的运行原理,只需要专注写java代码。虚拟机可以屏蔽底层操作系统平台的不同,并且减少基于原生语言开发的复杂性。

JVM是一个内存中的虚拟机,意味着JVM的存储就是内存。所写的所有类、常量、变量、方法都在内存中,这决定着我们程序运行的是否健壮,是否高效。

(2)JVM由四部分组成:Class Loader、Runtime Data Area、Execution Engine、Native Interface 

Class Loader:依据特定格式,加载class文件到内存;

Runtime Data Area:JVM内存空间结构模型。

Execution Engine:解释器,对命令进行解析,并提交到操作系统去执行。

Native Interface:融合不同开发语言的原生库为java所用。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值