Java 前置知识

@[toc] --- ## 为什么 Java 代码可以实现一次编写、到处运行? JVM(Java虚拟机)是 Java 跨平台的关键。 **在程序运行前,Java 源代码(.java)需要经过编译器编译成字节码(.class)。在程序运行时,JVM 负责将字节码翻译成特定平台下的机器码并运行**,也就是说,只要在不同的平台上安装对应的 JVM,就可以运行字节码文件。 同一份 Java 源代码在不同的平台上运行,它不需要做任何的改变,并且只需要编译一次。而编译好的字节码,是通过 JVM 这个中间的 “桥梁” 实现跨平台的,JVM 是与平台相关的软件,它能将统一的字节码翻译成该平台的机器码。 注意事项 - 编译的结果是生成字节码、不是机器码,操作系统无法直接运行字节码,必须通过JVM翻译成机器码才能运行 - **跨平台的是 Java 程序、而不是 JVM,JVM 是用 C/C++ 开发的软件,不同平台下需要安装不同版本的 JVM** ## JDK 和 JRE 的区别 首先,我们需要知道 Java 程序其实是运行在JVM (Java虚拟机) 上的,使用 Java 编译器编译 Java 程序时,生成的是与平台无关的字节码,这些字节码只面向 JVM。不同平台的 JVM 都是不同的,但它们都提供了相同的接口,这也正是 Java 跨平台的原因。其和 JDK、JRE 的关系如下图所示: <img src="https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210106175047.png" style="zoom:67%;" /> - **JDK(Java Development Kit)**:是 Java 的标准开发工具包(**普通用户只需要安装 JRE 来运行 Java 程序。而程序开发者必须安装 JDK 来编译、调试程序**)。它提供了编译、运行 Java 程序所需的各种工具和资源,包括 Java 编译器、Java 运行环境 JRE,以及常用的 Java 基础类库等,是整个 Java 的核心 > 下图是 Java 8 中 JDK 的安装目录 > > <img src="https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210106175401.png" style="zoom: 67%;" /> > > - `bin` 文件里面存放了JDK的各种开发工具的可执行文件,主要的是编译器 (`javac.exe`) > - `db` 文件是一个先进的全事务处理的基于 Java 技术的数据库(jdk 自带数据库 db 的使用) > - `include` 文件里面是 Java 和 JVM 交互用的头文件 > - `jre` 为 Java 运行环境 > - `lib` 文件存放的是 JDK 工具命令的实际执行程序 - **JRE(Java runtime environment)**: 是运行基于 Java 语言编写的程序所不可缺少的运行环境,用于解释执行 Java 的字节码文件。<u>JRE 是 Java 运行环境,并不是一个开发环境</u>,所以没有包含任何开发工具(如编译器和调试器),只是针对于【使用】Java 程序的用户 > 下图是Java 8中 JRE 的安装目录,里面有两个文件夹 `bin` 和 `lib`。你可以认为 bin 里的就是 JVM,lib 中则是 JVM 工作所需要的类库,而 JVM 和 lib 和起来就称为 JRE > > <img src="https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20210106175608.png" style="zoom:67%;" /> ## 介绍一下 Java 的数据类型 Java数据类型包括基本数据类型和引用数据类型两大类: 1)**基本数据类型**: 整数类型: - `byte`,1 字节(8 bit),数据范围是 $[-2^{7},2^{7}-1]$ - `short`,2 字节(16 bit),数据范围是 $[-2^{15},2^{15}-1]$ - `int`,4 字节(32 bit),数据范围是 $[-2^{31},2^{31}-1]$ - `long`,8 字节(64 bit),数据范围是 $[-2^{63},2^{63}-1]$ 浮点数类型: - `float`,4 字节(32 bit) - `double`,8 字节(64 bit) 布尔类型: - `boolean`,如果 boolean 是单独使用(在编译之后使用 Java 虚拟机中的 int 数据类型来代替),则 占 4 个字节。如果 boolean 是以 “boolean数组” 的形式使用,则占 1 个字节(不过 Java 规范对 boolean 占用的内存空间没有明确的规定,不同的 JVM 有不同的实现机制) 字符类型: - `char`,2 字节(16 bit) 2)**引用类型**:引用类型就是对一个对象的引用,根据引用对象类型的不同,可以将引用类型分为 3 类,即数组、类、 接口类型。<u>引用类型本质上就是通过指针,指向堆中对象所持有的内存空间,只是 Java 语言不再沿用指针这个说法而已</u> ## Java 是按值调用还是按引用调用的? - **按值调用 (call by value )** 表示方法接收的是调用者提供的值。 - **按引用调用 ( call by reference )** 表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。 **Java 程序设计语言总是采用「按值调用」。也就是说,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。** 在 Java 中,方法参数共有两种类型: - 基本数据类型:一个方法【不能】修改一个基本数据类型的参数 - 引用数据类型:一个方法【可以】改变一个引用数据类型的参数 > 举个例子,假定一个方法试图将一个参数值增加至 3 倍: > > ```java > public static void tripleValue(double x){ > x *= 3; > } > -------------------------- > double percent = 10; > tripleValue(percent); > ``` > > <u>调用这个方法之后,`percent` 的值还是 10</u>。下面看一下具体的执行过程: > > - x 被初始化为 `percent ` 值的一个拷贝(也就 是 10 ) > - x 被乘以 3 后等于 30。 但是 `percent `仍然是 10 > - 这个方法结束之后,参数变量 x 不再使用。 > > ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20200618152649.png) > > 已经看到,一个方法不可能修改一个基本数据类型的参数。而对象引用作为参数就不同了,可以很容易地修改对象的字段值(比如我们有个 `Employee` 类,其中有字段 `salary`和 方法 `raiseSalary` ): > > ```java > class Employee { > private salary; > ...... > public void raiseSalary { > salary += 200; > } > } > > ----------------------- > > public static void tripleSalary (Employee x) { > x.raiseSalary(200); > } > > ----------------------- > > harry = new Emplyee(...); > tipleSalary(harry); > ``` > > 具体的执行过程为: > > - x 被初始化为 `harry `值的拷贝,这里是一个对象的引用。 > - `raiseSalary `方法应用于这个对象引用。x 和 `harry `同时引用的那个 `Employee `对象的薪金提高了 200。 > - 方法结束后,参数变量 x 不再使用。当然,对象变量 `harry `继续引用那个薪金增加 200 的对象。 > > ![](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/20200618153148.png)