本文章最初发布在 XJHui’s Blog,未经允许,任何人禁止转载!

注意:最新修改版本已发布在 这里,点击前往查看!

Java环境搭建

JDK、JRE、JVM

  1. 名词解释:

    • JDK:Java Development Kit
    • JRE:Java Runtime Environment
    • JVM:Java Virtual Machine
  2. 关系图:

    注意:

    • jdk中包含了jre,所以我们开发时只安装jdk即可
    • jvm是实现java一次编译到处运行的关键(屏蔽底层差异)

JDK卸载

  1. 此电脑(右键)\属性\高级系统设置\环境变量\系统变量,找到JAVA_HOME:

    • JAVA_HOME的值为 D:\environment\jdk8,找到 jdk8 这个文件夹将其删除 :

    • 删除系统变量JAVA_HOME:

    • 双击打开 系统变量\Path,删除两个带有JAVA_HOME的值:

      注意:删除后记得点击确定,使修改生效

  2. 快捷键 win+r 输入 cmd 进入命令行,输入:

    1
    java -version

    运行结果:

    注意:如果未按上图,可以在 控制面板\程序\程序和功能 下找到 Java SE,双击删除后再次执行步骤2

JDK安装

  1. 打开链接,选择jdk下载:Java SE Development Kit 8 - Downloads (oracle.com)

    注意:需要勾选许可协议,并登录oracle账号才允许下载

  2. 双击下载后的exe文件,修改安装路径:

    注意:如果出现弹窗要求安装jre,关闭该窗口

  3. 右键 此电脑\属性\高级系统设置\环境变量\系统变量,配置环境变量:

    • 新建系统变量JAVA_HOME:

    • 给系统变量Path添加两个值:

      1
      2
      %JAVA_HOME%\bin
      %JAVA_HOME%\jre
  4. 快捷键 win+r 输入 cmd 进入命令行,输入:

    1
    java -version

    运行结果:

Hello World

  1. 新建文件夹code,存放代码:

  2. 新建java文件:Hello.java

    • 创建文件前先确保已显示文件拓展名

    • 新建Hello.java文件,编辑内容:

      1
      2
      3
      4
      5
      public class Hello{
      public static void main(String[] args){
      System.out.print("Hello world");
      }
      }

      注意代码规范:

      • 所有符号均为英文符号,输出内容也尽量为英文
      • class后的类名要与文件名一致,且首位必须大写
      • System.out.print("Hello world") 后要跟分号
    • 打开命令行:

    • 编译java文件:

      1
      javac Hello.java

      编译结果:

    • 运行java程序:

      1
      java Hello

      运行结果:

Java运行机制

  1. 运行机制:编译型(C、C++等)、解释型(HTML、JavaScript等)

  2. 运行图:

Java基本语法

注释

  1. 作用:解释一行代码、一个函数、一个程序的作用,注释内容不会被编译

  2. 分类:单行注释、多行注释、文档注释

  3. 单行注释:

    1
    2
    3
    // 单行注释
    // 多个单行注释可以同时使用
    // 一般用来解释单行代码的作用
  4. 多行注释:

    1
    2
    3
    4
    5
    /*
    多行注释
    注释内可以包含多行内容
    一般用来解释单个方法的作用
    */
  5. 文档注释:

    1
    2
    3
    4
    5
    6
    /**
    * 文档注释
    * 注释中的@author是会被识别的
    * @author XJHui
    * @date 2000.12.01
    */

标识符

  1. 包含:类名、方法名、变量名

  2. 标识符命名规则:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /*
    Java标识符(类名、方法名、变量名)命名规则:
    1. 所有的标识符都只能以字母(A-Z或a-z),美元符($),下划线(_)开始
    A、a、$、_
    2. 首字母之后可以是字母(A-Z或a-z),美元符($),下划线(_),数字(0-9)的任何字符组合
    Aa、a$、$1、_A
    3. 不能使用关键字作为
    关键字详见下图
    4. 标识符大小写敏感
    aa和Aa不相同
    5. 可以使用中文命名但不推荐,也不推荐使用pinyin
    你好、nihao
    */
  3. Java关键字:

数据类型

  1. 数据类型分类:

    • 基本数据类型:整型(byte、short、int、long)、浮点型(float、double)、字符型(char)、布尔型(True、False)

      注意:上图中-128~127表示该类型变量可表示的范围为[-128,127]

    • 引用数据类型:除去基本类型都属于引用类型(字符串、数组等)

  2. 案例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Demo1 {
    public static void main(String[] args) {
    // 整型 byte short int long
    byte num1 = 10; // 定义一个byte类型变量,变量的值为10
    short num2 = 20;
    int num3 = 30;
    long num4 = 40L;

    // 浮点型 float double
    float num5 = 50.111F;
    double num6 = 60.666;

    // 字符型 char
    char str1 = '你';

    // 字符串 string(string不是关键字,是类)
    String str2 = "你好";

    // 布尔类型 true false
    boolean flag1 = true; // 布尔类型的true和false都是小写
    boolean flag2 = false;
    }
    }

    注意:

    • 为了区分int和long,float和double,定义变量时long后加L(l),float后加F(f)

    • Java是强类型语言(变量的使用要严格符合规定),所有变量必须先定义再使用,且必须为其赋初值

    • byte范围是[-128,127],赋初值时不可以超过该范围,short、int、long、float、double同理

  3. 位、字节、字符:

    • 位(bit):是计算机存储的最小单位,例如11001100是8位二进制数
    • 字节(byte,B):是计算机处理数据的最小单位,1B (byte)= 8b(bit)
    • 字符:是指计算机中使用的字母、数字、字、符号

类型转换

  1. 容量大小:

  2. 转换规则:

    • 强制转换:低容量 <— 高容量
    • 自动转换:低容量 —> 高容量
  3. 案例:

    • 将int型变量转换为short类型

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
        public class demo2 {
      /*
      1. 不能对布尔值进行转换
      2. 转换可能出现内存溢出、精度丢失等问题
      */
      public static void main(String[] args) {
      int a = 10;
      short b = (short) a; // int类型容量大于short类型,需要强制转换
      System.out.print(b); // 10
      }
      }
    • 将long类型变量转换为double类型

      1
      2
      3
      4
      5
      6
      7
      public class demo2 {
      public static void main(String[] args) {
      long c = 10;
      double d = c; // long类型容量小于double类型,自动转换
      System.out.print(d); // 10.0
      }
      }
  4. 易错:

    • char与int相加:

      1
      2
      3
      4
      5
      6
      7
      public class demo2 {
      public static void main(String[] args) {
      char a = 'a';
      System.out.println(a + 1); // 98,两不同类型变量做运算,谁容量大结果为谁(int,类型)
      System.out.println((char) (a + 1)); // b,int型变char型需要强制转换
      }
      }
    • int和int相乘:

      1
      2
      3
      4
      5
      6
      7
      8
      public class demo2 {
      public static void main(String[] args) {
      int a = 10_0000_0000, b = 10_0000_0000;
      System.out.println("【a * b】:" + a * b);
      System.out.println("【(long) (a * b)】:" + (long) (a * b));
      System.out.println("【a * ((long) b)】:" + a * ((long) b));
      }
      }

      运行结果:

变量

  1. 定义:可以变化的量;变量为什么可变?变量时存放在内存中的,而内存就像一个衣柜

  2. 语法:

    1
    数据类型 变量名 = 值;

    注意:数据类型可以8中基本数据类型(整型、浮点型、字符型、布尔型)也可以是引用类型(数组、字符串等)

  3. 案例:创建变量PI,数据类型为double,值为3.1415926

    1
    2
    3
    4
    5
    6
    public class demo2 {
    public static void main(String[] args) {
    double PI = 3.1415926; // 数据类型 变量名 = 值;
    System.out.println(PI); // 3.1415926
    }
    }
  4. 变量分类:局部变量(方法外、类内);类变量(方法外、类内);实例变量(类内,方法外)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class demo2 {
    // 类变量(类内,方法外),比实例对象多static,可直接引用
    static double flag = 10;

    // 实例变量(类内,方法外),要new对象才能引用
    String name = "Jerry";

    public static void main(String[] args) {
    // 局部变量(方法内)
    int i = 10;
    System.out.println(i); // 10
    }
    }

常量

  1. 定义:定义后其值不会改变

  2. 案例:创建常量PI,其值为3.14

    1
    2
    3
    4
    5
    6
    7
    8
    public class demo2 {
    // 定义常量PI
    static final double PI = 3.14; // static、final都是修饰符无先后顺序

    public static void main(String[] args) {
    System.out.println(PI); // 3.14,添加了static修饰词,可以在方法内直接引用,去掉则不可
    }
    }

命名规则

  1. 常量:全大写字母,下划线(MAX_NUM)
  2. 局部变量、类变量、实例变量、方法名:首字母小写,驼峰命名法(sumSalary)
  3. 类名:首字母大写,驼峰命名法(TestDemo)

运算符

  1. 定义:运算符是一种特殊符号,用以表示数据的运算、赋值和比较。

  2. 分类:

    • 算术运算符
    • 赋值运算符
    • 比较运算符
    • 逻辑运算符
    • 位运算符(熟悉)
    • 三元运算符
  3. 算术运算符

    • +(正)、-(负)、 +、 -、*、/、%(取余)、++(前、后自增)、–(前、后自减)、+(字符串拼接)

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      package day03;

      public class AriTest {
      public static void main(String[] args) {
      /*
      除法运算 /
      */
      int num1 = 12;
      int num2 = 5;
      int result1 = num1 / num2;
      System.out.println(result1); // 2,两int变量相除结果仍为int

      double result3 = num1 / num2; // 2.0,相除结果为2强转为double
      double result4 = (double) (num1 / num2); //2.0
      double result5 = (num1 * 1.0) / num2; //2.4,double除int,结果为double
      double result6 = ((double) num1) / num2; //2.4

      /*
      取余(模)运算 %
      结果的符号与被模数符号一致
      */
      int m1 = 12;
      int n1 = 5;
      System.out.println("m1 % n1: " + m1 % n1); // 2

      int m2 = -12;
      int n2 = 5;
      System.out.println("m2 % n2: " + m2 % n2); // -2

      int m3 = 12;
      int n3 = -5;
      System.out.println("m3 % n3: " + m3 % n3); // 2

      int m4 = -12;
      int n4 = -5;
      System.out.println("m4 % n4: " + m4 % n4); // -2

      /*
      (前)++ 先自增1,再运算
      (后)++ 先运算,再自增1
      1. 自增1不会改变变量数据类型
      2. 常量不能自加(1++)
      */
      int a1 = 10;
      int b1 = ++a1;
      System.out.println("a1: " + a1 + " b1: " + b1); // 11 11

      int a2 = 10;
      int b2 = a2++;
      System.out.println("a2: " + a2 + " b2: " + b2); // 11 10

      int a3 = 10;
      a3++; // ++a3
      System.out.println("a3: " + a3); // 11

      // 注意:
      short s1 = 10;
      // s1=s1+1; //编译失败,s1=(short)(s1+1) //正确编译
      s1++; // 自增1不会改变变量本身数据类型

      // 练习
      int a4 = 10;
      int b4 = a4--;
      System.out.println(b4); // 10

      /*
      字符串拼接 +
      拼接字符串,至少要保证一边为字符串类型
      */
      int sNum = 10;
      System.out.println("sNum: " + sNum); // 10,字符串+int,做拼接
      System.out.println(10 + sNum); // 20,int+int,不做拼接
      }
      }
    • 案例练习:

      随意给出一个三位数整数,打印显示它的个位数、十位数、百位数的值。
      例如:

      数字153的情况如下:
      个位数:3
      十位数:5
      百位数:1
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      package day03;

      public class AriExer {
      public static void main(String[] args) {
      int num = 123;
      System.out.println("数字" + num + "的情况如下:");
      int fNum = num / 100;
      int sNum = (num / 10) % 10;
      int tNum = num % 10;
      System.out.println("个位数:" + tNum); // 3
      System.out.println("十位数:" + sNum); // 2
      System.out.println("百位数:" + fNum); // 1
      }
      }
  4. 赋值运算符

    • =、+=、-=、*=、/=、%=

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      package day03;

      public class SetValue {
      public static void main(String[] args) {
      /*
      赋值符号 =
      */
      int i1 = 10;
      int j1 = 10; // 方式一(推荐)

      int i2 = 10, j2 = 10; // 方式二

      int i3, j3;
      i3 = j3 = 10; // 方式三

      // 赋值符号拓展: +=
      int num1 = 10;
      int num2 = 3;
      num1 += num2; // 作用同 num1 = num1 + num2;

      // 区别:s1 += s2; s1 = s1 + s2;
      short s1 = 10;
      // s1 = s1 + 2; // 编译失败
      s1 += 2; // 不会改变变量本身的数据类型
      }
      }
    • 习题练习:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      //练习1:实现变量+1,有几种方法?
      int num = 1;
      num += 1; // 方式一
      num = num + 1; // 方式二
      num++; // 方式三(推荐)

      //练习2:
      int i = 1;
      i *= 0.1; // 0 = (int)0.1;
      i++;
      System.out.println(i); // 1

      // 练习3:
      int m = 2;
      int n = 3;
      n *= m++; // n=n*(m++)
      System.out.println(m + " " + n); // 3 6
  5. 比较运算符

    • ==、!=、<、>、<=、>=

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      package day03;

      public class CompareTest {
      public static void main(String[] args) {
      /*
      比较运算符
      1. 比较运算符结果为布尔类型
      2. 区分==和=:==表示判断是否相等,=表示赋值
      */
      int i = 10;
      int j = 20;
      System.out.println(i == j); // false,比较运算符(判断是否相等)
      System.out.println(i = j); // 20,赋值
      }
      }
  6. 逻辑运算符:

    • &(与)、&&(短路与)、|(或)、||(短路或)、!(非)、^(异或)

      注意:逻辑运算符操作的都是布尔类型的变量

    • 逻辑运算图:

      注意:

      • &、&&:两边均为true,结果为true;
      • |、||:任一边为true,结果就为true;
      • !:true变false;false变true;
      • ^:两边相异时结果为true,反之为false;
    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      package day03;

      public class logicTest {
      public static void main(String[] args) {
      /*
      区分&和&&,同理可推|和||
      1. 相同点:&和&&的运算结果相同;当左边为true时都会执行右边的语句
      2. 不同点:当左边为false时,&继续执行右边的语句,&&不在继续执行右边的语句
      */
      boolean b1 = false;
      int num1 = 10;
      if (b1 & (num1++ > 0)) {
      System.out.println("我在北京");
      } else {
      System.out.println("我在南京");
      }
      System.out.println(num1); // 11

      boolean b2 = false;
      int num2 = 10;
      if (b2 && (num2++ > 0)) {
      System.out.println("我在北京");
      } else {
      System.out.println("我在南京");
      }
      System.out.println(num2); // 10
      }
      }
    • 习题练习:

      写出每题的输出结果

      答案:

  7. 位运算符

    • <<(左移)、>>(右移)、>>>(无符号右移)、&、|、! 、^ 、~(取反)

      注意:位运算符操作的都是整型的数据

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      package day03;

      public class BitTest {
      public static void main(String[] args) {
      /*
      <<、>>
      <<:在一定范围内,向左移动一位,相当于*2
      >>:在一定范围内,向右移动一位,相当于/2
      原理见下图
      */
      int i = 21;
      System.out.println("i<<2 " + (i << 2)); // 84
      System.out.println("i<<3 " + (i << 3)); // 168

      System.out.println("i>>2 " + (i >> 2)); // 5
      System.out.println("i>>3 " + (i >> 3)); // 2

      // &、|、^
      int m = 12;
      int n = 5;
      System.out.println("m&n " + (m & n)); // 4
      System.out.println("m|n " + (m | n)); // 13
      System.out.println("m^n " + (m ^ n)); // 9
      }
      }
    • 图解位运算<<、>>原理:

    • 图解位运算&、|、^:

    • 习题练习:

      交换两变量的值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      package day03;

      public class BitExer {
      public static void main(String[] args) {
      /*
      交换两变量的值
      */
      int a = 10;
      int b = 5;

      int swap = a; // 方法一:借助第三个变量
      a = b;
      b = swap;
      System.out.println(a + " " + b); // 5 10

      a = a + b; // 方法二:a跳到b头上
      b = a - b;
      a = a - b;
      System.out.println(a + " " + b); // 10 5


      a = a ^ b; // 方法三:异或特性
      b = a ^ b;
      a = a ^ b;
      System.out.println(a + " " + b); // 5 10
      }
      }
  1. 三元运算符

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      package day03;

      public class ThreeTest {
      public static void main(String[] args) {
      /*
      三元运算符
      1. 语法:
      (条件表达式)? 表达式一 : 表达式二;
      2. 使用:
      条件表达式为true时执行表达式一,否则执行表达式二
      3. 注意:
      ① 三元运算符可以嵌套使用
      ② 任何三元运算符都可以改写成if-else语句,反之不成立
      */
      int m = 12;
      int n = 5;
      int max = (m > n) ? m : n;
      System.out.println(max); // 12

      // 嵌套使用(不建议,代码可读性差)
      String result = (m > n) ? "m大" : ((m == n) ? "m和n相等" : "n大");
      System.out.println(result); // m大

      // 改写为if-else语句
      if (m > n) {
      System.out.println("m大");
      } else {
      if (m == n) {
      System.out.println("m和n相等");
      } else {
      System.out.println("n大");
      }
      }
      }
      }
    • 习题练习:

      获取三个数中的最大值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      package day03;

      public class ThreeExer {
      public static void main(String[] args) {
      int n = 10;
      int m = -10;
      int q = 99;
      int max = (((n > m) ? n : m) > q) ? ((n > m) ? n : m) : q;
      System.out.println(max); // 9
      }
      }
    • 三元运算符和if-else的选择:程序在保证代码可读性的前提下,既可以使用三元运算符又可以使用if-else,优先使用三元运算符,原因:简洁、高效。

程序流程控制

  1. 分类:

    • 顺序结构
    • 分支结构(if-else、switch-case)
    • 循环结构(while、do…while、for)
  2. 顺序结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package day03;

    public class ShunXuTest {
    public static void main(String[] args) {
    /*
    顺序结构,程序从上到下逐行的执行,中间没有任何判断和跳转。
    注意:Java中定义成员变量时采用合法的向前引用
    */
    int num1 = 12;
    int num2 = num1 + 1;
    System.out.println(num2);

    //int num2 = num1+1; // 编译错误,num1要先定义才能使用
    //int num1 = 12;
    //System.out.println(num2);
    }
    }
  3. 分支语句

    • if-else

      • 三种结构:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        第一种:
        if(条件表达式){
        执行表达式
        }

        第二种:二选一
        if(条件表达式){
        执行表达式1
        }else{
        执行表达式2
        }

        第三种:n选一
        if(条件表达式){
        执行表达式1
        }else if(条件表达式){
        执行表达式2
        }else if(条件表达式){
        执行表达式3
        }
        ...
        else{
        执行表达式n
        }
      • 读取键盘内容(Scanner类):

        键盘读取个人信息(name、age、sex)并输出,输出格式如下:

        【name】,您的性别为:sex,您的年龄为:age岁!

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        package day04;
        /*
        读取键盘内容

        1. 导包 import java.util.Scanner;
        2. 实例化对象 Scanner scan = new Scanner(System.in);
        3. 调用Scanner类的方法(next/nextXxx),获取指定类型的变量

        Scanner方法

        1. 字符串: next()
        2. 整型: nextByte,nextShort(),nextInt(),nextLong()
        3. 浮点型: nextFloat,nextDouble()
        */
        import java.util.Scanner; // 导包

        public class ScannerTest {
        public static void main(String[] args) {
        Scanner scan = new Scanner(System.in); // 实例化对象
        System.out.println("请输入姓名:");
        String name = scan.next(); // 调用方法获取指定类型的变量
        System.out.println("请输入年龄:");
        int age = scan.nextInt();

        // 获取字符型
        System.out.println("请输入您的性别(男/女):");
        char sex = scan.next().charAt(0); // 先当做字符串获取,再使用字符串的charAt方法获取某位置的字符,下标从0开始

        System.out.println("【" + name + "】,您的性别为:" + sex + ",您的年龄为:" + age + "岁!");
        }
        }

        运行结果:

      • 生成随机数(Math.random()):

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        /*
        生成随机数 Math.random()
        1. 不需要导包
        2. Math.random()生成的随机数范围为[0.0,1.0)
        3. 生成[a,b]的随机数,公式:
        (int) (Math.random() * (b - a + 1) + a);
        */
        public class RandomTest {
        public static void main(String[] args) {
        // 案例:生成[10,99]的随机数
        int num = (int) (Math.random() * (90) + 10);
        System.out.println("生成的随机数为:" + num); // 57
        }
        }
      • if-else的就近原则:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        package day04;

        public class IfExer2 {
        public static void main(String[] args) {
        int x = 4;
        int y = 1;
        if (x > 2)
        if (y > 2)
        System.out.println(x + y);
        //System.out.println("hello");
        else // else会匹配离它最近的if
        System.out.println("x is " + x);
        }
        }
    • switch-case:

      • 基本使用:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        package day04;
        /*
        1. switch-case语法:
        switch(表达式){
        case 常量1:
        执行语句1;
        // break;
        case 常量2:
        执行语句2;
        // break;
        ...
        default:
        执行语句n;
        // break;
        }
        2.注意:
        ① 根据switch表达式的值,依次匹配各个case。一旦匹配成功,则进入case调用执行语句。
        当语句执行完后,仍然继续向下执行每个case结构中的执行语句,直到遇到break或switch-case语句结束。
        ② switch结构中的表达式,只能是以下6种:
        byte、short、int、char、字符串(JDK7.0新增)、枚举(JDK5.0新增)
        ③ case后只能是常量不能是一个范围
        ④ break、default都是可选的,default相当于if-else中的else,且位置不固定
        */

        public class SwitchCaseTest {
        public static void main(String[] args) {
        // 案例:使用switch-case语句,匹配数字1~3
        int num = 3;
        switch (num) {
        case 1:
        System.out.println("one");
        break;
        case 2:
        System.out.println("two");
        break;
        default:
        System.out.println("three");
        }
        }
        }
      • 案例练习1:

        对学生成绩大于 60 分的,输出“合格”。低于 60 分的,输出“不合格”

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        package day04;

        public class SwitchCaseExer {
        public static void main(String[] args) {
        int score=87;
        // 方式一:巧用break
        switch (score/10){
        case 0:
        case 1:
        case 2:
        case 3: // 如果匹配到3,会依次往下执行每个case,直到遇到break或程序结束
        case 4:
        case 5:
        System.out.println("不及格!");
        break;
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        System.out.println("及格!");
        }

        // 方式二:switch-case处理范围问题时,未必需要列出所有case
        switch (score/60){
        case 0:
        System.out.println("不及格!");
        break;
        default:
        System.out.println("及格!");
        }
        }
        }

        运行结果:

      • 案例练习2:

        从键盘上输入 2019 年 的“ month ”和 day ”,通过程序输出:输入的日期 为 2019 年 的 第几天

        1
        2
        package day04;

      import java.util.Scanner;

      public class SwitchCaseExer2 {
          public static void main(String[] args) {
              Scanner scan = new Scanner(System.in);
      
              System.out.println("请输入2019年个month:");  // 输入数据
              int month = scan.nextInt();
      
              System.out.println("请输入2019年个day:");
              int sumDay = 0;
              int day = scan.nextInt();
      
              switch (month) {
                  case 12:
                      sumDay += 30;
                  case 11:
                      sumDay += 31;
                  case 10:
                      sumDay += 30;
                  case 9:
                      sumDay += 31;
                  case 8:
                      sumDay += 31;
                  case 7:
                      sumDay += 30;
                  case 6:
                      sumDay += 31;
                  case 5:
                      sumDay += 30;
                  case 4:
                      sumDay += 31;
                  case 3:
                      sumDay += 28;
                  case 2:
                      sumDay += 31;
                  default:
                      sumDay += day;
              }
              System.out.println("输入的日期 为 2019 年 的 第" + sumDay + "天");
          }
      }
      1
      2
      3
      4
      5
      6
        
      运行结果:

      <img src="https://cdn.jsdelivr.net/gh/xingjiahui/CDN@latest/2020/12/05/09e12c6088225891186585e8914e14de.png" width="80%"/>

      - switch-case和if-else的选择:程序既可以使用switch-case又可以使用if-else,优先使用switch-case,原因:高效。
  4. 循环结构

    • 分类:for循环、while循环、do…while()循环

    • 循环语句的组成:

    • for循环:

      • 基本使用:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        package day04;

        /*
        1.循环条件:
        ① 初始化部分
        ② 循环条件部分
        ③ 循环体部分
        ④ 迭代部分

        2. for循环结构:
        for(①;②;④){

        }

        3. 执行过程:①->②->③->④->②->③->④->...->②

        */
        public class ForTest {
        public static void main(String[] args) {
        // 案例:输出100个"hello world"
        for (int i = 0; i < 100; i++) {
        System.out.println("hello world");
        }
        }
        }
      • 习题练习1:

        写出程序运行结果:

        1
        2
        3
        4
        int num = 1;
        for (System.out.print('a'); num <= 3; System.out.print('c'), num++) {
        System.out.print('b');
        }

        答案:abcbcbc

      • 习题练习2:

        遍历100以内的偶数,输出所有偶数的和,输出偶数的个数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        package day04;

        public class ForExer {
        public static void main(String[] args) {
        int numSum = 0;
        int cnt = 0;
        for (int i = 1; i <= 100; i++) {
        if (i % 2 == 0) {
        numSum += i;
        cnt++;
        }
        }
        System.out.println("偶数和:" + numSum + " 偶数数目:" + cnt); // 偶数和:2550 偶数数目:50
        }
        }
      • 习题练习3:

        输入两个正整数 m 和 n ,求其最大公约数和最小公倍数 。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        package day05;

        import java.util.Scanner;

        public class ForTest {
        public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 键盘读入数据m、n
        System.out.print("请输入m:");
        int m = scan.nextInt();
        System.out.print("请输入n:");
        int n = scan.nextInt();

        // 计算最大公约数
        int min = (m < n) ? m : n;
        for (int i = min; i >= 1; i--) {
        if (m % i == 0 && n % i == 0) {
        System.out.println("最大公约数为:" + i);
        break; // 结束循环
        }
        }

        // 计算最小公倍数
        int max = (m > n) ? m : n;
        for (int i = max; i <= m * n; i++) {
        if (i % m == 0 && i % n == 0) {
        System.out.println("最小公倍数为:" + i);
        break;
        }
        }
        }
        }

        运行结果:

    • while循环

      • 基本使用:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        package day05;

        /*
        1. 循环结构的4个要素
        ① 初始化条件
        ② 循环条件 --->是boolean类型
        ③ 循环体
        ④ 迭代条件

        2. while循环的结构

        while(②){
        ③;
        ④;
        }
        执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②

        3. 注意:
        ①写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!
        ②for循环和while循环是可以相互转换的!
        区别:for循环和while循环的初始化条件部分的作用范围不同。
        */
        public class WhileTest {
        public static void main(String[] args) {
        // 遍历10以内所有偶数
        int num = 1;
        while (num <= 10) {
        if (num % 2 == 0) {
        System.out.print(num + " "); // 2 4 6 8 10
        }
        num++;
        }
        }
        }
    • do-while循环:

      • 基本使用:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        package day05;

        /*
        一、循环结构的4个要素
        ① 初始化条件
        ② 循环条件 --->是boolean类型
        ③ 循环体
        ④ 迭代条件

        二、do-while循环结构:

        do{
        ③;
        ④;
        }while(②);
        执行过程:① - ③ - ④ - ② - ③ - ④ - ... - ②
        三、注意:
        1. do-while循环至少会执行一次循环体!
        */
        public class DoWhileTest {
        public static void main(String[] args) {
        // 遍历10以内的偶数
        int num = 1;
        do {
        if (num % 2 == 0) {
        System.out.print(num + " "); // 2 4 6 8 10
        }
        num++;
        } while (num <= 10);
        }
        }
      • 案例练习:

        从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为 0 时结束 程序

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        package day05;

        import java.util.Scanner;

        public class WhileExer {
        public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        int cnt1 = 0; // 正数数目
        int cnt2 = 0; // 负数数目

        while (true) { // 构造循环实现多次输入
        System.out.print("请输入一个整数:");
        int num = scan.nextInt();
        if (num == 0) {
        break;
        }
        if (num > 0) {
        cnt1++;
        } else if (num < 0) {
        cnt2++;
        }
        }
        System.out.println("正数数目:" + cnt1 + " 负数数目:" + cnt2);
        }
        }

        运行结果:

    1. 嵌套循环

      • 基本使用:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        package day05;

        import javax.swing.*;

        /*
        嵌套循环的使用
        1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环

        2.
        外层循环:循环结构B
        内层循环:循环结构A

        3. 说明
        ① 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次
        ② 假设外层循环需要执行m次,内层循环需要执行n次。此时内层循环的循环体一共执行了m * n次

        4. 技巧:
        外层循环控制行数,内层循环控制列数
        */
        public class ForForTest {
        public static void main(String[] args) {
        // ******
        for (int i = 1; i <= 6; i++) {
        System.out.print("*");
        }
        System.out.println("\n");

        /*
        ******
        ******
        ******
        ******
        */
        for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= 6; j++) {
        System.out.print("*");
        }
        System.out.println();
        }
        System.out.println("\n");

        /* i(行号) j(*数目)
        * 1 1
        ** 2 2
        *** 3 3
        **** 4 4
        */
        for (int i = 1; i <= 4; i++) {
        for (int j = 1; j <= i; j++) {
        System.out.print("*");
        }
        System.out.println();
        }
        }
        }
      • 案例练习:

        输出 20 以内所有素数(质数)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        package day05;

        public class ForForExer {
        public static void main(String[] args) {
        for (int i = 2; i <= 20; i++) {
        boolean isFlag = true;
        for (int j = 2; j <= Math.sqrt(i); j++) { // 优化二:c=a*b,a和b肯定分布在根号c两边,只判断a即可
        if (i % j == 0) {
        isFlag = false;
        break; // 优化一:只要能整除,就停止判断
        }
        }
        if (isFlag == true) {
        System.out.print(i + " "); // 2 3 5 7 11 13 17 19
        }
        }
        }
        }
    2. 特殊关键字:

      • breake、continue:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        package day05;

        /*
        break和continue关键字的使用
        使用范围 循环中使用的作用(不同点) 相同点
        break: switch-case
        循环结构中 结束当前循环 关键字后面不能声明执行语句

        continue: 循环结构中 结束当次循环 关键字后面不能声明执行语句
        */
        public class BreakContinueTest {
        public static void main(String[] args) {
        /* *************** break ******************** */
        for (int i = 1; i < 10; i++) {
        if (i % 4 == 0) {
        break; // 结束循环
        // System.out.println("太阳从西边出来!"); // 编译错误,break,continue后面都不可以跟语句
        }
        System.out.print(i); // 123
        }
        System.out.println();
        /* *************** continue ******************** */
        for (int i = 0; i < 10; i++) {
        if (i % 4 == 0) {
        continue; // 结束此次循环
        // System.out.println("太阳从西边出来!"); // 编译错误,break,continue后面都不可以跟语句
        }
        System.out.print(i); // 1235679
        }
        System.out.println();
        }
        }
      • 带标签的break:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        public class BreakContinueTest {
        public static void main(String[] args) {
        flag:
        // 给for循环添加标签
        for (int i = 1; i < 10; i++) {
        for (int j = 1; j < 10; j++) {
        if (j % 4 == 0) {
        break flag; // 添加标签后,可停止指定循环
        //break; // 默认情况下,break是停止此循环
        }
        System.out.print(j); // 123
        }
        }
        }
        }

数组

数组的概述

  1. 数组(Array):是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。

  2. 数组的相关概念:

    • 数组名
    • 元素
    • 索引(下标、角标)
    • 数组的长度(元素个数)
  3. 数组分类:

    • 按照维数:一维数组、二维数组 …
    • 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
  4. 数组的特点:

    • 数组是有序排列的
    • 数组属于引用数据类型的变量;数组的元素既可以是基本数据类型,也可以是引用数据类型;
    • 创建数组对象会在内存(堆)中开辟一整块连续的空间
    • 数组的长度一旦确定,就不能修改

一维数组

  1. 基本使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package cn.plushine.test;

    public class ArrayTest {
    public static void main(String[] args) {
    // 1.一维数组的声明和初始化
    // 注意:数组一旦初始化完成,其长度就确定了

    int[] ids; // 声明
    ids = new int[] { 2, 1, 3, 0 }; // 写法1,静态初始化:赋值和初始化同时进行

    String[] names = new String[3]; // 写法2,动态初始化:赋值和初始化分开进行
    names[0] = "小明"; // 赋值
    names[1] = "小红";
    names[2] = "小军";

    int[] arr4 = { 1, 2, 3, 4 }; // 写法3,类型推断

    // 2.如何调用数组的指定位置的元素:通过索引的方式调用
    // 注意:数组的角标(或索引)从0开始的,到数组的长度-1结束
    System.out.println(ids[3]); // 0
    System.out.println(names[0]); // "小明"

    // 3.如何获取数组的长度
    System.out.println(ids.length); // 4
    System.out.println(names.length); // 3

    // 4.如何遍历数组
    for (int i = 0; i < ids.length; i++) {
    System.out.print(ids[i]); // 2130
    }

    /*
    * 5.数组元素的默认初始化值
    * 数组元素是整型:0
    * 数组元素是浮点型:0.0
    * 数组元素是char型:0或'\u0000'(类似空格),而非'0'
    * 数组元素是boolean型:false
    * 数组元素是引用数据类型:null
    */
    }
    }
  2. 内存解析:

    代码运行后,栈、堆的变化过程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package cn.plushine.test;

    public class ArrayTest {
    public static void main(String[] args) {
    int[] arr1 = new int[4]; // 堆中开辟空间存放int型变量,长度为4,初值为0,首地址为0x12ab,栈中的arr1指向该地址
    arr1[0] = 10; // 将首地址为0x12ab的第1个值改为10
    arr1[2] = 20; // 将首地址为0x12ab的第3个值改为20

    String[] arr2 = new String[3]; // 堆中开辟空间存放字符串,长度3,初值null,首地址为0x34ab,栈中的arr2指向该地址
    arr2[1] = "刘杰"; // 将首地址为0x34ab的第2个值改为“刘杰”
    arr2 = new String[5]; // 堆中开辟空间存放字符串(注),长度为5,初值为null,首地址为0x78cd,栈中的arr2指向该地址
    }
    }
    // 简单的垃圾回收机制
    // 当main方法执行结束以后,arr2、arr1相继出栈,出栈后arr1与0x12ab的指针会断开连接,堆中判断到没有指针指向0x12ab后会将数组回收,其余数组同理

    注:字符串并不是存储在堆中,上图为了方便演示,才写成“堆中开辟空间存放字符串”。

  3. 案例练习:

    升景坊单间短期出租 4 个月 550 元 月(水电煤公摊,网费 35 元 月),空调、卫生间、厨房齐全。
    屋内均是 IT 行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class ArrayTest {
    public static void main(String[] args) {
    int[] arr = new int[] { 8, 2, 1, 0, 3 };
    int[] index = new int[] { 2, 0, 3, 2, 4, 0, 1, 3, 2, 3, 3 };
    String tel = "";
    for (int i = 0; i < index.length; i++) {
    tel += arr[index[i]];
    }
    System.out.println(" 联系方式:" + tel);
    }

    答案:18013820100

多维数组

  1. 基本使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package cn.plushine.test;

    /*
    * 二维数组的理解:可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。
    */
    public class ArrayTest2 {
    public static void main(String[] args) {
    // 1.二维数组的声明和初始化
    // 静态初始化
    int[][] arr1 = new int[][] { { 1, 2, 3 }, { 4, 5 }, { 6, 7, 8 } };
    // 动态初始化1
    String[][] arr2 = new String[2][3];
    // 动态初始化2
    String[][] arr3 = new String[3][];
    arr3[0] = new String[] { "1", "2" }; // 赋值

    // 其它正确写法
    int[] arr4[] = { { 1, 2, 3 }, { 4, 5 } };
    int arr5[][] = { { 1, 2, 3 }, { 4, 5 } };

    // 2.如何调用数组的指定位置的元素
    System.out.println(arr1[0][1]);// 2
    System.out.println(arr2[1][1]);// null

    // 3.获取数组的长度
    System.out.println(arr4.length);// 3,行数
    System.out.println(arr4[0].length);// 3,列数

    // 4.如何遍历二维数组
    for (int i = 0; i < arr4.length; i++) {
    for (int j = 0; j < arr4[i].length; j++) {
    System.out.print(arr4[i][j] + " ");
    }
    System.out.println();
    }

    }
    }
  2. 默认初始化值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package cn.plushine.test;

    /*
    * 1.二维数组的外层元素和内层元素定义:
    * 例:int[][] arr = new int[4][3];
    * 外层元素:arr[0],arr[1]等
    * 内层元素:arr[0][0],arr[1][2]等
    *
    * 2.数组元素的默认初始化值
    * 初始化方式一:int[][] arr = new int[4][3];
    * 外层元素的初始化值为:地址值
    * 内层元素的初始化值为:与一维数组初始化情况相同,整型:0,浮点型:0.0,字符型:'\u0000',布尔型:false等
    *
    * 初始化方式二:int[][] arr = new int[4][];
    * 外层元素的初始化值为:null
    * 内层元素的初始化值为:不能调用,否则报错。
    */
    public class ArrayTest3 {
    public static void main(String[] args) {
    // 初始化方式一:
    int[][] arr = new int[4][3];
    System.out.println(arr[0]); // [I@15db9742,[:一维数组,I:int型,15db9742:首地址
    System.out.println(arr[0][0]); // 0,一维数组中int型初始化为0

    // 初始化方式二:
    double[][] arr3 = new double[4][];
    System.out.println(arr3[1]);// null,引用数据类型初始化为null,数组也是引用数据类型
    // System.out.println(arr3[1][0]);//报错
    }
    }
  3. 内存解析:

    代码运行后,栈、堆的变化过程:

    1
    2
    3
    4
    5
    6
    int[][] arr4 = new int[3][]; // 栈中开辟空间存放int型一维数组,长度为3,初始化为null,首地址为0x5566,arr4指向该地址
    System.out.println(arr4[0]); // 一维数组为引用数据类型,初始化值为null
    // System.out.println(arr4[0][0]); // 报错
    arr4[0] = new int[3]; // 栈中开辟空间存放int型变量,长度为3,初始化为0,首地址为0x8899,arr4[0]指向该地址
    arr4[0][1] = 5; // 修改栈中首地址为0x8899的第2个变量的值为5
    arr4[1] = new int[] { 1, 2 }; // 栈中开辟空间存放int型变量,长度为2,首地址为0x8899,arr4[1]指向该地址
  4. 案例练习:

    【题目】

    ​ 使用二维数组打印一个10 行杨辉三角

    【提示】

    • 第一行有 1 个元素, 第 n 行有 n 个元素

    • 每一行的第一个元素和最后一个元素都是 1

    • 从第三行开始, 对于非第一个元素和最后一个元素的元素。即:yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];

    程序代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package cn.plushine.exer;

    public class YangHuiTest {
    public static void main(String[] args) {
    int[][] arrayList = new int[10][]; // 由于不确定每行的元素个数,先动态初始化
    for (int i = 0; i < 10; i++) {
    arrayList[i] = new int[i + 1]; // 初始化每行元素数目
    for (int j = 0; j <= i; j++) {
    if (j == 0 || j == i) {
    arrayList[i][j] = 1; // 两边值为1
    } else {
    arrayList[i][j] = arrayList[i - 1][j - 1] + arrayList[i - 1][j];
    }
    }
    }
    for (int i = 0; i < 10; i++) { // 输出
    for (int j = 0; j <= i; j++) {
    System.out.print(arrayList[i][j] + " ");
    }
    System.out.println();
    }
    }
    }

    运行结果:

常见算法

  1. 分类:

    • 数组元素的赋值(杨辉三角、回环数)
    • 求数值型数组中的最大值、最小值、平均数、总和等
    • 数组的复制、反转、查找(线性查找、二分查找)
    • 数组元素的排序算法
  2. 数组的复制:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package cn.plushine.exer;

    public class ArrayTest {
    public static void main(String[] args) {
    int[] arr1 = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

    int[] arr2 = arr1; // arr2赋值为arr1

    for (int i = 0; i < arr1.length; i++) { // 输出arr1的内容
    System.out.print(arr2[i] + "\t");
    }
    System.out.println();

    for (int i = 0; i < arr2.length; i++) { // 修改arr2中偶数位的值
    if (i % 2 == 0) {
    arr2[i] = i;
    }
    }

    for (int i = 0; i < arr1.length; i++) { // 输出arr1
    System.out.print(arr2[i] + "\t");
    }
    }

    }

    运行结果:

    内存分析:

    总结:直接赋值不能实现数组复制,可以使用for循环遍历依次赋值。

  3. 二分查找:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package cn.plushine.exer;

    public class ArrayTest1 {
    public static void main(String[] args) {
    int[] arr1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int aim = 1;
    int l = 0; // 左边界
    int r = arr1.length - 1; // 右边界
    while (l <= r) {
    int mid = (l + r) / 2; // 中间索引
    if (arr1[mid] > aim) { // 当前值>目标值
    r = mid - 1;
    } else if (arr1[mid] < aim) { // 当前值<目标值
    l = mid + 1;
    } else if (arr1[mid] == aim) { // 当前值==目标值
    System.out.println("位置:" + mid); // 1
    System.exit(0); // 退出程序
    }
    }
    System.out.println("未查询到该数!");
    }
    }

    注意:

    • 左右边界可以重合(l <= r)
    • 判断当前值(arr1[mid])和目标值(aim)的大小,修改l、r的值
  4. 排序算法(冒泡排序)

    • 思路:

      • 从头开始比较相邻两变量大小,每次循环结束都会将最大的一个数移动到最后
      • 数组元素个数为n,就需要循环n-1次(选出n-1个最大的数)
    • 动态图:

    • 源代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      package cn.plushine.exer;

      public class ArrayTest2 {
      public static void main(String[] args) {
      int[] arr1 = new int[] { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 }; // 初始数组

      for (int i = 0; i < arr1.length - 1; i++) {
      for (int j = 0; j < arr1.length - i - 1; j++) {
      if (arr1[j] > arr1[j + 1]) { // 交换变量
      int swap = arr1[j];
      arr1[j] = arr1[j + 1];
      arr1[j + 1] = swap;
      }
      }
      }

      for (int i = 0; i < arr1.length; i++) { // 输出排序后数组
      System.out.print(arr1[i] + " ");
      }
      }
      }

Arrays工具类

  1. 基本使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package cn.plushine.exer;

    import java.util.Arrays;

    public class ArrayTest3 {
    public static void main(String[] args) {
    // 1.boolean equals(int[] a,int[] b):判断两个数组是否相等。
    int[] arr1 = new int[] { 1, 2, 3, 4 };
    int[] arr2 = new int[] { 1, 3, 2, 4 };
    boolean isEqual = Arrays.equals(arr1, arr2);
    System.out.println(isEqual); // false,返回布尔值

    // 2.String toString(int[] a):输出数组信息。
    System.out.println(Arrays.toString(arr1)); // [1, 2, 3, 4]

    // 3.void sort(int[] a):对数组进行排序。
    Arrays.sort(arr2);
    System.out.println(Arrays.toString(arr2)); // [1, 2, 3, 4],顺序从小到大

    // 4.进行二分查找
    int[] arr3 = new int[] { -98, -34, 2, 34, 54, 66, 79, 105, 210, 333 };
    int index = Arrays.binarySearch(arr3, -34);
    System.out.println(index); // 1,返回索引值
    }
    }
  2. 运行结果:

数组常见异常

  1. 数组索引越界的异常(ArrayIndexOutOfBoundsExcetion):

    1
    2
    3
    4
    5
    6
    7
    8
    package cn.plushine.exer;

    public class ArrayExceptionTest {
    public static void main(String[] args) {
    int[] arr1 = new int[] { 1, 2, 3, 4 };
    //System.out.println(arr1[4]); // 数组索引越界
    }
    }
  2. 空指针异常(NullPointerException):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package cn.plushine.exer;

    public class ArrayExceptionTest {
    public static void main(String[] args) {
    // 情况1:一维数组
    int[] arr2 = new int[] { 1, 2, 3 };
    arr2 = null;
    System.out.println(arr2[0]);

    // 情况2:二维数组
    int[][] arr3 = new int[4][];
    System.out.println(arr3[0][0]);

    // 情况3:调用方法
    int[][] arr4 = new int[4][];
    System.out.println(arr4[0].toString());

    }
    }

面向对象(上)

面向过程和面向对象

  1. 区别:

    • 面向过程(POP):强调的是功能行为,以函数为最小单位,考虑怎么做。
    • 面向对象(OOP):将功能封装进对象,强调具备了功能的对象,以类、对象为最小单位,考虑谁来做。
  2. 学习代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    package cn.plushine.java;

    /*
    * 一、“人把大象装进冰箱”
    *
    * 1.面向过程:
    *
    * ① 把冰箱门打开
    * ② 把大象装进冰箱
    * ② 把冰箱门关闭
    *
    * 2.面向对象:
    *
    * 人{
    * 打开(冰箱){
    * 冰箱.开门();
    * }
    * 抬起(大象){
    * 大象.进入(冰箱);
    * }
    * 关闭(冰箱){
    * 冰箱.关门();
    * }
    * }
    *
    * 冰箱{
    * 开开(){}
    * 闭合(){}
    * }
    *
    * 大象{
    * 进入(冰箱){}
    * }
    *
    * 二、面向对象的两个要素:
    * 类:对一类事物的描述,是抽象的、概念上的定义
    * 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
    *
    */
    public class OopTest {

    }
  3. 案例练习:

    练习1:我要开车去丽江,这句话包含的类有什么?

    答案:人、车

    练习2:售货员统计收获小票的金额,这句话包含的类有什么?

    答案:人、小票

类和对象

  1. 学习代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    package cn.plushine.java;
    /*
    * 1.类和对象的使用:
    * ①创建类
    * ②创建类对象
    * ③调用对象的属性、方法
    *
    * 2.创建类:设计类的成员(属性、方法)
    * 属性 = 成员变量 = field = 域、字段
    * 方法 = 成员方法 = 函数 = method
    *
    * 3.创建类的对象 = 类的实例化 = 实例化类
    *
    * 4. 注意:创建类对象要在方法中
    *
    */

    public class PersonTest {
    public static void main(String[] args) {
    // ******************创建类对象p1*****************
    Person p1 = new Person();

    // 调用对象的属性:“对象.属性”
    p1.name = "Tom";
    p1.isMale = true;
    System.out.println(p1.name); // "Tom"

    // 调用对象的方法:“对象.方法”
    p1.eat();
    p1.talk("English");

    // ******************创建类对象p2*****************
    Person p2 = new Person();
    System.out.println(p2.name); // 0或'\u0000',而不是"Tom",具体见下文分析
    }
    }

    // 设计类(设计类成员):属性、方法
    class Person {
    // 属性
    String name;
    int age = 1;
    boolean isMale;

    // 方法
    public void eat() {
    System.out.println("人可以吃饭!");
    }

    public void talk(String language) {
    System.out.println("人可以说话,用的语言是:" + language);
    }

    }
  2. 内存分析: p2.name != p1.name

属性(成员变量)

  1. 学习代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    package cn.plushine.java;

    /*
    * 属性(成员变量)VS 局部变量
    *
    * 1.相同点:
    * 1.1 定义变量的格式:数据类型 变量名 = 变量值
    * 1.2 先声明,后使用
    * 1.3 变量都有其对应的作用域
    *
    * 2.不同点:
    * 2.1 在类中声明的位置的不同
    * 属性:直接定义在类的一对{}内
    * 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
    *
    * 2.2 关于权限修饰符的不同
    * 属性:可以在声明属性时,指明其权限,使用权限修饰符。
    * 常用的权限修饰符:private、public、缺省、protected --->封装性
    * 目前,大家声明属性时,都使用缺省就可以了。
    * 局部变量:不可以使用权限修饰符。
    *
    * 2.3 默认初始化值的情况:
    * 属性:类的属性,根据其类型,都有默认初始化值。
    * 整型(byte、short、int、long):0
    * 浮点型(float、double):0.0
    * 字符型(char):0 (或'\u0000')
    * 布尔型(boolean):false
    * 引用数据类型(类、数组、接口):null
    *
    * 局部变量:没有默认初始化值。
    * 意味着,我们在调用局部变量之前,一定要显式赋值。
    *
    * 2.4 在内存中加载的位置:
    * 属性:加载到堆空间中 (非static)
    * 局部变量:加载到栈空间
    *
    */
    public class UserTest {
    public static void main(String[] args) {
    User u1 = new User(); // 创建类对象

    System.out.println(u1.name); // 调用类属性
    u1.eat(); // 调用类方法
    }
    }

    class User {
    String name; // 属性(成员变量)

    public void eat() {
    String food = "烙饼"; // 局部变量
    System.out.println("北方人喜欢吃:" + food);
    }

    }
  2. 内存分析:

方法(成员方法)

  1. 学习代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    package cn.plushine.java;

    /*
    * 类中方法的声明和使用
    *
    * 方法:描述类应该具有的功能。
    * 比如:Person类:eat()\...
    * Math类:sqrt()\random() \...
    * Scanner类:nextXxx() ...
    * Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...
    *
    * 1.方法举例:
    * public void eat(){}
    * public void sleep(int hour){}
    * public String getName(){}
    * public String getNation(String nation){}
    *
    * 2. 方法的声明:权限修饰符 返回值类型 方法名(形参列表){
    * 方法体
    * }
    * 注意:static、final、abstract 来修饰的方法,后面再讲。
    *
    * 3. 说明:
    * 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
    * Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说
    *
    * 3.2 返回值类型: 有返回值 vs 没有返回值
    * 如果方法有返回值,则必须在方法声明时指定返回值的类型,使用void表示无返回值。
    * 方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
    *
    * 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
    *
    * 3.4 形参列表: 方法可以声明0个,1个,或多个形参。
    * 格式:数据类型1 形参1,数据类型2 形参2,...
    *
    * 3.5 方法体:方法功能的体现。
    *
    * 4.return关键字的使用:
    * 1.使用范围:使用在方法体中
    * 2.作用:① 结束方法
    * ② 针对有返回值类型的方法,使用"return 数据"来返回所要的数据。
    * 3.注意点:return关键字后面不可以声明执行语句。
    *
    * 5. 方法的使用中,可以调用当前类的属性或方法
    * 特殊的:方法A中又调用了方法A:递归方法。
    * 方法中,不可以定义方法。
    */
    public class CustomerTest {
    public static void main(String[] args) {
    Customer c1 = new Customer(); // 创建类对象

    c1.name = "Tom"; // 调用类的属性
    c1.status(); // 调用类的方法
    }

    }

    // 设计类
    class Customer {
    String name;
    int age;

    public void status() {
    eat(name); // 方法中调用属性、方法
    }

    public void eat(String name) {
    System.out.println(name + "在吃饭!"); // Tom在吃饭!
    }
    }
  2. 案例练习:

    定义类 Student ,包含三个属性:学号 number(int),年级 state(int),成绩score(int)

    创建 20 个学生对象,学号为 1 到 5 ,年级和成绩都由随机数确定

    • 打印出 3 年级 (state 值为 3 )的学生信息

    • 使用冒泡排序按学生成绩排序,并遍历所有学生信息

    程序代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    package cn.plushine.exer;

    public class Exer3Test {
    public static void main(String[] args) {
    Student[] s1 = new Student[5]; // 创建长度为5的Student类数组

    for (int i = 0; i < s1.length; i++) { // 创建Student类对象并给属性赋值
    s1[i] = new Student();
    s1[i].number = i + 1; // 学号(i+1)
    s1[i].state = (int) (Math.random() * (3 - 1 + 1) + 1); // 年级[1-3]
    s1[i].score = (int) (Math.random() * (100 - 0 + 1) + 0); // 成绩[0-100]
    }

    Exer3Test e1 = new Exer3Test(); // 创建Exer3Test类对象,方便调用该类中方法
    System.out.println("----------------排序前------------------");
    e1.show(s1);
    System.out.println("-------------status == 3----------------");
    e1.showInfo(s1, 3);
    System.out.println("----------------排序后------------------");
    e1.sort(s1);
    e1.show(s1);

    }

    /**
    * @Description 根据score大小,对s1数组排序(递增)
    * @author XJHui
    * @date 2020年12月10日下午8:46:13
    * @param s1 Student类数组
    */
    public void sort(Student[] s1) {
    for (int i = 0; i < s1.length - 1; i++) {
    for (int j = 0; j < s1.length - i - 1; j++) {
    if (s1[j].score > s1[j + 1].score) {
    Student swap = s1[j];
    s1[j] = s1[j + 1];
    s1[j + 1] = swap;
    }
    }
    }
    }

    /**
    * @Description 输出state值为3的信息
    * @author XJHui
    * @date 2020年12月10日下午8:47:08
    * @param s1 Student类数组
    * @param state 年级
    */
    public void showInfo(Student[] s1, int state) {
    for (int i = 0; i < s1.length; i++) {
    if (s1[i].state == 3) {
    System.out.println(s1[i].number + " , " + s1[i].state + " , " + s1[i].score);
    }
    }
    }

    /**
    * @Description 遍历数组并输出所有信息
    * @author XJHui
    * @date 2020年12月10日下午8:47:40
    * @param s1 Student类数组
    */
    public void show(Student[] s1) {
    for (int i = 0; i < s1.length; i++) {
    System.out.println(s1[i].number + " , " + s1[i].state + " , " + s1[i].score);
    }
    }
    }

    // 设计类
    class Student {
    // 属性
    int number; // 学号
    int state; // 年级
    int score; // 成绩
    }

    运行结果:

  3. 匿名对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package cn.plushine.java;

    /*
    * 匿名对象的使用:
    * 1.理解:我们创建的对象,没有显式的赋给一个变量名。
    * 2.特征:匿名对象只能调用一次。
    */
    public class InstanceTest {
    public static void main(String[] args) {
    // Phone p1=new Phone(); // 先创建一个对象,再通过该对象调用属性、方法。
    // p1.sendEmail();

    new Phone().price = 1.23; // 匿名对象,只能调用一次
    System.out.println(new Phone().price); // 0.0,因为每次new都会在内存中开辟新的空间

    PhoneMall pm1 = new PhoneMall(); // 虽然匿名对象只能调用一次,但可通过该方法实现匿名对象的多次调用
    pm1.show(new Phone());
    }
    }

    class Phone {
    double price;

    public void sendEmail() {
    System.out.println("发送邮件!");
    }
    }

    class PhoneMall {
    public void show(Phone phone) {
    phone.price = 1.0;
    System.out.println(phone.price); // 1.0
    }
    }

重载、可变个数形参、值传递、递归

  1. 方法重载:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    package cn.plushine.java;

    /*
    * 1. 定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
    * 2. 判断是否构成重载:跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
    */
    public class OverLoadTest {
    public static void main(String[] args) {
    OverLoadTest ol1=new OverLoadTest();
    ol1.getSum(0, 1);
    }

    // 以下四种方法构成重载(参数数目、类型不同)
    public void getSum(int i, int j) {
    System.out.println("1");
    }

    public void getSum(double d1, double d2) {
    System.out.println("2");
    }

    public void getSum(String s, int i) {
    System.out.println("3");
    }

    public void getSum(int i, String s) {
    System.out.println("4");
    }

    // 以下是错误重载
    // public int getSum(int i, int j) {
    // return 0;
    // }
    //
    // public void getSum(int m, int n) {
    // System.out.println("5");
    // }
    //
    // private void getSum(int i, int j) {
    // System.out.println("6");
    // }
    }
  2. 可变个数的形参:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package cn.plushine.java;

    /*
    * 1.语法:数据类型 ... 变量名
    * 2.参数个数:0个,1个,2个 ...
    * 3.重载:
    * ①可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
    * ②可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载(二者不能共存)
    * 4.注意:
    * ①形参中【可变个数形参】和【非可变个数形参】同时存在时,可变个数形参在最后
    * ②可变个数形参至多有一个
    */
    public class MethodArgsTest {
    public static void main(String[] args) {

    new MethodArgsTest().showInfo("A", "B", "C");
    }

    public void showInfo(String... str) {
    for (int i = 0; i < str.length; i++) {
    System.out.print(str[i] + ' '); // A B C
    }
    }

    // 形参中【可变个数形参】和【非可变个数形参】同时存在时,可变个数形参在最后
    public void showInfo(int num, String... str) {
    for (int i = 0; i < str.length; i++) {
    System.out.print(str[i] + ' ');
    }
    }
    }
  3. 值传递机制

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      package cn.plushine.java;

      /*
      * 方法的形参的传递机制:值传递
      *
      * 1.形参:方法定义时,声明的小括号内的参数
      * 实参:方法调用时,实际传递给形参的数据
      *
      * 2.值传递机制:
      * 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
      * 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
      *
      */
      public class ValueTransferTest {
      public static void main(String[] args) {

      }
      }
    • 案例练习1:

      交换两个变量的值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      public class ValueTransferTest {
      public static void main(String[] args) {
      // 失败方法
      int m = 10;
      int n = 20;

      System.out.println("m = " + m + ", n = " + n); // m = 10, n = 20

      ValueTransferTest vt1 = new ValueTransferTest();
      vt1.swap(m, n); // 参数为基本数据类型,实参传递给形参的是值而非地址

      System.out.println("m = " + m + ", n = " + n); // m = 10, n = 20

      }

      public void swap(int m, int n) {
      int temp = m;
      m = n;
      n = temp;
      }
      }

      内存解析:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      package cn.plushine.java;

      public class ValueTransferTest2 {
      public static void main(String[] args) {
      // 正确方法
      Data d1 = new Data();
      d1.m = 10;
      d1.n = 20;
      System.out.println("d1.m = " + d1.m + ", d1.n = " + d1.n);

      ValueTransferTest2 vt2 = new ValueTransferTest2();
      vt2.swap(d1); // 参数是引用数据类型,实参传递给形参的是地址

      System.out.println("d1.m = " + d1.m + ", d1.n = " + d1.n);
      }

      public void swap(Data data) {
      int swap = data.m;
      data.m = data.n;
      data.n = swap;
      }
      }

      class Data {
      int m;
      int n;
      }

      内存解析:

    • 案例练习2:

      画出下面程序的参数传递图示:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      package cn.plushine.exer;

      public class MethodTransferExer {
      public static void main(String[] args) {
      MethodTransferExer test = new MethodTransferExer();
      test.first();
      }

      public void first() {
      int i = 5;
      Value v = new Value();
      v.i = 25;
      second(v, i);
      System.out.println(v.i); // 20
      }

      public void second(Value v, int i) {
      i = 0;
      v.i = 20;
      Value val = new Value();
      v = val;
      System.out.println(v.i + " " + i); // 15 0
      }
      }

      class Value {
      int i = 15;
      }

      过程图示:

  4. 递归方法:

    • 基本使用:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      package cn.plushine.java;

      /*
      * 1.定义:一个方法调用它自身
      * 2.方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
      * 3.注意:递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
      */
      public class RecursionTest {
      public static void main(String[] args) {
      // 案例
      RecursionTest r1 = new RecursionTest();
      int numSum = r1.getSum(100);
      System.out.println("1-100之间所有自然数的和为:" + numSum); // 5050

      int f10 = r1.f(10);
      System.out.println("f(10)的值为:" + f10); // 10497
      }

      // 1.计算1-100之间所有自然数的和
      public int getSum(int n) {
      if (n == 1) {
      return 1;
      } else {
      return n + getSum(n - 1);
      }
      }

      // 2.已知数列: f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),求 f(10)
      public int f(int n) {
      if (n == 0) {
      return 1;
      } else if (n == 1) {
      return 4;
      } else {
      return 2 * f(n - 1) + f(n - 2);
      }
      }
      }
    • 可能用到递归:汉诺塔问题、斐波那契数列、快速排序、计算阶乘


不足之处,欢迎留言,会及时回复,及时更正!

创作不易,感谢支持!