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 不再使用。
>
> 
>
> 已经看到,一个方法不可能修改一个基本数据类型的参数。而对象引用作为参数就不同了,可以很容易地修改对象的字段值(比如我们有个 `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 的对象。
>
> 
