Java 基础

JDK 和 JRE

  • JDK 是什么?有哪些内容组成?

    JDK 是 Java 开发工具包

    • JVM 虚拟机: Java 程序运行的地方

    • 核心类库: Java 已经写好的东西,可以直接用

    • 开发工具: Javac、Java、jdb、jhat…

  • JRE 是什么?有哪些内容组成?

    • JRE 是 Java 运行环境
    • JVM、核心类库、运行工具
  • JDK,JRE,JVM三者的包含关系

    • JDK 包含 JRE

    • JRE 包含 JVM

运算符

算术运算符

  • 隐式转换(自动类型提升)

    • 把一个取值范围小的数值,转成取值范围大的数据

    • 取值范围: double > float > long > int > short > byte

    • 取值范围小的,和取值范围大的进行运算,小的会先提升为大的,再进行运算

    • byte short char 三种类型的数据在运算时,都会直接先提升为 int ,然后再进行运算

      1
      2
      3
      byte a = 10;
      byte b = 20;
      数据类型? c = a + b; // a 和 b 为 byte, 在运算时提升为 int, 故此时数据类型为 int.
  • 强制转换

    • 把一个取值范围大的数值,转成取值范围小的数据

    • 目标数据类型 变量名 = (目标数据类型) 被强转的数据;

  • 字符串的 “+” 操作

    • 当 “+” 操作中出现字符串时, 这个 “+” 是字符串连接符, 而不是算术运算符了, 会将前后的数据进行拼接, 并产生一个新的字符串

    • 连续进行 “+” 操作时, 从左到右逐个执行

    • System.out.println(1 + 2 + "abc" + 2 + 1); // "3abc21"

自增自减运算符

  • 参与计算: 后缀(a++ 先用后加), 前缀(++a 先加后用)

逻辑运算符

  • 普通逻辑运算符: &, |, ^, !

  • 短路逻辑运算符: &&, ||

原码反码补码

  • 原码

    • 十进制数据的二进制表现形式, 最左边是符号位, 0为正, 1为负
    • 弊端: 利用原码进行计算时, 如果是正数没有问题, 但如果是负数计算, 结果会出错, 实际运算方向跟正确的运算方向相反
  • 反码

    • 为了解决原码不能计算负数的问题而出现的
    • 正数的反码不变, 负数的反码在原码的基础上, 符号位不变, 数值取反, 0变1, 1变0
    • 弊端: 负数运算时, 如果结果不跨0, 没有问题, 但如果结果跨0, 跟实际结果会有1的偏差
  • 补码

    • 为了解决负数计算时跨0的问题而出现的

    • 正数补码不变, 负数的补码在反码的基础上 +1, 另外补码还能多记录一个特殊的值 -128, 该数据在1个字节下, 没有原码和反码

    • 计算机的存储和计算都是以补码的形式进行的

      image-20250118232514719

该知识可以解释类型转换

其他运算符

运算符 含义 运算规则
& 逻辑与 0为false, 1为true
| 逻辑或 0为false, 1为true
<< 左移 向左移动, 低位补0
>> 右移 向右移动, 高位补0或1(看符号)
>>> 无符号右移 向右移动, 高位补1

判断和循环

switch

  • default不一定写在最下面, 可写在任意位置, 但仍是最后执行

  • case穿透: 首先会拿小括号中表达式的值跟下面每一个case进行匹配, 如果匹配上了, 就会执行对应的语句体, 如果此时发现了break, 那么结束整个switch语句, 如果没发现break, 那么程序会继续执行下一个case的语句体, 一直遇到break或右大括号为止

JDK12新特性:

1
2
3
4
5
6
switch (number) {
case 1 -> System.out.println("1");
case 2 -> System.out.println("2");
case 3 -> System.out.println("3");
default -> System.out.println("无");
}

默认case语句体内有break

  • switch 和 if 的使用场景

    • if: 一般用于对范围的判断
    • switch: 把有限个数据一一列举出来选择

for 与 while 的区别

  • for 循环中, 控制循环的变量, 因为归属 for 循环的语法结构中, 在 for 循环结束后, 就不能再次被访问到了

  • while 循环中, 控制循环的变量, 对于 while 循环来说不归属其语法结构中, 在 while 循环结束后, 该变量还可以继续使用

数组

初始化

  • 在内存中为数组容器开辟空间, 并将数据存入容器中的过程

  • 静态初始化

    • 数据类型[] 数组名 = new 数据类型[] { 元素1, 元素2, 元素3…}
    • 简化后: 数据类型[] 数组名 = { 元素1, 元素2, 元素3…}
    • 范例: int[] array = new int[] {11, 22, 33};
    • 简化后: int[] array = {11, 22, 33};
  • 动态初始化

    • 数据类型[] 数组名 = new 数组类型[数组长度]
    • 范例: int[] array = new int[3];
    • 数组默认初始化规律
      • 整数类型: 默认为 0
      • 小数类型: 默认为 0.0
      • 字符类型: 默认为 ‘/u0000’ (空格)
      • 布尔类型: 默认为 false
      • 引用数据类型: 默认为 null

地址值

  • 数组地址值表示数组在内存中的位置

  • [D@776ec8df 为例

    • [ : 表示当前是一个数组
    • D: 表示当前数组里面的元素都是double类型的
    • @: 表示一个间隔符号 (固定格式)
    • 776ec8df: 数组真正的地址值 (十六进制)

遍历数组

  • 在 IDEA 自动生成数组的遍历方式: 数组名.fori

内存图

  • 栈: 方法运行时使用的内存, 比如 main 方法运行, 进入方法栈中执行

  • 堆: 存储对象或者数组, new 来创建的, 都存储在堆内存中

  • 方法区: 存储可以运行的 class 文件

  • 本地方法栈: JVM 在使用操作系统功能的时候使用, 和我们开发无关

  • 寄存器: 给 CPU 使用, 和我们开发无关

    image-20250118232652565

从JDK8开始, 取消方法区, 新增元空间, 把原来方法区的多种功能进行拆分, 有的功能放到了栈中, 有的功能放到了元空间中

image-20250118232701989

  • 当两个数组指向同一个小空间时, 其中一个数组对小空间中的值发生了改变, 那么其他数组再次访问的时候都是修改之后的结果了

拓展: 思考二维数组内存图 (静态初始化, 动态初始化, 动态初始化的两种特例)

方法

程序中最小的执行单元

形参与实参

  • 形参: 形式参数, 方法定义中的参数

  • 实参: 实际参数, 方法调用中的参数

注意事项

  • 方法之间是平级关系, 不能相互嵌套定义

重载

  • 在同一个类中, 定义了多个同名的方法, 这些同名的方法具有同种功能

  • 每个方法具有不同的参数类型参数个数, 这些同名的方法构成重载关系

  • 同一个类中, 方法名相同, 参数不同的方法. 与返回值无关

    • 参数不同: 个数不同, 类型不同, 顺序不同
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 不构成重载关系, 因为未满足参数不同这个要求
    public class MethodDemo {
    public static void fn(int a) {
    // 方法体
    }
    public static int fn(int a) {
    // 方法体
    }
    }
  • 虚拟机通过参数的不同来区分同名的方法

方法的内存

  • 基本数据类型: 整数类型, 浮点数类型, 布尔类型, 字符类型

    • 数据值是存储在自己的空间中
    • 赋值给其他变量, 也是赋值真实的值
  • 引用数据类型: 需要 new 创造的

    • 数据值是存储在其他空间中, 自己空间中存储的是地址值
    • 赋值给其他变量, 赋值的是地址值

方法的值传递

  • 传递基本数据类型的内存原理

    • 传递基本数据类型时, 传递的是真实的数据, 形参的改变, 不影响实参的值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public class ArgsDemo01 {
      public static void main(String[] args) {
      int number = 100;
      sout("调用change方法前: " + number);
      change(number);
      sout("调用change方法后: " + number);
      }
      public static void change(int number) {
      number = 200;
      }
      }
      /*
      输出结果为:
      调用change方法前: 100
      调用change方法后: 100
      */
  • 传递引用数据类型的内存原理

    • 传递引用数据类型时, 传递的是地址值, 形参的改变, 影响实参的值

以上内容依据内存图来理解

键盘录入

  • 第一套体系

    • nextInt() : 接收整数

    • nextDouble() : 接收小数

    • next() : 接受字符串

      键盘录入的字符串是 new 创建的

    • 遇到空格、制表符、回车就停止接收,这些符号后面的数据就不会接受了

  • 第二套体系

    • nextLine() : 接受字符串
    • 遇到空格、制表符可以接收,遇到回车才停止