通过Hello World了解Java基础。

一、使用Eclipse打印输出Hello World

  1. public class HelloWorld {
  2. public static void main(String[] args) {
  3. System.out.println("Hello World");
  4. }
  5. }

控制台输出结果
image.png

二、分析HelloWorld.java执行过程

HelloWorld执行过程.pdf

未命名文件 (1).png

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文件内存分布

image.png

补充图
image.png

2、java运行clas文件

  • class文件首先进入应用程序类加载器,通过Java的双亲委派机制,检查当前包以及类是否在jdk中已存在。如果存在,就加载jdk中的相应包下的类,而致使main找不到;如果不存在,就让应用程序类加载器加载当前class文件。
  • 类加载加载的过程,相当于初始化虚拟机内存的过程。类加载会把变量和方法等保存到相应的内存中。
  • 类加载,还会创建或生成引用类型的对象,这些对象会保存在堆中。
  • 运行期的多态(继承,重写,父类引用指向子类对象)
  • 反射的发生阶段
  • 类加载机制就是对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的java类型。

因为class字节码文件的存在,所以java实现了“一次编译,到处运行”(Write one,Run Anywhere)。
jvm除了能运行Java语言之外,还能运行groovy,jRuby等语言

class文件有两种数据类型:无符号数和表(无符号数+符合数据类型)

  1. javap -v (或-verbose) HelloWorld.class//查询字节码文件

思考

Object是顶级父类,而其他类都会显示或隐式的继承这个Object顶级父类。在Java中时不允许,多继承的。现在加入有一个Animal类,隐式继承了Object类;一个Dog类,隐式继承了Object类。如果Dog类继承Animal了,但同时Dog也有继承了Object类,如此看来,Dog是不是相当于继承了两次Object类呢?在Java中,是如何保持这种Object单继承的状态的呢?

  • image.png

  • 扩展

    类索引,父类索引和接口索引集合

  • 类索引:确定当前类的犬类限定名。

  • 父类索引:父类索引只有一个,除了Object类外,所有的Java类都有父类。所以除了Object类外,其他所有父类索引都只有一个,且不为0。
  • 接口索引集合:就是用来描述这个类实现了哪些接口。这些被实现的接口按照implements语句的先后顺序,从左到右排列在接口索引集合中

类的生命周期

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化
  6. 使用
  7. 卸载

加载—>连接(验证、准备、解析)—>初始化—>使用—>卸载

一个类什么时候被加载

  • 包含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)上所指定的类库。一般情况下,它是程序中的默认类加载器。
  • 空闲列表。在堆中分配一块足够大的内存(还可能有剩余),存放对象。
  • 指针碰撞。在堆中,分配一块域对象大小一模一样的内存,存储对象。