通过Hello World了解Java基础。
一、使用Eclipse打印输出Hello World
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
二、分析HelloWorld.java执行过程
1、javac编译java文件
- javac命令是java文件进入编译期
- java文件进入编译期之后,javac会检查java文件的语义和语法是否正确
- javac还会将一些
- javac解析字面常量和数值,分配一定大小的内存,只是当前存放的位置不是存放在JVM中,而是保存在后面生成的class文件存放在磁盘的位置
- javac还会去检查静态变量和静态方法,也是会分配一定的内存,暂时保存在文件内存中
- 检查并分配静态代码块等,被static修饰的代码区域
- 编译期的多态(重载)就是在javac命令执行阶段发生的,在这个阶段确定重载的方法
- javac会将整个类的信息,保存在后面生成的class文件中
- javac还会生成一个魔数,用于让JVM识别,JVM想要正确加载JVM魔数是必须的一个标识。
- javac会生成jdk的版本信息(次版本和主版本信息)
常量池中的常量
字面量:比较接近java语言层面的常量的概念,如文本字符串、声明为final的常量值等
符号引用:
- 类和接口的全限定名
- 字段的名称和文件描述符
- 方法名称和描述符
描述符:权限修饰符等
class文件内存分布
补充图
2、java运行clas文件
- class文件首先进入应用程序类加载器,通过Java的双亲委派机制,检查当前包以及类是否在jdk中已存在。如果存在,就加载jdk中的相应包下的类,而致使main找不到;如果不存在,就让应用程序类加载器加载当前class文件。
- 类加载加载的过程,相当于初始化虚拟机内存的过程。类加载会把变量和方法等保存到相应的内存中。
- 类加载,还会创建或生成引用类型的对象,这些对象会保存在堆中。
- 运行期的多态(继承,重写,父类引用指向子类对象)
- 反射的发生阶段
- 类加载机制就是对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的java类型。
因为class字节码文件的存在,所以java实现了“一次编译,到处运行”(Write one,Run Anywhere)。
jvm除了能运行Java语言之外,还能运行groovy,jRuby等语言
class文件有两种数据类型:无符号数和表(无符号数+符合数据类型)
javap -v (或-verbose) HelloWorld.class//查询字节码文件
思考
Object是顶级父类,而其他类都会显示或隐式的继承这个Object顶级父类。在Java中时不允许,多继承的。现在加入有一个Animal类,隐式继承了Object类;一个Dog类,隐式继承了Object类。如果Dog类继承Animal了,但同时Dog也有继承了Object类,如此看来,Dog是不是相当于继承了两次Object类呢?在Java中,是如何保持这种Object单继承的状态的呢?
-
扩展
类索引,父类索引和接口索引集合
类索引:确定当前类的犬类限定名。
- 父类索引:父类索引只有一个,除了Object类外,所有的Java类都有父类。所以除了Object类外,其他所有父类索引都只有一个,且不为0。
- 接口索引集合:就是用来描述这个类实现了哪些接口。这些被实现的接口按照implements语句的先后顺序,从左到右排列在接口索引集合中
类的生命周期
- 加载
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
加载—>连接(验证、准备、解析)—>初始化—>使用—>卸载
一个类什么时候被加载
- 包含main主方法的类,java程序一开始的时候,就会被加载到JVM内存
- 当类中存在静态(被static修饰)的方法或变量时,在主动使用,这些静态的成员的时候,类会被加载
- 使用Class.forName()反射的时候,类会被加载
- 初次使用类,进行实例化对象的时候,类会被加载
- 使用序列化的时候,类会被加载
一句话:只要类被使用的时候,类就会被加载,并且,类只会加载一次,只要类被加载过了,就不会再加载。
补充
- 启动类加载器(Bootstrap ClassLoader):主要负责把lib目录下(或被-Xbootclasspath参数指定的路径),并且能被JVM识别的(仅按照文件名识别,如rt.jar,名字不符合的,就算被放到lib目录下,也不会被时被)类库加载到jvm中。启动类加载器不能被java程序直接使用,原因是启动类加载器底层是c++编写的。如果需要使用,那就在重写的getClassload方法中返回null即可
- 扩展类加载器(Extension ClassLoader):主要负责把lib/ext目录中,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器
- 应用程序类加载器(Application ClassLoader):这个类加载器是ClassLoader中getSystemClassLoader()方法的返回值,所以一般也可以成为系统类加载器。它主要负责加载用户类路径(ClassPath)上所指定的类库。一般情况下,它是程序中的默认类加载器。
- 空闲列表。在堆中分配一块足够大的内存(还可能有剩余),存放对象。
- 指针碰撞。在堆中,分配一块域对象大小一模一样的内存,存储对象。