引入:谈谈你对java的理解
1.java的平台无关性
2.GC
3.语言特性(泛型反射)
4.面向对象
5.类库
6.异常处理
Compile Once,Run Anywhere如何实现?
编译期:javac指令,编译java源码生成字节码存入相应的.class文件中
运行期: jvm解析,转换成特定平台(ios或者windows或者Linux)的执行指令
示例代码:
package com.edu;
public class text {
public static void main(String[] args) {
int i=1,j=5;
i++;
++j;
System.out.println(i);
System.out.println(j);
}
}
正常编译后:
会多出来这样的.class文件
再进一步调用:
使用指令javap打开text.class:
Compiled from "text.java" //这个类由text.java编译而来
public class com.edu.text { //定义了text这个类,这个类带有他的package,
public com.edu.text(); //编译器给我们一个缺省构造函数
Code: //无参构造函数执行的内容
0: aload_0 //表示对this这个句柄操作
1: invokespecial #1 //Method java/lang/Object."<init>":()V 即调用父类的构造方法
4: return //退出这个构造函数
//从以上可知,当我们不使用构造函数时,编译器会默认生成一个无参构造函数
public static void main(java.lang.String[]); //main函数 接收一组字符串数组
Code:
0: iconst_1 //常量1放到栈顶
1: istore_1 //将栈顶的值放在局部变量1中(i)
2: iconst_5 //将5放到栈顶
3: istore_2 //将栈顶的值放到局部变量2中 (j)
4: iinc 1, 1 //将变量1+1(实际变量i)
7: iinc 2, 1 //将变量2+1(实际变量j)
10: getstatic #2 //Field java/lang/System.out:Ljava/io/PrintStream;去获取PrintStream的静态域对象并将静态域对象压入栈顶
13: iload_1 //然后将本地变量i的值推送到栈顶
14: invokevirtual #3 //Method java/io/PrintStream.println:(I)V然后调用PrintStream.println的方法打印i的值
17: getstatic #2
20: iload_2
21: invokevirtual #3 // 对变量2做了同样的操作
24: return //退出方法
总结:
java源码首先被转换为字节码,再由不同平台的jvm解析,java语言在不同的平台上不需要重新编译,java虚拟机在执行字节码的时候把字节码转换成具体平台上的机器指令。
为什么jvm不直接将源码解析成机器码去执行呢?
准备工作:每次执行都需要各种检查,都要重新编译重新分析,所以引入了中间字节码,多次执行程序不需要反复编译
兼容性:也可以将别的语言解析成字节码。也可以被jvm执行,增加兼容扩展能力