• 欢迎光临~

JavaSE2️⃣程序基础(上)

开发技术 开发技术 2022-12-17 次浏览

需要了解的计算机基础知识:👉 存储单位 & 数值表示

  1. 存储单位
    1. bit(位):描述电脑数据量的最小单位。
    2. byte(字节):计算机内存的最小存储单位(1byte = 8bit)。
  2. 数值表示:计算机中正负数的表示,即符号位的含义。

1、程序基本结构

针对 HelloWorld 程序,分析 Java 程序基本结构。

  1. :Java 程序的基本单位(即 class 关键字)。

    1. 命名要求:英文字母开头,字母、数字、下划线组合。
    2. 命名规范:大驼峰命名。
  2. 方法:定义一组执行语句,代码会依次顺序执行。

    1. 命名要求:英文字母开头,字母、数字、下划线组合。
    2. 命名规范:小驼峰命名。
    3. main 方法:程序的主入口。
  3. 注释:标注代码,提高代码可读性。

    1. 单行注释

    2. 多行注释

    3. 文档注释:用于类和方法的定义处,可用于自动生成文档(JavaDoc)。

      /**
       * 文档注释
       *
       * @author Jaywee
       * @date 2022/12/12
       */
      public class Hello {
          public static void main(String[] args) {
              /*
              多行注释
              */
      
              // 单行注释
              System.out.println("Hello World!");
          }
      }
      

2、变量 & 数据类型

2.1、变量

2.1.1、说明

  1. 类型:基本变量、引用变量。
  2. 使用:先定义后使用。
    1. 定义时可以赋初始值,定义后可以重新赋值。
    2. 可以赋值,也可以赋变量。

2.1.2、示例

针对以下代码,分析 JVM 执行操作。

// 定义变量
int x;
int y = 1;

// 修改变量值
x = 10;
y = x;
  1. int x;

    1. 语句:定义变量 x,没有显式赋值(但 int 类型默认值 0);

    2. JVM 操作:分配一个存储单元,变量 x 指向该存储单元。

            x
            │
            ▼
      ┌───┬───┬───┬───┬───┬───┬───┐
      │   │ 0 │   │   │   │   │   │
      └───┴───┴───┴───┴───┴───┴───┘
      
  2. int y = 1;

    1. 语句:定义变量 y,赋值 1;

    2. JVM 操作:分配一个存储单元,变量 y 指向该存储单元。

            x       y
            │       │
            ▼       ▼
      ┌───┬───┬───┬───┬───┬───┬───┐
      │   │ 0 │   │ 1 │   │   │   │
      └───┴───┴───┴───┴───┴───┴───┘
      
  3. x = 10;

    1. 语句:将变量 x 的值赋为 10;

    2. JVM 操作:找到变量 x 的存储单元,移除原来的值 0,放入新的值10。

             x       y
             │       │
             ▼       ▼
      ┌───┬────┬───┬───┬───┬───┬───┐
      │   │ 10 │   │ 1 │   │   │   │
      └───┴────┴───┴───┴───┴───┴───┘
      
  4. y = x;

    1. 语句:将变量 y 的值赋为变量 x 的值。

    2. JVM 操作:找到变量 y 的存储单元,移除原来的值 1,放入新的值 10(还包含查找 x = 10 的过程)。

             x        y
             │        │
             ▼        ▼
      ┌───┬────┬───┬────┬───┬───┬───┐
      │   │ 10 │   │ 10 │   │   │   │
      └───┴────┴───┴────┴───┴───┴───┘
      

2.2、数据类型

2.2.1、八大基本类型

基本数据类型:CPU 可直接进行运算的类型。

含义 内存(byte) 范围 默认值
byte 字节 1 [-27 , 27 -1] 0
short 短整型 2 [-215, 215 - 1] 0
int 整型 4 [-231, 231 - 1] 0
long 长整型 8 [-263, 263 - 1] 0
float 单精度浮点型 4 [1.4 & 10-45, 3.4 * 1038] 0.0
double 双精度浮点型 8 [4.9 * 10-324, 1.79 * 10308] 0.0
char 字符 2 [0, 216 - 1] ''(空)
boolean 布尔 理论 1bit,实际通常 4byte {true, false} false

使用

// byte
byte num1 = -100;
// short
short num2 = 300;
// int
int num3 = 200_000_000;
// long:赋值需要以 L 结尾
long num4 = 1L;

// float:赋值需要以 F 结尾
float num5 = -1.0F;
// double
double num6 = 3.14;

// char:以单引号赋值,即使是空字符
char ch1 = 'A';
char ch2 = '好';
char ch3 = '';

// boolean
boolean flag = true;
boolean isGreater = 10 > 9;

2.2.2、引用类型

除了八大基本类型,其它都是引用类型。

最常用的引用类型是 String(字符串)。

  1. 变量:存放在中,内部存储了对象实例在堆中的内存地址。

  2. 实例:存放在中。

    引用类型 变量名 = new 对象实例();
    Object obj = new Object();
    

2.2.3、说明

  1. 变量的作用域

    1. 语句块:Java 中使用 {} 包围语句块,作为一组完整代码(如类、方法、控制语句)。
    2. 作用域:从变量的声明位置开始,到变量所在语句块结束
    3. 说明:尽量将变量的作用域最小化,且避免使用重复的变量名。
  2. 常量:需要显式初始化,并且无法再次赋值,否则报错。

    1. 定义:定义变量时使用 final 修饰符。
    2. 作用:提前声明变量名,避免在代码中使用魔法值(Magic Number)。
  3. var 关键字:省略变量类型,由编译器自动推断。

    // 示例
    var sb = new StringBuilder();
    // 编译器自动推断为以下语句
    StringBuilder sb = new StringBuilder();
    

3、运算

3.1、整数运算

整数:表示的是精确的数,其运算结果也是精确的整数。

3.1.1、运算符

① 基本运算符

  1. 运算符

    1. 符号:加 +,减 -,乘 *,除 /,取余 %

    2. 除法 / 结果取整数部分,取余 % 结果取余数部分。

    3. 除数若为 0,编译通过但运行时报错。

      java.lang.ArithmeticException: / by zero
      
  2. 运算符简写

    1. 符号+=-=*=/=%=

    2. 使用

      x += 10;
      // 等价于
      x = x + 10;
      
  3. 自增/自减:本质也是运算符简写

    1. 符号++--

    2. 使用:符号可以在变量之前或之后,其位置表示自增的顺序。

      1. 符号在前:先自增,后引用。

      2. 符号在后:先引用,后自增。

        int x = 1;
        int y = 2;
        
        // 情况1:y先自增成3,后引用;x=3+10=13
        x = ++y + 10;
        // 情况2:先引用y,x=2+10=12;后y自增成3
        x = y++ + 10;
        
        // 结论:y最终结果都是3,但运算符位置不同导致引用和自增顺序不同,因此x结果不同
        

② 特殊运算符

  1. 移位运算:将整数对应的二进制数进行移动。

    1. 左移<<

    2. 右移>>(符号位不会移动)

    3. 无符号右移>>>(符号位也移动,高位自动补 0)

      // 右移
      int n = -536870912; // 11100000 00000000 00000000 00000000 = -536870912
      int a = n >> 1;  	// 11110000 00000000 00000000 00000000 = -268435456
      int b = n >> 2;  	// 11111000 00000000 00000000 00000000 = -134217728
      int c = n >> 28; 	// 11111111 11111111 11111111 11111110 = -2
      int d = n >> 29;	// 11111111 11111111 11111111 11111111 = -1
      
      // 无符号右移
      int n = -536870912; // 11100000 00000000 00000000 00000000 = -536870912
      int a = n >>> 1;  	// 01110000 00000000 00000000 00000000 = 1879048192
      int b = n >>> 2; 	// 00111000 00000000 00000000 00000000 = 939524096
      int c = n >>> 29; 	// 00000000 00000000 00000000 00000111 = 7
      int d = n >>> 31; 	// 00000000 00000000 00000000 00000001 = 1
      
      // 对byte和short进行位移时,会先转换为int
      // 本质:左移即 * 2,右移即 / 2
      
  2. 位运算:将整数对应的二进制数按位对齐,依次运算。

    1. :全 1 才 1。
    2. :有 1 则 1。
    3. :01 互换。
    4. 异或:同 0 异 1。

3.1.2、说明

① 运算符优先级

  1. ():优先级最高,可用来改变运算顺序,提高可读性。
  2. ! ~ ++ --
  3. * / %
  4. + -
  5. << >> >>>
  6. &
  7. |
  8. += -= *= /= %=

② 溢出

溢出:若计算结果超过了整数范围,不会报错,但会导致溢出。

  1. 原理:将整数转换为二进制运算,其最高位计算结果变成 1,导致符号改变。
  2. 解决方案:改用更大范围的整数类型,如 int 改成 long。

③ 转型

  1. 类型自动提升:若参与运算的两个数类型不一致,会先自动转型为较大类型。

    short num1 = 1;
    int num2 = 10;
    // short先自动转型为int,再参与运算
    System.out.println(num1 + num2);
    
  2. 强制转型:将大类型的整数强制转为小范围的整数。

    1. 使用(类型)

    2. 注意:以 int 和 short 为例,若 int 整数超出了 short 类型,强制转型时会丢弃 2 个高位字节,可能导致错误结果。

      // 正确结果
      int num1 = 10;
      short num2 = (short) num1; // 10
      
      // 错误结果
      int num1 = 12345678;
      short num2 = (short) num1; // 24910
      

3.2、浮点数运算

浮点数:通常无法精确表示,其运算结果也是如此。

3.2.1、运算符

  1. 支持的运算符

    1. 四则运算:加 +,减 -,乘 *,除 /(含简写形式 +=-=*=/=%=
    2. 自增/自减++--
  2. 不支持的运算符

    1. 取余
    2. 移位
    3. 位运算

3.2.2、说明

① 误差

  1. 由于浮点数无法精确表示,因此容易产生误差。

    double num1 = 1.0 / 10;
    double num2 = 1 - 9.0 / 10;
    
    // 观察x和y是否相等
    System.out.println(x);
    System.out.println(y);
    
  2. 由于误差的存在,判断浮点数是否相等的依据是二者之差小于一个很小的数。

    // 二者之差的绝对值
    double diff = Math.abs(x - y);
    
    if (r < 0.00001) {
        // 认为相等
    }
    

② 溢出

  1. 整数运算 / 0 会报错,浮点数运算 / 0 不会报错。

  2. IEEE-754 规定,浮点数 /0 结果需要是 NaN(Not a Number)或 Infinity(无穷大)。

    double num1 = 0.0/0;	// NaN
    double num2 = 1.0/0;	// Infinity
    double num2 = -1.0/0	// -Infinity1
    

③ 转型

  1. 类型提升:整数与浮点数参与同一则运算时,整数通常会自动转型为浮点型。

    // 情况1:自动转型
    int num = 1;
    // int自动转为double,再参与运算
    System.out.println(24.1 / num);
    
    // 情况2:不会自动转型
    int num1 = 20, num2 = 4;
    /*
        num1和num2没有直接与浮点数运算,因此不会转型。
        按整数运算得到结果5,5会自动转型为double
    */
    System.out.println(3.4 + num1 / num2);
    
  2. 强制转型:浮点数可以强制转型为整数。

    1. 浮点数的小数部分会被丢弃。

    2. 四舍五入:强制转型之前,对浮点数加上 0.5。

    3. 若转型后超出整型的最大范围,将返回该整型的最大值。

      // 丢弃小数部分
      int n1 = (int) -3.4; // -3
      int n2 = (int) 5.7;  // 5
      // 四舍五入:转型前+0.5
      int n3 = (int) (5.7 + 0.5); // 6
      // 超出范围:自动返回最大值
      int n4 = (int) 1.2e20; // 2147483647
      

3.3、布尔运算

布尔运算:布尔运算是一种关系运算,结果只有 true 和 false。

3.3.1、运算符

  1. 比较运算符>>=<<===!=

  2. 逻辑运算符

    1. &, &&

    2. |, ||

    3. !

      boolean flag1 = 1 > 2;	// false
      boolean flag2 = 2 >= 1; // true
      
      boolean flag3 = flag1 && flag2;	// false
      boolean flag4 = flag1 || flag2;	// true
      boolean flag5 = !flag4;			// false
      

3.3.2、说明

① 优先级

  • !
  • >>=<<=
  • ==!=
  • &&
  • ||

② 短路运算

短路运算:若布尔运算的表达式能提前确定结果,则不会判断后续条件,直接返回结果。

  1. 短路运算符&&||

  2. 优点:提高性能。

    // 非短路运算:计算后面的表达式时报错
    boolean result1 = false & (7 / 0 > 1);
    
    // 短路运算:第一个false可确定结果为false,直接返回结果,不会报错
    boolean result2 = false && (7 / 0 > 1);
    

④ 三目运算符

三目运算符:根据布尔表达式的结果,返回后续两个表达式之一的计算结果。

  1. 格式布尔表达式 ? 表达式1 : 表达式2

  2. 示例

    // 取两数中的最大值
    int num1 = 20;
    int num2 = 10;
    
    int result = num1 >= num2 ? num1 : num2;
    

4、字符 & 字符串

4.1、char

char(character):字符,基本类型。

  1. 形式:单引号 ''

  2. Java 使用 Unicode 表示中/英文字符,一个 char 占用 2 个字节。

  3. 可将 char 赋值给整数,整数值为 char十进制 Unicode 编码。

  4. 可用转义字符 u十六进制 Unicode 编码表示字符。

    char ch1 = 'A';
    char ch2 = '好';
    
    int num1 = ch1;   // 65
    int num2 = ch2;	  // 22909
    
    char ch3 = 'u0041';	// A
    char ch4 = 'u597D';	// 好
    

4.2、String

4.2.1、说明

String:字符串,引用类型。

  1. 形式:双引号 ""

  2. 底层实现String 本质是 char 数组,一个 String 可以存储任意个字符。

  3. 特点不可变性,即字符串对象创建后无法改变。

    1. 含义:修改字符串时,JVM 会创建新的字符串,并修改变量的引用。
    2. 原因:String 底层的 char 数组用 final 修饰。
  4. 特殊值null""

    1. null(空值):任何引用对象都可指向 null,表示不存在。

    2. ""(空串):值为空的有效字符串对象,不等同于 null。

      String str1 = "ABC";
      String str2 = null;
      String str3 = "";
      

4.2.2、转义字符

  1. 若字符串中存在特殊符号,则需要使用转义字符 ,避免识别错误。

  2. 常用转义字符

    转义字符 真实含义
    " "
    ' '
    \
    n 换行
    r 回车
    t tab
    u#### Unicode 字符
  3. 示例

    // 三个字符:A 换行符 好
    String str = "Anu597D";
    

4.2.3、相关操作

  1. 字符串拼接:使用 +,可将 String 与任意数据类型连接。

    1. 好处:简化字符串处理操作。
    2. 说明:连接之前,其它数据类型会先自动转型为 String
  2. 多行字符串:两种形式。

    1. 使用 + 拼接。

    2. 使用一对 """ 包围(Java 13 引入)。

      String str1 = "SELECT * " +
          "FROM tb_user" +
          "WHERE id = 1;";
      
      String str2 = """
          SELECT *
          FROM tb_user
          WHERE id = 1;
      """;
      

5、数组

数组(array):相同类型数据的有序集合。

5.1、一维数组

5.1.1、语法

格式数据类型[] 定义数组,new 关键字初始化。

  1. 动态初始化:指定数组长度。

  2. 静态初始化:指定内容,由 Java 推断数组长度。

    // 动态
    int[] nums1 = new int[3];
    
    // 静态
    int[] nums2 = new int[] {83, 97, 62};
    int[] nums3 = {83, 97, 62};
    

5.1.2、访问数组

  1. 数组元素数组名[索引],索引从 0 开始。

  2. 数组长度数组名.length

    int[] nums = new int[5];
    
    // 读
    System.out.println(nums[0]);	// 0
    // 写
    nums[0] = 100;
    
    // 长度
    System.out.println(nums.length);	// 5
    

5.1.3、特点

  1. 类型:数组是引用类型。
  2. 容量大小:数组一旦创建,容量不可变。
  3. 数组初始化后,所有元素都是默认值(基本类型对应默认值,引用类型 null)。
  4. 下标越界:若访问数组元素时索引超出范围,会报错 IndexOutOfBoundsException

5.2、引用关系

数组是引用类型。

变量保存了实例在堆中的内存地址,是对数组内存地址的引用。

5.3.1、基本类型

以 int 数组为例

int[] ns = new int[] {1, 2, 3, 4};

ns = new int[] {10, 20, 30};
  1. 初始化 ns:在堆内存开辟一块连续的内存空间,初始化数组。

         ns
          │
          ▼
    ┌───┬───┬───┬───┬───┬───┐
    │   │ 1 │ 2 │ 3 │ 4 │   │
    └───┴───┴───┴───┴───┴───┘
    
  2. 重新赋值:在堆内存开辟另一块连续的内存空间,初始化数组。

    原数组没有改变,而是修改了变量引用

         ns ──────────────────────┐
                                  │
                                  ▼
    ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐───┐
    │   │ 1 │ 2 │ 3 │ 4 │   │   │10 │20 │30 │   │
    └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘───┘
    

5.3.2、引用类型

以 String 数组为例

String[] arrays = {"AA", "BB", "CC"}

arrays[1] = "XX";
  1. 初始化 arrays:在内存开辟一块连续的内存空间,初始化数组。

    (数组元素是引用类型,指向内存中的对象实例)

              ┌─────────────┐
       arrays │   ┌─────────┼───────────────────────┐
          │   │   │         │                       │
          ▼   │   │         ▼                       ▼
    ┌───┬───┬─┴─┬─┴─┬───┬──────┬───┬──────┬───┬──────┬───┐
    │   │░░░│░░░│░░░│   │ "BB" │   │ "AA" │   │ "CC" │   │
    └───┴─┬─┴───┴───┴───┴──────┴───┴──────┴───┴──────┴───┘
          │                           ▲
          └───────────────────────────┘
    
  2. 赋值:在内存中创建新的 String 实例,修改属性的引用。

              ┌─────────────────────────────────────────────┐
       arrays │   ┌──────────────────────────────┐          │
          │   │   │                              │          │
          ▼   │   │                              ▼          ▼
    ┌───┬───┬─┴─┬─┴─┬───┬──────┬───┬──────┬───┬──────┬───┬──────┬───┐
    │   │░░░│░░░│░░░│   │ "BB" │   │ "AA" │   │ "CC" │   │ "XX" │   │
    └───┴─┬─┴───┴───┴───┴──────┴───┴──────┴───┴──────┴───┴──────┴───┘
          │                           ▲
          └───────────────────────────┘
    

Hint:数组本身是引用类型。

相比基本类型数组,引用类型数组多了一层指向关系。

5.3、多维数组

多维数组:一维数组的拓展,常见的是二维和三维数组。

语法、使用方式等基本相同。

5.3.1、二维数组

二维数组:一维数组的数组。

即每个数组元素是一维数组。

  1. 语法数组类型[][],支持动态、静态初始化。
  2. 访问数组
    1. 数组元素数组名[行索引][列索引],索引从 0 开始。
    2. 数组长度
      1. 行数数组名.length
      2. 列数数组名[行索引].length
  3. 特点
    1. Java 高维数组,允许不同数组的长度不同。
    2. 其它特点同一维数组。

示例

  1. 代码

    // 初始化
    int[][] nums = {
        {1, 2, 3},
        {4, 5, 6, 7},
        {8, 9}
    };
    
    // 访问数组元素
    System.out.println(nums[1][3]);	// 7
    // 数组长度
    System.out.println(nums.length);	// 3
    System.out.println(nums[1].length);	// 4
    
  2. 结构示意

                        ┌───┬───┬───┐
             ┌───┐  ┌──▶│ 1 │ 2 │ 3 │
    ns ─────▶│░░░│──┘   └───┴───┴───┘
             ├───┤      ┌───┬───┬───┬───┐
             │░░░│─────▶│ 4 │ 5 │ 6 │ 7 │
             ├───┤      └───┴───┴───┴───┘
             │░░░│──┐   ┌───┬───┐
             └───┘  └──▶│ 8 │ 9 │
                        └───┴───┘
    

5.3.2、三维数组

三维数组:二维数组的数组。

即每个数组元素是二维数组。

  1. 语法数组类型[][][],支持动态、静态初始化。
  2. 访问数组
    1. 数组元素数组名[索引][行索引][列索引],索引从 0 开始。
    2. 数组长度:类比二维数组。
    3. 遍历:推荐使用 Arrays.deepToString
  3. 特点
    1. 在实际应用中,通常最多使用二维数组,很少使用更高数组。
    2. 其它特点同二维数组。

示例

  1. 初始化并访问

    int[][][] nums = {
        {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        },
        {
            {10, 11},
            {12, 13}
        }
    };
    
    // 访问数组元素
    System.out.println(nums[0][1][2]);	// 6
    // 数组长度
    System.out.println(nums.length);	// 2
    
  2. 结构示意

                                  ┌───┬───┬───┐
                       ┌───┐  ┌──▶│ 1 │ 2 │ 3 │
                   ┌──▶│░░░│──┘   └───┴───┴───┘
                   │   ├───┤      ┌───┬───┬───┐
                   │   │░░░│─────▶│ 4 │ 5 │ 6 │
                   │   ├───┤      └───┴───┴───┘
                   │   │░░░│──┐   ┌───┬───┬───┐
            ┌───┐  │   └───┘  └──▶│ 7 │ 8 │ 9 │
    ns ────▶│░░░│──┘              └───┴───┴───┘
            ├───┤      ┌───┐      ┌───┬───┐
            │░░░│─────▶│░░░│─────▶│10 │11 │
            └───┘      ├───┤      └───┴───┘
                       │░░░│──┐   ┌───┬───┐
                       └───┘  └──▶│12 │13 │
                                  └───┴───┘
    
程序员灯塔
转载请注明原文链接:JavaSE2️⃣程序基础(上)
喜欢 (0)