bit与byte

  • 计算机就是一系列的电路开关,每个开关会存在2种状态:off(关)和on(开) 如果电路是开的,则值为1;如果电路是关的,它的值是0 [这个部分会在计算机组成原理去更详细的解释]
  • 一个0或者一个1存储为一个比特(bit),是计算机中最小的存储单位。二进制 0 和 1
  • 计算机中基本的存储单元是字节(byte),每个字节由8个比特构成,比特是最基本的计算单位。所有的命令、代码、页面等等各种你在电脑上、手机上、终端上的操作都会转化为字节的运算。但是字节的计算本质是二进制比特的计算。
  • 1Byte = 8bit
  • 1KB = 1024 byte
  • 1MG = 1024 kb
  • 1GB = 1024 mg
  • 1TB = 1024 GB

    内存

  • 一个程序和它的数据在CPU中执行前必须移到计算机的内存中,也就是说,所有的计算操作都是在内存中进行的。那我们在之后的编码中,可以通过数据计算出执行此逻辑需要的内存,并且可以制造出某些JVM异常的原因。

  • 每个字节都有唯一的地址。会用地址确定字节的位置,便于存储和获取数据。
  • 如果想要加载数据,需要从硬盘 -> 内存 -> CPU
  • 内存数据:断电消失
  • 硬盘数据:持久保存
  • 这里后期会涉及到 数据一致性的处理

    Java基础知识图解

    image.png

    最基础部分

    Java的优势

  • 简单性:简单的都是基本功,难以处理和理解的是业务。业务是有明确的上下文,深知业务可以更好的编排代码。所以,Java是简单的。并且Java的垃圾回收器已经比较完善了,有很多强大的功能。需要程序员手动去管理内存的很少了,且Java生态非常强悍和成熟。

  • 可移植性:Java 先编译生成字节码,再由 JVM(Java 虚拟机)来解释执行,目的就是将统一的字节码转成操作系统可以识别的二进制码,然后执行。而针对不同的操作系统,都有相应版本的 JVM,所以 Java 就实现了可移植性。
  • 安全性:Java适用于网络和分布式环境,Java可以构建防病毒、防篡改的应用程序。
    • 运行时堆栈溢出,这是蠕虫病毒常用的攻击手段。
    • 字节码验证,可以确保代码符合 JVM 规范并防止恶意代码破坏运行时环境。
    • 安全的类加载,可以防止不受信任的代码干扰 Java 程序的运行。
    • 全面的 API 支持广泛的加密服务,包括数字签名、消息摘要、(对称、非对称)密码、密钥生成器。
    • 安全通信,支持 HTTPS、SSL,保护传输的数据完整性和隐私性。
  • 并发性:多线程支持十分强悍。
  • 对多个领域都有突出的表现:大数据、金融服务领域、物联网(IoT)领域、Web领域

    Java跨平台的机制

  • Java跨平台的机制在于其将Java文件编译成所有Java虚拟机可以识别的class文件,类似在方法论中提到的去差异化设计。

  • Java虚拟机是和平台有关的,因为不同操作系统存在不同的JDK,但是这些JDK都能保证识别所有的由其他JDK或者是自身JDK编译出来的class文件。这样一来,开源的JDK和非开源的JDK都要遵循一定的标准,要表达的意思就是,所有的”服务提供方“都要遵守”输出“的契约。这样才能够保证所有的class是完全通用的。
  • 所有的class文件都需要运行在JDK之上,其JDK是跨平台的,可以理解为将Java代码的编译层和执行层进行了一次封装。
  • “契约精神”:约定大于编码。

    JDK和JRE和JVM

  • JDK:Java Development Kit 是Java开发工具包。其范围最大,包含JRE和JVM。其也会包含一些指令等,比如编译指令等。

  • JRE:Java Runtime Environment 是Java运行时环境,包括 JRE 所有内容,以及开发应用程序所需的编译器和调试器等工具。JRE 提供了库、Java 虚拟机(JVM)和其他组件,用于运行 Java 编程语言、小程序、应用程序。如果你的机器上不需要将Java文件编译成class文件,那么只需要安装JRE即可,但是这种情况现在已经不存在,因为CI/CD工作流 自动化拉取代码、编译、执行、部署 需要,而且安装完整的JDK几乎没有成本。
  • JVM:Java Virtual Machine 是Java虚拟机,整个Java的的核心,JVM可以理解为是一个虚拟出来的计算机,具备着计算机的基本运算方式,它主要负责把 Java 程序生成的字节码文件,解释成具体系统平台上的机器指令,让其在各个平台运行。

image.png

  • 一些命令行

    • javac:编译Java文件到class文件;
    • keytool:用于操作 keystore 密钥;
    • javap:class 类文件的最基础的反编译器;
    • jstack:用于打印 Java 线程栈踪迹的工具;
    • jconsole:用于监视 Java 程序的工具;
    • jhat:用于 Java 堆分析的工具
    • jar:用于打包 Java 程序的工具;
    • javadoc:用于生成 Java 文档的工具;

      关键字

  • 关键字,是Java中已经定义的,只能Java来使用。其中大部分已经使用,少部分没有使用,称为保留字。

  • 所有的关键字如下 | Java关键字类别 | Java关键字 | 关键字含义 | | —- | —- | —- | | 访问控制 | private | 一种访问控制方式:私用模式,访问控制修饰符,可以应用于类、方法或字段(在类中声明的变量) | | 访问控制 | default | 一种访问控制方式:缺省模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符 | | 访问控制 | protected | 一种访问控制方式:保护模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符 | | 访问控制 | public | 一种访问控制方式:共用模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。 | | 类、方法和变量修饰符 | abstract | 表明类或者成员方法具有抽象属性,用于修改类或方法 | | 类、方法和变量修饰符 | class | 声明一个类,用来声明新的Java类 | | 类、方法和变量修饰符 | extends | 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口 | | 类、方法和变量修饰符 | final | 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量 | | 类、方法和变量修饰符 | implements | 表明一个类实现了给定的接口 | | 类、方法和变量修饰符 | interface | 接口 | | 类、方法和变量修饰符 | native | 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的 | | 类、方法和变量修饰符 | new | 用来创建新实例对象 | | 类、方法和变量修饰符 | static | 表明具有静态属性 | | 类、方法和变量修饰符 | strictfp | 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范 | | 类、方法和变量修饰符 | synchronized | 表明一段代码需要同步执行 | | 类、方法和变量修饰符 | transient | 声明不用序列化的成员域 | | 类、方法和变量修饰符 | volatile | 表明两个或者多个变量必须同步地发生变化 | | 程序控制 | break | 提前跳出一个块 | | 程序控制 | continue | 回到一个块的开始处 | | 程序控制 | return | 从成员方法中返回数据 | | 程序控制 | do | 用在do-while循环结构中 | | 程序控制 | while | 用在循环结构中 | | 程序控制 | if | 条件语句的引导词 | | 程序控制 | else | 用在条件语句中,表明当条件不成立时的分支 | | 程序控制 | for | 一种循环结构的引导词 | | 程序控制 | instanceof | 用来测试一个对象是否是指定类型的实例对象 | | 程序控制 | switch | 分支语句结构的引导词 | | 程序控制 | case | 用在switch语句之中,表示其中的一个分支 | | 程序控制 | default | 默认,例如:用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现 | | 错误处理 | try | 尝试一个可能抛出异常的程序块 | | 错误处理 | catch | 用在异常处理中,用来捕捉异常 | | 错误处理 | finally | 用在捕获异常的格式中,放在最后 | | 错误处理 | throw | 抛出一个异常 | | 错误处理 | throws | 声明在当前定义的成员方法中所有需要抛出的异常 | | 包相关 | import | 表明要访问指定的类或包 | | 包相关 | package | 包 | | 基本类型 | boolean | 基本数据类型之一,声明布尔类型的关键字 | | 基本类型 | byte | 基本数据类型之一,字节类型 | | 基本类型 | char | 基本数据类型之一,字符类型 | | 基本类型 | double | 基本数据类型之一,双精度浮点数类型 | | 基本类型 | float | 基本数据类型之一,单精度浮点数类型 | | 基本类型 | int | 基本数据类型之一,整数类型 | | 基本类型 | long | 基本数据类型之一,长整数类型 | | 基本类型 | short | 基本数据类型之一,短整数类型 | | 基本类型 | null | 空,表示无值,不能将null赋给原始类型(byte、short、int、long、char、float、double、boolean)变量 | | 基本类型 | true | 真,boolean变量的两个合法值中的一个 | | 基本类型 | false | 假,boolean变量的两个合法值之一 | | 变量引用 | super | 表明当前对象的父类型的引用或者父类型的构造方法 | | 变量引用 | this | 指向当前实例对象的引用,用于引用当前实例 | | 变量引用 | void | 声明当前成员方法没有返回值,void可以用作方法的返回类型,以指示该方法不返回值 | | 保留字 | goto | 保留关键字,没有具体含义 | | 保留字 | const | 保留关键字,没有具体含义,是一个类型修饰符,使用const声明的对象不能更新 |

数据类型

  • Java中的数据类型可以分为2种,一种是基本数据类型,一种是引用数据类型。
  • 基本数据类型是 Java 语言操作数据的基础,包括 boolean、char、byte、short、int、long、float 和 double,共 8 种。
  • 引用数据类型,除了基本数据类型,其他的都是引用数据类型。这里使用《Java编程思想:第四版》的比喻:将对象引用比喻为遥控器,将其能够操控的电视机比喻为对象,那么使用遥控器可以操作电视机(对象引用操作对象实际的地址以及其数据)。

🎉 基础篇 - 图3

  • 数据类型的大小 | 数据类型 | 默认值 | 大小 | | —- | —- | —- | | boolean | false | 1比特 | | char | ‘\u0000’ | 2字节 | | byte | 0 | 1字节 | | short | 0 | 2字节 | | int | 0 | 4字节 | | long | 0L | 8字节 | | float | 0.0f | 4字节 | | double | 0.0 | 8字节 |

  • char为啥是2个字节,这和JDK的编码有关。JDK内部使用UFT-16编码。(详细了解参见文末参考资料)

  • 比较常见或者说是比较难以理解的问题是long的大小为8字节,float的大小为4字节。
  • Java中long类型占8字节,1字节=8位(1byte=8bit)也就是64位,每一位都有0和1两种状态,64位也就可以表示2^64个状态,也就是2^64个数,而long类型是有符号的(分正负),负数用-2^63至-1表示,正数用0至2^63-1表示,加起来正是2^64个数。
  • Java中float占4字节,但是其表达的数值范围大于long类型,这是为啥呢。
    • 一个字节是8个二进制位,4个字节就是32个二进制位。
    • 最左边的一位表示符号位。
    • 最后面23位表示尾数(小数位,最大无限接近于1)
    • 剩下的8位,为指数位:注意,是指数位置,是放在右上角的位置的。如2的4次方。二进制表示为 00000000~11111111 取值范围是0~255。
    • 根据IEEE 754规定,其中0代表0,255代表无限大。去除这两个值,中间的范围是1~254。
    • 且每个指数要减去127,所以范围是:-126~127 即最大为2^127。 远远大于long类型的最大值:2^63-1
  • boolean:仅仅用来存储2个值:true或者false
  • byte:byte的取值范围在 -128 ~ 127 之间。包含-128 和 127 默认值为0。比较特殊的就是 -128 的由来,规定 1000 0000 为 -128

image.png

  • short:取值范围在 -32768 ~ 32767 之间。包含-32768 和 32767 默认值为0
  • int:取值范围在 -2,147,483,648(-2^31)~ 2,147,483,647(2^31 - 1)之间 默认值为0
  • long:-9,223,372,036,854,775,808(-2^63) 和 9,223,372,036,854,775,807(2^63 -1)之间,包含最大值和最小值,默认值为 0。为了和int进行区分,当定义long类型的时候,必须使用大写的L作为末尾声明。禁止使用小写的l。

    1. long startTime = 0L;
    2. long endTime = 100000L;
  • float:单精度的浮点数。遵循IEEE 754标准(二进制浮点数算术标准:参见文末参考资料链接),取值范围是无限的,默认值为 0.0f 这里float类型,强制带上小写的f。当然大写的F也可以,但是小写的已经足够了。数学计算严禁使用float进行计算,会有损失精度的问题。如需使用,使用BigDecimal进行计算,且必须使用 new BigDecimal(String str) 类型的构造函数。

  • double:双精度的浮点数。遵循IEEE 754标准(二进制浮点数算术标准:参见文末参考资料链接) 数学计算严禁使用double进行计算,会有损失精度的问题。如需使用,使用BigDecimal进行计算,且必须使用 new BigDecimal(String str) 类型的构造函数。
  • char:可以表示一个 16 位的 Unicode 字符,其值范围在 ‘\u0000’(0)和 ‘\uffff’(65,535)之间,使用 单引号包起来的 ‘’
  • 引用数据类型:引用数据类型的默认值全部为null。
  • 引用数据类型的引用,也就是上文提到的遥控器,其是放在栈中的,而被引用的对象,也就是电视机,其是放在堆中的。在Java执行的过程中,需要知道其需要执行的所有的数据的生命周期,其能够编译通过,则其class文件就可以在不被破坏的情况下,正确的被执行。代码块的执行,和代码的执行,我们在后面学习JVM的时候进行深入探讨。
  • 引用数据类型的地址,可以通过toString方法来打印,如下

    1. public class Object {
    2. // 略过其他方法
    3. public String toString() {
    4. return getClass().getName() + "@" + Integer.toHexString(hashCode());
    5. }
    6. }
  • Java中所有的类都继承自Object类,如果子类没有重写toString方法,则会执行父类的toString方法。其实就是打印个哈希值地址。

  • 这里会涉及到一个经常面试会问到的问题,为什么要重写equals和hashcode方法。这个地方我们讲到集合框架的时候会具体的进行分析。通过debug源码的方式进行分析。

    String

  • String是一种特殊的引用类型。可以看一下他的源码

    1. public final class String
    2. implements java.io.Serializable, Comparable<String>, CharSequence {
    3. /** The value is used for character storage. */
    4. private final char value[];
    5. }
  • 是有final修饰的,表示其是终类,不可被继承、不可被修改。

  • 字符串比较复杂,其和JVM相关,会有这样的面试题:为什么String是final修饰的?后续我们看源码的时候,会解决一部分问题,在讲解JVM的时候,会解决剩下的问题。

    运算符

  • 运算符分类如下

🎉 基础篇 - 图5

  • 算术运算符
  • 算术运算符除了最常见的加减乘除,还有一个取余的运算符,用于得到除法运算后的余数,来串代码感受下。 ```java public class ArithmeticOperator { public static void main(String[] args) {

    1. int a = 10;
    2. int b = 5;
    3. System.out.println(a + b);//15
    4. System.out.println(a - b);//5
    5. System.out.println(a * b);//50
    6. System.out.println(a / b);//2
    7. System.out.println(a % b);//0
    8. b = 3;
    9. System.out.println(a + b);//13
    10. System.out.println(a - b);//7
    11. System.out.println(a * b);//30
    12. System.out.println(a / b);//3
    13. System.out.println(a % b);//1

    } }


- 加法(+)、减法(-)、乘法(*)很好理解,但除法(/)和取余(%)比较特殊。因为数字在程序中分为2种,浮点型和整型。如果都是整型,则不会出现浮点型,否则会出现。
```java
public class ArithmeticOperator {
    public static void main(String[] args) {
        int a = 10;
        float c = 3.0f;
        double d = 3.0;
        System.out.println(a / c); // 3.3333333
        System.out.println(a / d); // 3.3333333333333335
        System.out.println(a % c); // 1.0
        System.out.println(a % d); // 1.0
    }
}
  • 需要注意的是,当浮点数除以 0 的时候,结果为 Infinity 或者 NaN。

    System.out.println(10.0 / 0.0); // Infinity
    System.out.println(0.0 / 0.0); // NaN
    
  • Infinity 的中文意思是无穷大,NaN 的中文意思是这不是一个数字(Not a Number)

  • 当整数除以 0 的时候(10 / 0),会抛出异常

    Exception in thread "main" java.lang.ArithmeticException: / by zero
      at com.ldl.baselearn.model01.ArithmeticOperator1.main(ArithmeticOperator1.java:29)
    
  • 算术运算符中还有两种特殊的运算符,自增运算符(++)和自减运算符(—),它们也叫做一元运算符,只有一个操作数。 ```java public class UnaryOperator1 { public static void main(String[] args) {

      int x = 10;
      System.out.println(x++);//10 (11)  
      System.out.println(++x);//12  
      System.out.println(x--);//12 (11)  
      System.out.println(--x);//10  
    

    } }


- 一元运算符可以放在数字的前面或者后面,放在前面叫前自增(前自减),放在后面叫后自增(后自减)
- 前自增和后自增是有区别的,拿 int y = ++x 这个表达式来说(x = 10),它可以拆分为 x = x+1 = 11; y = x = 11,所以表达式的结果为 x = 11, y = 11。拿 int y = x++ 这个表达式来说(x = 10),它可以拆分为 y = x = 10; x = x+1 = 11,所以表达式的结果为 x = 11, y = 10
```java
int x = 10;
int y = ++x;
System.out.println(y + " " + x);// 11 11

x = 10;
y = x++;
System.out.println(y + " " + x);// 10 11
  • 关系运算符

🎉 基础篇 - 图6

  • 位运算符
  • 在学习位运算符之前,需要先学习一下二进制,因为位运算符操作的不是整形数值(int、long、short、char、byte)本身,而是整形数值对应的二进制

    public class BitOperator {
      public static void main(String[] args) {
          System.out.println(Integer.toBinaryString(60)); // 111100
          System.out.println(Integer.toBinaryString(13)); // 1101
      }
    }
    

    🎉 基础篇 - 图7 ```java public class BitOperator1 { public static void main(String[] args) {

      int a = 60, b = 13;
      System.out.println("a 的二进制:" + Integer.toBinaryString(a)); // 111100
      System.out.println("b 的二进制:" + Integer.toBinaryString(b)); // 1101
    
      int c = a & b;
      // 0011 1100
      // 0000 1101
      // 0000 1100 
      System.out.println("a & b:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = a | b;
      // 0011 1100
      // 0000 1101
      // 0011 1101 
      System.out.println("a | b:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = a ^ b;
      // 0011 1100
      // 0000 1101
      // 1100 1110
      System.out.println("a ^ b:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = ~a;
      System.out.println("~a:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = a << 2;
      System.out.println("a << 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = a >> 2;
      System.out.println("a >> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
    
      c = a >>> 2;
      System.out.println("a >>> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
    

    } }


- 按位左移运算符
```java
public class LeftShiftOperator {
    public static void main(String[] args) {
        System.out.println(10 << 2);//10*2^2=10*4=40  
        System.out.println(10 << 3);//10*2^3=10*8=80  
        System.out.println(20 << 2);//20*2^2=20*4=80  
        System.out.println(15 << 4);//15*2^4=15*16=240  
    }
}
// 10<<2 等于 10 乘以 2 的 2 次方;10<<3 等于 10 乘以 2 的 3 次方。
  • 按位右移运算符

    public class RightShiftOperator {
      public static void main(String[] args) {
          System.out.println(10 >> 2);//10/2^2=10/4=2
          System.out.println(20 >> 2);//20/2^2=20/4=5
          System.out.println(20 >> 3);//20/2^3=20/8=2
      }
    }
    // 10>>2 等于 10 除以 2 的 2 次方;20>>2 等于 20 除以 2 的 2 次方。
    
  • 无符号右移动 ```java public class RightShiftOperator2 { public static void main(String[] args) {

      int a = -4;
      // 1111 1111 1111 1111 1111 1111 1111 1100
      System.out.println(Integer.toBinaryString(a));
    
      int b = a >>> 2;
      // 0011 1111 1111 1111 1111 1111 1111 1111
      System.out.println(Integer.toBinaryString(b));
    

    } }


- **逻辑运算符**
- 逻辑与运算符(&&):多个条件中只要有一个为 false 结果就为 false
- 逻辑或运算符(||):多个条件只要有一个为 true 结果就为 true
```java
public class LogicalOperator {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int c = 20;
        System.out.println(a < b && a < c);//false && true = false

        System.out.println(a > b || a < c);//true || true = true
    }
}
  • 逻辑非运算符(!):用来反转条件的结果,如果条件为 true,则逻辑非运算符将得到 false。
  • 单逻辑与运算符(&):很少用,因为不管第一个条件为 true 还是 false,依然会检查第二个。
  • 单逻辑或运算符(|):也会检查第二个条件。
  • 也就是说,& 和 | 性能不如 && 和 ||,但用法一样: ```java public class LogicalOperator { public static void main(String[] args) {

      int a = 10;
      int b = 5;
      int c = 20;
      System.out.println(a < b & a < c);//false && true = false
    
      System.out.println(a > b | a < c);//true || true = true
    

    } }


- 赋值运算符
```java
public class AssignmentOperator {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        a += 4;//a=a+4 (a=10+4)  
        b -= 4;//b=b-4 (b=20-4)  
        System.out.println(a);
        System.out.println(b);
    }
}
  • 不过在进行数值的赋值时,需要小点心,比如说下面这种情况:

image.png

  • 因为整型默认都是int类型,但是这里是short类型,需要的类型范围变小,就会有问题
  • 所以需要强转,可能存在精度丢失问题

image.png

  • 除此之外,还会有边界问题,比如说,两个非常大的 int 相乘,结果可能就超出了 int 的范围 ```java public class BigIntMulti { public static void main(String[] args) {
      int a = Integer.MAX_VALUE;
      int b = 10000;
      int c = a * b;
      System.out.println(c); // -10000
    
    } }

- 程序输出的结果为 -10000,这个答案很明显不是我们想要的结果,虽然可以通过右侧表达式强转 long 的方法解决
```java
public class BigIntMulti2 {
    public static void main(String[] args) {
        int a = Integer.MAX_VALUE;
        int b = 10000;
        long c = (long) a * b;
        System.out.println(c); // -10000
    }
}
  • 但尽量不要这样做,结果非常大的时候,尽量提前使用相应的类型进行赋值 ```java long a = Integer.MAX_VALUE - 1; long b = 10000; long c = a * b; System.out.println(c); // 21474836460000

- **三元运算符**
- 三元运算符用于替代 if-else,可以使用一行代码完成条件判断的要求。
```java
public class TernaryOperator {
    public static void main(String[] args) {
        int a = 2;
        int b = 5;
        int min = (a < b) ? a : b;
        System.out.println(min);
    }
}
// 如果 ? 前面的条件为 true,则结果为 : 前的值,否则为 : 后的值
  • 运算优先级:先乘除位运算后加减,有括号优先。

    流程控制

  • 流程控制的关键字如下: if-else、switch、for、while、do-while、return、break、continue 等

  • if-else相关

🎉 基础篇 - 图10

  • 这个比较简单,在下面进行演示即可,有些场景下,可能会积攒很多的if-else,维护起来是比较麻烦的,比如多一个case,就要多一层if。之后会使用策略模式进行去除if-else ```java // if语句 if(boolean 表达式 ){ // 为 true 就执行 }

// if-else语句 if(boolean 表达式 ){ // 为 true 就执行 }else{ // 为 false 就执行 }

// if-else-if int a = 1; if(a == 1){ // a == 1 就执行 }else if (a == 2){ // a == 2 就执行 }else if (a == 3){ // a == 3 就执行 }else { // a != 1 && a != 2 && a != 3 就执行 }

// if 嵌套语句 int a = 1; int b = 2; if(a == 1){ if(b == 2){

}

}


- **switch语句:**switch语句可以用来判断变量与多个值之间的相等性。变量的类型可以是 byte、short、int、long,或者对应的包装器类型 Byte、Short、Integer、Long,以及字符串和枚举。**至于switch为什么支持字符串String和枚举,会在String和枚举专门解释。**
```java
switch(变量) {    
case 可选值1:    
 // 可选值1匹配后执行的代码;    
 break;  // 该关键字是可选项
case 可选值2:    
 // 可选值2匹配后执行的代码;    
 break;  // 该关键字是可选项
......    

default: // 该关键字是可选项     
 // 所有可选值都不匹配后执行的代码 
}
  • 变量可以有 1 个或者 N 个值。
  • 值类型必须和变量类型是一致的,并且值是确定的。
  • 值必须是唯一的,不能重复,否则编译会出错。
  • break 关键字是可选的,如果没有,则执行下一个 case,如果有,则跳出 switch 语句。
  • default 关键字也是可选的。
  • 关键字break:跳出循环或者switch
  • 关键字continue:略过当前的执行条件
  • 关键字return:结束当前方法,自然也就跳出循环了 ```java public class Switch1 { public static void main(String[] args) {
      int age = 20;
      switch (age) {
          case 20:
              System.out.println("上学");
              break;
          case 24:
              System.out.println("苏州工作");
              break;
          case 30:
              System.out.println("洛阳工作");
              break;
          default:
              System.out.println("未知");
              break; // 可省略
      }
    
    } }

- **for循环**

![](https://cdn.nlark.com/yuque/0/2022/jpeg/1806904/1641305153625-1d008854-925d-4944-9ae0-5c068e8acf1f.jpeg)

- 普通的 for 循环可以分为 4 个部分
- 初始变量:循环开始执行时候的初始条件
- 条件:循环每次执行时要判断的条件,如果为 true,就执行循环体;如果为 false,就跳出循环。当然了,条件是可选的,如果没有条件,则会一直循环
- 循环体:循环语句需要执行的代码块,直到条件变为 false
- 自增/自减:初识变量变化的方式
```java
for(初识变量;条件;自增/自减){  
    // 循环体
}  

for (int i = 0; i < 5; i++) {
    System.out.println("hello LDL");
}
  • 双层for循环

    public class PyramidForExample {
      public static void main(String[] args) {
          for (int i = 0; i < 5; i++) {
              for (int j = 0; j <= i; j++) {
                  System.out.print("❤");
              }
              System.out.println();
          }
      }
    }
    
  • for-each:for-each 循环通常用于遍历数组和集合,它的使用规则比普通的 for 循环还要简单,不需要初始变量,不需要条件,不需要下标来自增或者自减 ```java for(元素类型 元素 : 数组或集合){
    // 要执行的代码 }

// case public class ForEachExample { public static void main(String[] args) { String[] strings = { “111”, “2222” }; for (String s : strings) { System.out.println(s); } } }


- **无限 for 循环:**
```java
public class InfinitiveForExample {
    public static void main(String[] args) {
        for (;;) {
            System.out.println("InfinitiveForExample.main");
        }
    }
}
  • while循环 ```java while(条件){
    //循环体
    }

// case

public class WhileExample { public static void main(String[] args) { int i = 0; while (true) { System.out.println(“DDD”); i++; if (i == 5) { break; } } } }

// 无限for循环

while (true) { // 执行体 }


- **do-while循环**
```java
do{  
    // 循环体
}while(条件);  

// 例子

public class DoWhileExample {
    public static void main(String[] args) {
        int i = 0;
        do {
            System.out.println("LDL");
            i++;
            if (i == 5) {
                break;
            }
        } while (true);
    }
}
// 无限循环

do {
    System.out.println("DDD");
} while (true);
  • 比较

🎉 基础篇 - 图11

数组

  • 顾名思义:是一组固定类型的组合。
  • 如何定义数组 ```java int[] anArray;

int[][] anArray;

int anArray[][];

// index 必须有值 二维数组 int anArray[][] = new int[index][];

// 初始化

String[] strings = { “111”, “2222” };

int[] anArray = new int[10]; // 大小10个,默认值是0 这个就是基本数据类型的默认值,其他数据类型的默认值和之前的讲的一致

// 访问数组 String[] strings = { “111”, “2222” }; // 数组长度为2,下标从0开始 strings[0] strings[1] strings[2] // 抛出下标越界异常 // 数组可以使用循环语句进行输出


- 数组的索引从0开始,那么为什么从0开始:当计算机拿到一个数组的时候,拿到的其实是数组的地址,也就是下标为0的地址,举个例子如下
```java
String[] strings = { "111", "2222","33333" };

image.png

  • 有关数组相关的基本算法和操作,会在后面讲Arrays工具类和ArrayList源码时候,更多的去学习。

    其他

  • 有些方法会进行重写,比如equals、hashcode方法、toString方法。在什么时候进行重写,是有一定的条件的,当然也可以无条件进行重写,但是有时候没必要的哈。

  • toString方法,当你想要知道这个数据内部是啥的时候,所有的对象的打印都是输出的toString方法。阿里巴巴开发手册要求所有的POJO类都必须重写toString方法。如果有继承。则必须使用super.toString()
  • equals、hashcode方法已经mark,在集合的部分进行讲解。

    参考资料

  • -128的二进制补码怎么来的:https://zhidao.baidu.com/question/303175158130244284.html

  • 为什么Java中的char类型只有两个字节:https://www.zhihu.com/question/483613181
  • 解析IEEE 754 标准:https://www.cnblogs.com/HDK2016/p/10506083.html
  • 沉默王二的博客:https://itwanger.gitee.io/tobebetterjavaer/#/