JAVA基础【第一篇】

文章目录


示例代码下载: CongSec

java的运行机制及特征

  1. 特征

    1. Java语言是面向对象的(oop)

    2. Java语言是健壮的。 Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证

    3. Java语言是跨平台性的。 [即:一个编译好的.class文件可以在多个系统下运行,这种特性称为跨平台]

    4. Java 语言是解释型

      1. 解释性语言:javascript,PHP,java
      2. 编译性语言:c/c++
      3. 区别是:解释性语言,编译后的代码,不能直接被机器执行,需要解释器来执行,编译性语言,编译后的代码,可以直接被机器执行,c/c++
  2. 运行机制

    1. 介绍
      1. JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器,JDK中.

      2. 对于不同的平台,有不同的虚拟机。

      3. Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,到处运行”[说明]

什么是JDK,JRE

  1. JDK

    1. JDK也称java开发的工具包,JDK=JRE+java的开发工具[java,javac,javadoc.javap等],比如说javac hello.java这个就是产生Java虚拟机可以识别的字节码文件
    2. JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。
  2. JRE

    1. JRE 也称Java 运行环境 JRE=JVM+Java的核心类库[类],比如说java hello这个命令就相当于启动java虚拟机的意思
    2. 包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序, 计算机中只需要安装JRE即可。
  3. JDK、JRE和JVM的包含关系

    1. JDK=JRE+开发工具集(例如Javac.java编译工具等)
    2. JRE=JVM+JavaSE标准类库(java核心类库)
    3. 如果只想运行开发好的.class文件只需要JRE

快速入门

  1. 代码示例

    1.  public class hello {
           public static void main(String[] args) {
               System.out.println("hello,world!");
           }
       }
      
       class Dog {
           public static void main(String[] args) {
               System.out.println("hello,小狗狗~");
           }
       }
      
       class Tiger {
           public static void main(String[] args) {
               System.out.println("hello,小老虎~");
           }
       }
      
  2. 原理解释

    1. 使用javac hello.java命令进行编译可以看到当前目录下会生成三个文件,分别是程序的三个类文件,这三个类文件都是可以运行的

  3. 注意事项

    1. 1.Java源文件以.java 为扩展名。源文件的基本组成部分是类(class),如本类中的Hello

      2. Java应用程序的执行入口是main()方法。它有固定的书写格式:

      public static void main(String[] args) {…}

      3.Java语言严格区分大小写。

      4. Java方法由一条条语句构成,每个语句以“;”结束。

      5.大括号都是成对出现的,缺一不可。[习惯,先写{}再写代码]

      6.一个源文件中最多只能有一个public类。其它类的个数不限。

      7.如果源文件包含一个public类,则文件名必须按该类名命名!

      8. 一个源文件中最多只能有一个public类。其它类的个数不限,也可以将main方法写在非public类中,然后指定运行非public 类,这样入口方法就是非public 的main方法

      9.java数值默认是int,double,string,使用float是后面数字要添加f,使用long是添加l,单字符用单引号

      10.一个英文字符占一个字节,在gdk中,一个中文名占两个字节,在utf8中占3个字节

      11.当一个精度高的转化为低的时候会报错

转义字符

  • \t 制表位

  • \n 换行符

  • \r 回车

注释类型

  1. 单行注释 //这里是注释的单行文字

  2. 多行注释 /* 这是一个多行文字 */

  3. 文档注释

    1. /** 这是一个用来演示文档注释的类 @author 某某 @version 1.0 */

变量以及数据类型

  1. 数据类型

    1. 定义
      1. 整数型

        1. byte: 1字节 (8位,有符号)
        2. short: 2字节 (16位,有符号)
        3. int: 4字节 (32位,有符号)
        4. long: 8字节 (64位,有符号)
      2. 浮点数型

        1. float: 4字节 (32位,IEEE 754标准)
        2. double: 8字节 (64位,IEEE 754标准)
      3. 字符型char: 2字节(16位,用来表示Unicode字符)

      4. **字符串型:**​String

      5. **布尔型:**​boolean

    2. 代码示例
      1.  public class hello{
             public static void main(String[] args){
                 int age=30;
                 double score=88.9;
                 char gender='男';
                 String name="king";
                 System.out.println("人的信息如下:");
                 System.out.println(name);
                 System.out.println(age);
                 System.out.println(score);
                 System.out.println(gender);
             }
        
         }
        
  2. 自动类型转换

    1. 介绍
      1. 当java程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换。
    2. 代码示例
      1.  public class hello{
             public static void main(String[] args){
             int a='a';
             System.out.println(a);//97
             }
         }
        
  3. 强制类型转换

    1. 介绍
      1. 如果想不按照精度顺序来进行转换的话,可以进行强制转换,但容易造成精度损失或数据溢出
    2. 代码示例
      1.  public class hello{
             public static void main(String[] args){
             int a=(int)1.9;
             System.out.println(a);//1,会造成精度损失
             int b=2000;
             byte c=(byte)b;
             System.out.println(c);//-48,会造成数据溢出
             }
         }
        

常用编码

  1. ASCII 码

    1. 上个世纪60年代,美国制定了一套字符编码(使用一个字节),对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码。ASCII码一共规定了128个字符的编码,只占用了一个字节的后面7位,最前面的1位统一规定为0。特别提示:一个字节可以表示256个字符,ASCII码只用了128个字符.
    2. 看一个完整的ASCII码表[资料中]
    3. 缺点:不能表示所有字符。
  2. Unicode 编码

    1. Unicode的好处:一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独
      一无二的编码,使用 Unicode 没有乱码的问题。
    2. Unicode 的缺点:一个英文字母和一个汉字都占用2个字节,这对于存储空间来说是浪费。
      3.2的16次方是 65536,所以最多编码是65536个字符。
    3. 编码0—127的字符是与ASCII的编码一样·比如 ‘a’ 在ASCII码是 Ox61, 在 unicode码是
      ox0061, 都对应97. 因此 Unicode码兼容 ASCII码.
  3. UTF-8 编码

    1. UTF—8是在互联网上使用最广的一种Unicode的实现方式(改进)
    2. UTF—8是一种变长的编码方式。它可以使用1—6个字节表示一个符号,根据不
      同的符号而变化字节长度。
    3. 使用大小可变的编码字母占1个字节,汉字占3个字节

运算符

算术运算符

操作符描述示例结果
+正号+77
-负号b=11; -b-11
+9+918
-10-82
*7*856
/9/91
%取模(取余数)11%92
++自增(前):先增加再返回值a=2;b=++a;a=3;b=3
++自增(后):先返回值再增加a=2;b=a++;a=3;b=2
自减(前):先减少再返回值a=2;b=–a;a=1;b=1
自减(后):先返回值再减少a=2;b=a–;a=1;b=2
+字符串拼接“hsp”+“edu”“hspedu”
//i++与++i的区别
public class hello{
    public static void main(String[] args){
        int i = 1;
        i = i++;
        System.out.println(i); // 1
        int a = 1;
        a = ++a;
        System.out.println(a);//2
    }
}

关系运算符

运算符描述实例结果
==相等8==7false
!=不等8!=7true
<小于8<7false
>大于8>7true
<=小于等于8<=7false
>=大于等于8>=7true
instanceof检查是否是类的实例"hsp" instanceof Stringtrue

逻辑运算符

aba&ba&&ba|ba||b!aa^b
truetruetruetruetruetruefalsefalse
truefalsefalsefalsetruetruefalsetrue
falsetruefalsefalsetruetruetruetrue
falsefalsefalsefalsefalsefalsetruefalse
  • 短路与&&

    • 这是一个条件运算符,仅当第一个操作数的结果为 true 时才会评估第二个操作数。如果第一个操作数为 false,那么不论第二个操作数的值是什么,整个表达式的结果都是 false,且第二个操作数不会被评估。这种行为称为“短路”,因为它可以阻止不必要的计算
  • 短路或||

    • 同样是一个条件运算符,仅当第一个操作数的结果为 false 时才会评估第二个操作数。如果第一个操作数为 true,则整个表达式的结果立即确定为 true,并且第二个操作数不会被评估
  • 取反!

    • 这是一个布尔逻辑运算符,用于反转其单个操作数的布尔值。如果操作数为 true,则结果为 false,反之亦然
  • 逻辑与&

    • 作为布尔逻辑运算符时,它需要评估两个操作数,无论第一个操作数的值如何。当用作位运算符时,它执行按位与操作,即对两个操作数的每一位进行与运算
  • 逻辑或|

    • 作为布尔逻辑运算符时,它同样需要评估两个操作数,无论第一个操作数的值如何。作为位运算符时,它执行按位或操作,即对两个操作数的每一位进行或运算
  • 逻辑异或^

    • 作为布尔逻辑运算符,如果两个操作数具有不同的值,则结果为 true;如果两个操作数相同,则结果为 false。作为位运算符,它执行按位异或操作,即对两个操作数的每一位进行异或运算。如果位相同,则结果位为 0;如果位不同,则结果位为 1

三元运算符

  1. 基本语法
    1. 条件表达式?表达式1:表达式2;

      1. 如果条件表达式为true,运算后的结果是表达式1;
        如果条件表达式为false,运算后的结果是表达式2;

运算符的优先级

方向操作符
.,(),{},,
R→L++, --, ~, !(data type)
L→R*, /, %
L→R+, -
L→R<<, >>, >>>,
L→R<, >, <=, >=, instanceof
L→R==, !=
L→R&
L→R^
L→R|
L→R&&
L→R||
L→R?, :
R→L=, *=, /=, %=

+=, -=, <<=, >>=
>>>=, &=, ^=, |=

JAVA包

  1. java.util包

    1. 键盘输入–Scanner类

      1. 介绍
      2. 使用
        1. 导入,import java.util.Scanner;

        2. 代码示例

          1.  import java.util.Scanner;
             public class hello{
                 public static void main(String[] args){
                     Scanner myscanner=new Scanner(System.in);
                     System.out.println("请输入名字");
                     String name=myscanner.next();
                     System.out.println("请输入年龄");
                     int age=myscanner.nextInt();
                     System.out.println("请输入薪水");
                     double sal=myscanner.nextDouble();
                     System.out.println("人的信息如下:");
                     System.out.println("名字="+ name + " 年龄="+ age +" 薪水=" + sal);
                 }
             }
            

进制转换

  1. 介绍

    1. 二进制:0,1,满2进1.以0b或0B开头。
    2. 十进制:0—9,满10进1。
    3. 八进制:0—7,满8进1.以数字0开头表示。
    4. 十六进制:0—9及A(10)—F(15),满16进1.以0x或0X开头表示。此处的A—F不区分大小写。
    5. 十进制十六进制八进制二进制
      0000
      1111
      22210
      33311
      444100
      555101
      666110
      777111
      88101000
      99111001
      10A121010
      11B131011
      12C141100
      13D151101
      14E161110
      15F171111
      16102010000
      17112110001
  2. 代码示例

    1.  public class hello {
           public static void main(String[] args) {
               // 二进制表示
               int n1 = 0b1010; // 表示十进制的 10
               // 十进制表示
               int n2 = 1010; // 直接写的是十进制数
               // 八进制表示
               int n3 = 01010; // 表示十进制的 520
               // 十六进制表示
               int n4 = 0X10101; // 表示十进制的 65793
      
               System.out.println("n1=" + n1);//10
               System.out.println("n2=" + n2);//1010
               System.out.println("n3=" + n3);//520
               System.out.println("n4=" + n4);//65793
      
               // 打印十六进制数0x23A的十进制值
               System.out.println(0x23A); // 表示十进制的 570
           }
       }
      
  3. 进制转换

    1. 二转十

      1. 规则
        1. 从最低位(右边)开始,将每个位上的数提取出来,乘以2的(位数—1)次方,然后求和。
      2. 案例
        1. 0b1011 = 12的(1-1)次方 + 12的(2-1)次方 + 0*2的(3-1)次方 + 1** 2的(4-1)次方 = 1 + 2 + 0 + 8 = 11
    2. 八转十

      1. 规则
        1. 从最低位(右边)开始,将每个位上的数提取出来,乘以8的(位数—1)次方,然后求和。
      2. 案例
        1. 0234=480+3*81+2 8^2=4+24+128=156
    3. 十六转十

      1. 规则
        1. 从最低位(右边)开始,将每个位上的数提取出来,乘以16的(位数—1)次方,然后求和。
      2. 案例
        1. 0x23A=10160+3*161+2 16^2=10+48+512=570
    4. 十转二

      1. 规则
        1. 将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制。
      2. 案例
        1. 步骤十进制数除以2的商余数
          134170
          21781
          3840
          4420
          5210
          6101
        2. 故34转为二进制位0B00100010
    5. 十转八

      1. 规则
        1. 将该数不断除以8,直到商为0为止,然后将每步得到的余数倒过来,就是对应的八进制。
      2. 案例
        1. 131 ÷ 8 = 16 余 3
        2. 16 ÷ 8 = 2 余 0
        3. 2 ÷ 8 = 0 余 2
        4. 十进制数 131 转换成八进制是 203
    6. 十转十六

      1. 规则
        1. 将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的十六进制。
      2. 案例
        1. 以下是转换237为十六进制的详细步骤:

          1. 237 ÷ 16 = 14 余 13
          2. 14 ÷ 16 = 0 余 14

          在十六进制中,数字大于9的部分用字母表示,即:

          • 10 代表 A
          • 11 代表 B
          • 12 代表 C
          • 13 代表 D
          • 14 代表 E
          • 15 代表 F

          根据上述计算,我们得到的余数是13和14。将这些余数替换为十六进制的字符:

          • 13 => D
          • 14 => E

          因此,将余数倒序排列,十进制数237对应的十六进制数是 ED

    7. 二转八

      1. 规则
        1. 从低位开始,将二进制数每三位一组,转成对应的八进制数即可。
      2. 案例
        1. 首先,我们从右边开始,分组每三位:

          • 0b110 101 01
        2. 由于二进制最左边的分组只有两位,我们可以在前面补一个0来使其成为三位,变为 001

          • 0b1 101 101 变为 0b001 101 101
        3. 现在,我们转换每组二进制数为对应的八进制数:

          • 001 对应的八进制是 1
          • 101 对应的八进制是 5
          • 101 对应的八进制是 5
        4. 因此,将二进制数 0b11010101 组合起来得到的八进制数是 155

    8. 二转十六

      1. 规则
        1. 从低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
      2. 案例
          1. 分组每四位:从右边开始,我们将二进制数分为每四位一组:

            • 0b1101 0101
          2. 如果左边的分组不足四位,则可以在前面补0以完成四位,但在此示例中,每组都已完整。

          3. 转换每组:将每个四位二进制数转换为对应的十六进制数:

            • 1101 对应十六进制的 D
            • 0101 对应十六进制的 5
          4. 组合结果:二进制数 0b11010101 转换成十六进制是 D5

    9. 八转二

      1. 规则
        1. 将八进制数每1位,转成对应的一个3位的二进制数即可。
      2. 案例
        1. 分解每一位八进制数

          • 237
        2. 将每位八进制数转换为对应的三位二进制数

          • 八进制的 2 对应二进制的 010(因为 2 的二进制是10,前面补一个0以完成三位)
          • 八进制的 3 对应二进制的 011(因为 3 的二进制是11,前面补一个0以完成三位)
          • 八进制的 7 对应二进制的 111(因为 7 的二进制已经是三位)
        3. 组合结果

          • 将上述转换的二进制数直接拼接起来,即 010011111
    10. 十六转二

      1. 规则
        1. 将十六进制数每1位,转成对应的4位的一个二进制数即可。
      2. 案例
        1. 分解每一位十六进制数

          • 23B(十六进制的B等于十进制的11)
        2. 将每位十六进制数转换为对应的四位二进制数

          • 十六进制的 2 对应二进制的 0010
          • 十六进制的 3 对应二进制的 0011
          • 十六进制的 B 对应二进制的 1011(十进制11的二进制形式)
        3. 组合结果

          • 将上述转换的二进制数直接拼接起来,形成 001000111011

程序控制结构

  1. 顺序控制

    1. 程序从上到下逐行地执行,中间没有任何判断和跳转。
  2. 分支控制

    1. 单分支
      1. 基本语法

        1.  if (条件表达式) {
               // 执行多条语句
               // 语句1
               // 语句2
               // ...
           }
          
    2. 双分支
      1. 基本语法

        1.  if (条件表达式) {
               // 执行代码块1
           } else {
               // 执行代码块2
           }
          
    3. 多分支
      1. 基本语法

        1.  if (条件表达式1) {
               // 执行代码块1
           } else if (条件表达式2) {
               // 执行代码块2
           } else {
               // 执行代码块n
           }
          
  3. 嵌套分支

    1. 介绍
      1. 在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分支外面的分支结构称为外层分支。老师建议:不要超过3层(可读性不好)
    2. 代码示例
      1.  import java.util.Scanner;
        
         public class hello {
             public static void main(String[] args) {
                 Scanner myScanner = new Scanner(System.in);
                 System.out.println("请输入该歌手的成绩:");
                 double score = myScanner.nextDouble();
        
                 if (score > 8.0) {
                     System.out.println("请输入性别 (男/女):");
                     char gender = myScanner.next().charAt(0);
        
                     if (gender == '男') {
                         System.out.println("进入男子组");
                     } else if (gender == '女') {
                         System.out.println("进入女子组");
                     } else {
                         System.out.println("你的性别有误,不能参加决赛");
                     }
                 } else {
                     System.out.println("Sorry, 你被淘汰了");
                 }
        
                 myScanner.close();
             }
         }
        
  4. switch分支结构

    1. 基本语法
      1.  switch (表达式) {
             case 常量1:
                 // 语句块1
                 break;
             case 常量2:
                 // 语句块2
                 break;
             case 常量n:
                 // 语句块n
                 break;
             default:
                 // default语句块
                 break;
         }
        
    2. 代码示例
      1.  //题目:请编写一个程序,该程序可以接收一个字符,比如:a,b,c,d,e,f,ga表示星期一,b表示星期二 .
         //根据用户的输入显示相应的信息.要求使用 switch 语句完成
         import java.util.Scanner;
        
         public class hello {
             public static void main(String[] args) {
                 Scanner myScanner = new Scanner(System.in);
                 System.out.println("请输入一个字符(a-g):");
                 char c1 = myScanner.next().charAt(0);
        
                 switch (c1) {
                     case 'a':
                         System.out.println("今天星期一,猴子穿新衣");
                         break;
                     case 'b':
                         System.out.println("今天星期二,猴子当小二");
                         break;
                     case 'c':
                         System.out.println("今天星期三,猴子爬雪山.");
                         break;
                     default:
                         System.out.println("你输入的字符不正确,没有匹配的");
                         System.out.println("退出了switch,继续执行程序");
                 }
        
                 myScanner.close();
             }
         }
        
    3. 注意事项
      1. 表达式数据类型,应和case后的常量类型一致,或者是可以自动转成可以相互比较的类型,比如输入的是字符,而常量是int

      2. switch(表达式)中表达式的返回值必须是:(byte,short,int,char,enum[枚举],String)

        1.  double c= 1.1;
           switch(c){//错误 case 1.1://错误
               System.out. println("ok3"); 
               break;
           }
          
      3. case子句中的值必须是常量,而不能是变量

      4. default子句是可选的,当没有匹配的case时,执行default

      5. break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有写break,程序会顺序执行到switch结尾,除非遇到break;

  5. for循环结构

    1. 基本语法
      1.  for (循环变量初始化;循环条件;循环变量迭代) {
             循环操作(可以多条语句);
         }
        
    2. 注意事项
      1. 循环条件是返回一个布尔值的表达式
      2. for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。
      3. 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开。
    3. 代码示例
      1.  public class hello {
             public static void main(String[] args) {
                 for (int i = 1; i <= 10; i++) {
                     System.out.println("你好,cong" + i);
                 }
             }
         }
        
  6. while循环控制

    1. 基本语法
      1.  while (循环条件) {
             // 循环体(语句)
             // 循环变量迭代
         }
        
    2. 代码示例
      1.  public class hello {
             public static void main(String[] args) {
                 int i = 1; // 初始化循环变量
                 while (i <= 5) {
                     System.out.println("hello,congsec"+i); // 循环体:打印变量值
                     i++; // 循环变量迭代:使 i 递增
                 }
             }
         }
        
  7. do…while语法控制

    1. 基本语法
      1.  do {
             // 循环体(语句)
             // 循环变量迭代
         } while (循环条件);
        
    2. 代码示例
      1.  public class hello {
             public static void main(String[] args) {
                 int i = 1; // 初始化循环变量
                 do {
                     System.out.println(i); // 循环体:打印变量值
                     i++; // 循环变量迭代:使 i 递增
                 } while (i <= 5); // 循环条件:当 i 小于或等于 5 时继续循环
             }
         }
        
  8. 多重循环

    1. 介绍
      1. 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for,while,do…while均可以作为外层循环和内层循环。【建议一般使用两层,最多不要超过3层,否则,代码的可读性很差】
      2. 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为false时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环[听不懂,走案例]。
    2. 代码示例
      1. 打印九九乘法表

        1.  public class hello {
               public static void main(String[] args) {
                   // 外层循环控制行(乘数)
                   for (int i = 1; i <= 9; i++) {
                       // 内层循环控制列(被乘数)
                       for (int j = 1; j <= i; j++) {
                           // 打印乘法表的一项,格式为:j * i = product
                           System.out.print(j + " * " + i + " = " + (j * i) + "\t"); // 使用 \t 来添加制表符,使输出对齐
                       }
                       // 每完成一行打印一个换行符,开始新的一行
                       System.out.println();
                   }
               }
           }
          
      2. 打印金字塔

        1.  public class hello {
               public static void main(String[] args) {
                   //打印99乘法表
                   for(int x=1; x<=9; x=x+2){
                           if(x!=9) {
                               for (int z = 1; z <= 9 - x; z = z + 2) {
                                   System.out.print(" ");
                               }
                               for (int y = 1; y <= x; y++) {
                                   if (y == 1 | y == x) {
                                       System.out.print("*");
                                   } else {
                                       System.out.print(" ");
                                   }
          
                               }
                               System.out.println();
                           }else{
                               for(int i=1; i<=9; i++){
                                   System.out.print("*");
                               }
                           }
          
                   }
               }
           }
          
           输出结果:
               *
              * *
             *   *
            *     *
           *********
          
  9. 循环控制函数

    1. break函数
      1. 介绍
        1. break语句用于终止某个语句块的执行,一般使用在switch或者循环[for,while,do-while]中
      2. 代码示例
        1. 随机数

          1.  public class hello {
                 public static void main(String[] args) {
                     int count = 0; // 初始化计数器
                     int number = 0; // 初始化随机数变量
            
                     // 无限循环,直到满足条件后用 break 退出
                     while (true) {
                         number = (int) (Math.random() * 100) + 1; // 生成 1 到 100 之间的随机数
                         count++; // 每生成一次,计数器加一
                         System.out.println("Attempt " + count + ": " + number);
            
                         if (number == 97) {
                             break; // 如果生成的数字是 97,退出循环
                         }
                     }
                     // 输出最终结果
                     System.out.println("It took " + count + " attempts to generate the number 97.");
                 }
             }
            
    2. continue函数
      1. 介绍
        1. continue语句用于结束本次循环,继续执行下一次循环。
        2. continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环,这个和前面的标签的使用的规则一样.
      2. 代码示例
        1.  public class hello {
               public static void main(String[] args) {
                   int i = 1; // 初始化 i
                   while (i <= 4) {
                       i++;
                       if (i == 2) {
                           continue; // 当 i 等于 2 时,跳过本次循环的剩余部分
                       }
                       System.out.println("i=" + i); // 打印 i 的值
                   }
               }
           }
           //i=3
           //i=4
           //i=5
          
    3. return函数
      1. 介绍
        1. return使用在方法,表示跳出所在的方法,在讲解方法的时候,会详细的介绍,这里我们简单的提一下。注意:如果 return 写在 main方法,退出程序.
      2. 代码示例
        1.  public class hello {                                           
               public static void main(String[] args) {                   
                   for (int i = 1; i <= 5; i++) {                         
                       if (i == 3) { // 使用双等号 == 进行比较                         
                           System.out.println("cong" + i);               
                           return; // 当 i 等于 3 时,退出 main 方法                   
                       }                                                  
                       System.out.println("Hello World!");                
                   }                                                      
                   System.out.println("go on.."); // 这行代码将不会被执行,因为 main 方法在 i 等于
               }                                                          
           }   
           //Hello World!
           //Hello World!
           //cong3                                       
          

数组,排序和查找

数组

  1. 介绍

    1. 数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型。即:数(数据)组(一组)就是一组数据
  2. 代码示例

    1.  public class hello {                                    
           public static void main(String[] args) {            
               double[] hens = {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1.1
               double totalWeight = 0;                         
               for (int i = 0; i < hens.length; i++) {         
                   totalWeight += hens[i];                     
               }                                               
               System.out.println("总体重=" + totalWeight + " 平均体重=" +
           }                                                   
       }                                                       
       //总体重=267.7 平均体重=24.336363636363636                     
      
    2.  要求:请求出一个数组int[]的最大值{4,-1,9,10,23},并得到对应的下标。
       public class hello {
           // 编写一个main方法
           public static void main(String[] args) {
               int[] arr = {4, -1, 9, 10, 23};
               int max = arr[0]; // 假定第一个元素就是最大值
               int maxIndex = 0; // 初始化最大值的索引
      
               for (int i = 1; i < arr.length; i++) { // 从下标 1 开始遍历 arr
                   if (max < arr[i]) { // 如果 max < 当前元素
                       max = arr[i]; // 把 max 设置成当前元素
                       maxIndex = i; // 更新最大值的索引
                   }
               }
               System.out.println("最大值=" + max + " 最大值的下标  =" + maxIndex);
           }
       }
      
       //最大值=23 最大值的下标  =4
      
  3. 数组的使用

    1. 动态初始化
      1. 语法
        1. 数据类型 数组名[]=new 数据类型[大小]
    2. 动态初始化
      1. 语法
        1. 数据类型 数组名[]; 或者 数据类型[] 数组名;
    3. 静态初始化
      1. 语法
        1. 数据类型 数组名[]={元素值,元素值…}
  4. 注意事项

    1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理
    2. 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用。
    3. 数组创建后,如果没有赋值,有默认值int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
    4. 使用数组的步骤 1. 声明数组并开辟空间 2 给数组各个元素赋值 3 使用数组
    5. 数组的下标是从0开始的。
    6. 数组下标必须在指定范围内使用,否则报:下标越界异常,比如int [] arr=new int[5]; 则有效下标为 0-4

排序

  1. 介绍

    1. 排序是将多个数据,依指定的顺序进行排列的过程。
  2. 内部排序

    1. 指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法、选择式排序法和插入式排序法);
  3. 外部排序

    1. 介绍
      1. 数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法和直接合并排序法)。
    2. 冒泡排序
      1. 介绍
        1. 冒泡排序(BubbleSorting)的基本思想是:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素 的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。
      2. 代码示例
        1.  要求:们将五个无序:24,69,80,57,13使用冒泡排序法将其排成一个从小到大的有序数列
          
           public class hello {
               // 编写一个main方法
               public static void main(String[] args) {
                   int[] arr = {24,69,80,57,13};
                   int temp; // 用于辅助交换的变量
                   for (int i = 0; i < arr.length - 1; i++) { // 外层循环控制总的排序轮次
                       for (int j = 0; j < arr.length - 1 - i; j++) { // 内层循环进行相邻元素比较和交换
                           // 如果前面的数大于后面的数,则交换
                           if (arr[j] > arr[j + 1]) {
                               temp = arr[j];
                               arr[j] = arr[j + 1];
                               arr[j + 1] = temp;
                           }
                       }
                       // 打印每轮排序后的数组状态
                       System.out.println("\n==第" + (i + 1) + "轮==");
                       for (int j = 0; j < arr.length; j++) {
                           System.out.print(arr[j] + "\t");
                       }
                   }
               }
           }
          
           输出结果:
           ==1==
           24	69	57	13	80
           ==2==
           24	57	13	69	80
           ==3==
           24	13	57	69	80
           ==4==
           13	24	57	69	80
          

查找

  1. 顺序查找

    1. 代码示例
      1.  要求:有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:从键盘中任意输入一个名称,判断数列中是否
         包含此名称【顺序查找】要求:如果找到了,就提示找到,并给出下标值。
         import java.util.Scanner;
        
         public class SeqSearch {
             // 编写一个main方法
             public static void main(String[] args) {
                 String[] names = {"白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"};
                 Scanner myScanner = new Scanner(System.in);
                 System.out.println("请输入名字");
                 String findName = myScanner.next();
                 int index = -1;
                 for (int i = 0; i < names.length; i++) {
                     // 比较 字符串比较 equals, 如果要找到名字就是当前元素
                     if (findName.equals(names[i])) {
                         System.out.println("恭喜你找到 " + findName);
                         System.out.println("下标为= " + i);
                         // 把 i 保存到 index
                         index = i;
                         break; // 退出循环
                     }
                 }
                 if (index == -1) { // 没有找到
                     System.out.println("sorry, 没有找到 " + findName);
                 }
                 myScanner.close(); // 关闭扫描器
             }
         }
        
  2. 二分查找

    1. 此部分先跳过

二维数组

  1. 介绍

    1. 在Java中,二维数组是数组的数组,通常用于存储表格数据,例如矩阵。它可以看作是有多行多列的数组,每一行都是一个一维数组。
  2. 使用

    1. 动态初始化
      1. 基本语法
        1. 类型[][] 数组名=new 类型[大小][大小];
      2. 代码示例
        1.  public class hello {
               // 编写一个main方法
               public static void main(String[] args) {
                   int[][] arr; // 声明二维数组
                   arr = new int[2][3]; // 再开空间
                   arr[1][1] = 8; // 初始化其中一个元素
          
                   // 遍历arr数组
                   for (int i = 0; i < arr.length; i++) {
                       for (int j = 0; j < arr[i].length; j++) { // 对每个一维数组遍历
                           System.out.print(arr[i][j] + " "); // 打印元素和一个空格
                       }
                       System.out.println(); // 换行
                   }
               }
           }
           //0 0 0 
           //0 8 0 
          
    2. 动态初始化
      1. 基本语法
        1. 类型 数组名[][];
      2. 代码示例
        1.  public class hello {
               // 编写一个main方法
               public static void main(String[] args) {
                   int[][] arr = new int[3][];
                   for (int i = 0; i < arr.length; i++) { // 遍历 arr 的每个一维数组
                       arr[i] = new int[i + 1]; // 给每个一维数组开空间 new
                       // 如果没有给一维数组 new, 那么 arr[i] 就是 null
                       // 遍历一维数组,并给一维数组的每个元素赋值
                       for (int j = 0; j < arr[i].length; j++) {
                           arr[i][j] = i + 1; // 赋值
                       }
                   }
                   // 遍历arr输出
                   for (int i = 0; i < arr.length; i++) {
                       // 输出arr的每个一维数组
                       for (int j = 0; j < arr[i].length; j++) {
                           System.out.print(arr[i][j] + " "); // 在输出数字后添加一个空格
                       }
                       System.out.println(); // 换行
                   }
               }
           }
           //1
           //2 2
           //3 3 3
          
    3. 静态初始化
      1. 基本语法
        1. 类型数组名[][] ={{值1,值2…},{值1,值2…},{值1,值2…}};
  3. 代码示例

    1.  public class TwoDimensionalArray01 {
           // 编写一个main方法
           public static void main(String[] args) {
               int[][] arr = {
                   {0, 0, 0, 0, 0, 0},
                   {0, 0, 1, 0, 0, 0},
                   {0, 2, 0, 3, 0, 0},
                   {0, 0, 0, 0, 0, 0}
               };
      
               // 关于二维数组的关键概念
               System.out.println("二维数组的元素个数=" + arr.length);
         
               // 举例访问第3个一维数组的第4个值,它是3
               System.out.println("第3个一维数组的第4个值=" + arr[2][3]); // 输出3
      
               // 输出二维图形
               for (int i = 0; i < arr.length; i++) { // 遍历二维数组的每个元素
                   for (int j = 0; j < arr[i].length; j++) { // 遍历二维数组的每个元素(数组)
                       System.out.print(arr[i][j] + " "); // 输出一维数组的元素,并添加空格
                   }
                   System.out.println(); // 换行
               }
           }
       }
      
       输出结果:
       二维数组的元素个数=43个一维数组的第4个值=3
       0 0 0 0 0 0 
       0 0 1 0 0 0 
       0 2 0 3 0 0 
       0 0 0 0 0 0 
      
    2. 杨辉三角

      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 int[][] yangHui = new int[9][];
                 for (int i = 0; i < yangHui.length; i++) { // 遍历 yangHui 的每个元素
                     // 给每个一维数组(行) 开空间
                     yangHui[i] = new int[i + 1];
                     // 给每个一维数组(行) 赋值
                     for (int j = 0; j < yangHui[i].length; j++) {
                         // 每一行的第一个元素和最后一个元素都是1
                         if (j == 0 || j == yangHui[i].length - 1) {
                             yangHui[i][j] = 1;
                         } else { // 中间的元素
                             yangHui[i][j] = yangHui[i - 1][j] + yangHui[i - 1][j - 1];
                         }
                     }
                 }
                 // 输出杨辉三角
                 for (int i = 0; i < yangHui.length; i++) {
                     for (int j = 0; j < yangHui[i].length; j++) { // 遍历输出该行
                         System.out.print(yangHui[i][j] + "\t");
                     }
                     System.out.println(); // 换行.
                 }
             }
         }
        
         输出结果:
         1
         1	1
         1	2	1
         1	3	3	1
         1	4	6	4	1
         1	5	10	10	5	1
         1	6	15	20	15	6	1
         1	7	21	35	35	21	7	1
         1	8	28	56	70	56	28	8	1
        

类与对象

  1. 介绍

    1. 在面向对象编程(OOP)中, 是定义对象属性和行为的蓝图,它是一种抽象的数据类型,而对象 是根据类的模板创建的具体实例。类定义了一组属性(数据字段)和方法(函数),对象则是这些属性和方法的具体化,每个对象都独立拥有自己的属性值但共享同一类的方法。这种机制使得软件开发更加模块化,易于管理和维护。
  2. 区别和联系

    1. 类是抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型.
    2. 对象是具体的,实际的,代表一个具体事物, 即 是实例.
    3. 类是对象的模板,对象是类的一个个体,对应一个实例
  3. 创建对象

    1. 先声明再创建

      1. Cat cat ; //声明对象 cat
      2. cat = new Cat(); //创建
    2. 直接创建

      1. Cat cat = new Cat();
  4. 克隆对象

    1. 代码示例

      1.  public class hello {
             // 编写一个 main 方法
             public static void main(String[] args) {
                 // 创建第一只猫对象 cat1
                 Cat cat1 = new Cat();
                 cat1.name = "小白";
                 cat1.age = 3;
                 cat1.color = "白色";
                 cat1.weight = 10;
        
                 // 创建第二只猫对象 cat2
                 Cat cat2 = new Cat();
                 cat2.name = "小花";
                 cat2.age = 100;
                 cat2.color = "花色";
                 cat2.weight = 20;
        
                 // 输出第一只猫的信息
                 System.out.println("第 1 只猫信息: " + cat1.name + " " + cat1.age + " " + cat1.color + " " + cat1.weight);
        
                 // 输出第二只猫的信息
                 System.out.println("第 2 只猫信息: " + cat2.name + " " + cat2.age + " " + cat2.color + " " + cat2.weight);
             }
         }
        
         // 定义猫类 Cat -> 自定义的数据类型
         class Cat {
             // 属性/成员变量
             String name;   // 名字
             int age;       // 年龄
             String color;  // 颜色
             double weight; // 体重
             // 行为可以通过定义方法来表示,如 miaow() 方法等,目前暂未定义行为
         }
         //第 1 只猫信息: 小白 3 白色 10.0
         //第 2 只猫信息: 小花 100 花色 20.0
        
  5. 属性

    1. 介绍
      1. 成员变量 = 属性 =field(字段) (即 成员变量是用来表示属性的,授课中,统一叫 属性)
      2. 属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。比如我们前面定义猫类的int age就 是属性
    2. 注意事项
      1. 属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;
      2. 属性的定义类型可以为任意类型,包含基本类型或引用类型
      3. 属性如果不赋值,有默认值,规则和数组一致。具体说:int 0,shor t0,byte 0,lon g0,float 0.0,double 0.0,char \u0000, boolean false,String null
    3. 代码示例
      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 // 创建Person 对象
                 // p1 是对象名(对象引用)
                 // new Person() 创建的对象空间(数据) 才是真正的对象
                 Person p1 = new Person();
                 // 对象的属性默认值,遵守数组规则:
                 // int 0,short 0, byte 0, long 0, float 0.0, double 0.0,char \u0000,boolean false,String null
                 System.out.println("\n当前这个人的信息");
                 System.out.println("age=" + p1.age + " name=" + p1.name + " sal=" + p1.sal + " isPass=" + p1.isPass);
             }
         }
        
         class Person {
             // 四个属性
             int age;
             String name;
             double sal;
             boolean isPass;
         }
        
         输出结果:
         当前这个人的信息
         age=0 name=null sal=0.0 isPass=false
        
  6. 内存分配机制

    1. 代码

      1.  Person p1=new Person(); 
         p1.age=10;
         p1.name="小明";
         Person p2=p1;//把p1赋给了p2,让p2指向p1 
         System.out.println(p2.age);
        
    2. 机制原理图

  7. 方法

    1. 介绍
      1. 在某些情况下,我们要需要定义成员方法(简称方法)。比如人类:除了有一些属性外(年龄,姓名.),我们人类还有一些行为比如:可以说话、跑步.,通过学习,还可以做算术题。这时就要用成员方法才能完成。现在要求对Person类完善。
    2. 基本使用
      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 // 方法使用
                 // 1.方法写好后,如果不去调用(使用),不会输出
                 // 2.先创建对象,然后调用方法即可
                 Person p1 = new Person();
                 p1.speak(); // 调用speak方法
                 p1.cal01(); // 调用cal01方法
                 p1.cal02(5); // 调用cal02方法,同时给n=5
                 p1.cal02(10); // 调用cal02方法,同时给n=10
                 // 调用getSum方法,同时num1=10, num2=20
        
                 // 把方法getSum返回的值,赋给变量returnRes
                 int returnRes = p1.getSum(10, 20);
                 System.out.println("getSum 方法返回的值 = " + returnRes);
             }
         }
        
         class Person {
             String name;
             int age;
        
             // 方法(成员方法)
             // 添加speak成员方法,输出“我是一个好人”
             public void speak() {
                 System.out.println("我是一个好人");
             }
        
             // 添加cal01成员方法,可以计算从1+..+1000的结果
             public void cal01() {
                 int res = 0;
                 for (int i = 1; i <= 1000; i++) {
                     res += i;
                 }
                 System.out.println("cal01 方法计算结果 = " + res);
             }
        
             // 添加cal02成员方法,该方法可以接收一个数n,计算从1+..+n的结果
             public void cal02(int n) {
                 int res = 0;
                 for (int i = 1; i <= n; i++) {
                     res += i;
                 }
                 System.out.println("cal02 方法计算结果 = " + res);
             }
        
             // 添加getSum成员方法,可以计算两个数的和
             public int getSum(int num1, int num2) {
                 int res = num1 + num2;
                 return res;
             }
         }
        
         输出结果:
         我是一个好人
         cal01 方法计算结果 = 500500
         cal02 方法计算结果 = 15
         cal02 方法计算结果 = 55
         getSum 方法返回的值 = 30
        
    3. 方法的使用细节和注意事项
      1. 基本使用
        1. 访问修饰符返回数据类型方法名(形参列表…){//方法体

          语句;
          return返回值;
          }

      2. 注意事项
        1. 一个方法最多有一个返回值 [思考,如何返回多个结果 返回数组 ]
        2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
        3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值; 而且要求返回值类型必须和return的 值类型一致或兼容
        4. 如果方法是void,则方法体中可以没有return语句,或者 只写 return;
      3. 代码示例
        1.  public class MethodDetail {
               public static void main(String[] args) {
                   AA a = new AA();
                   int[] res = a.getSumAndSub(1, 4);
                   System.out.println("和 = " + res[0]);
                   System.out.println("差 = " + res[1]);
             
                   // 细节: 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数
                   byte b1 = 1;
                   byte b2 = 2;
                   a.getSumAndSub(b1, b2); // byte -> int
             
                   // a.getSumAndSub(1.1, 1.8); // double -> int (×)
             
                   // 细节: 实参和形参的类型要一致或兼容、个数、顺序必须一致
                   // a.getSumAndSub(100); // × 个数不一致
             
                   a.f3("tom", 10); // ok
                   // a.f3(100, "jack"); // 实际参数和形式参数顺序不对
               }
           }
          
           class AA {
               // 细节: 方法不能嵌套定义
               public void f4() {
                   // 错误
                   // public void f5() {
                   // }
               }
             
               public void f3(String str, int n) {
               }
          
               // 1. 一个方法最多有一个返回值 [思考,如何返回多个结果,返回数组]
               public int[] getSumAndSub(int n1, int n2) {
                   int[] resArr = new int[2];
                   resArr[0] = n1 + n2;
                   resArr[1] = n1 - n2;
                   return resArr;
               }
          
               // 2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
               // 具体看 getSumAndSub
          
               // 3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为 return 值;
               // 而且要求返回值类型必须和 return 的值类型一致或兼容
               public double f1() {
                   double d1 = 1.1 * 3;
                   int n = 100;
                   return n; // int -> double
                   // return d1; // ok? double -> int
               }
          
               // 最好是见名知意
               public void f2() {
                   // 如果方法是 void,则方法体中可以没有 return 语句,或者只写 return;
                   // 老韩提示:在实际工作中,我们的方法都是为了完成某个功能,所以方法名要有一定含义
                   System.out.println("hello1");
                   System.out.println("hello1");
                   System.out.println("hello1");
                   int n = 10;
                   // return;
               }
           }
          
           //和 = 5
           //差 = -3
          
    4. 传参机制
      1. 基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参!

        1.  public class hello {
               // 编写一个main方法
               public static void main(String[] args) {
                   int a = 10;
                   int b = 20;
                   // 创建AA对象名字obj
                   AA obj = new AA();
                   obj.swap(a, b); // 调用swap
                   System.out.println("main方法a=" + a + " b=" + b); // a=10 b=20
               }
           }
           class AA {
               public void swap(int a, int b) {
                   System.out.println("\na和b交换前的值\na=" + a + "\tb=" + b); // a=10 b=20
                   // 完成了a和b的交换
                   int tmp = a;
                   a = b;
                   b = tmp;
                   System.out.println("\na和b交换后的值\na=" + a + "\tb=" + b); // a=20 b=10
               }
           }
          
           输出结果:
           a和b交换前的值
           a=10	b=20
          
           a和b交换后的值
           a=20	b=10
           main方法a=10 b=20
          
      2. B类中编写一个方法test100,可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化?会变化 ;B类中编写一个方法test200,可以接收一个Person(age,sal)对象,在方法中修改该对象属性,看看原来的对象是否变化?会变化;引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!

        1.  public class hello {
               // 编写一个main方法
               public static void main(String[] args) {
                   // 测试
                   B b = new B(); // Corrected the instantiation of class B
                   int[] arr = {1, 2, 3};
                   b.test100(arr); // 调用方法
                   System.out.println("main 的 arr 数组 ");
                   // 遍历数组
                   for(int i = 0; i < arr.length; i++) {
                       System.out.print(arr[i] + "\t");
                   }
                   System.out.println(); // Moved inside the for loop to correct syntax
          
                   // 测试
                   Person p = new Person();
                   p.name = "jack";
                   p.age = 10;
                   b.test200(p);
                   // 测试题, 如果 test200 执行的是 p=null,下面的结果是 10
                   // 测试题, 如果 test200 执行的是 p=new Person();..., 下面输出的是10
                   System.out.println("main 的 p.age=" + p.age); // 10 is printed because the object reference is not changed in test200
               }
           }
          
           class Person {
               String name;
               int age;
           }
          
           class B {
               public void test200(Person p) {
                   p.age = 10000; // 修改对象属性
                   // 可以选择下面的代码来测试不同的行为
                   // p = new Person(); // This will not affect 'p' in the main method
                   // p.name = "tom";
                   // p.age = 99;
                   // p = null; // This will not affect 'p' in the main method
               }
          
               // B 类中编写一个方法test100,
               // 可以接收一个数组,在方法中修改该数组,看看原来的数组是否变化
               public void test100(int[] arr) {
                   arr[0] = 200; // 修改元素
                   // 遍历数组
                   System.out.println("test100 的 arr 数组 ");
                   for(int i = 0; i < arr.length; i++) {
                       System.out.print(arr[i] + "\t");
                   }
                   System.out.println();
               }
           }
          
           输出结果:
           test100 的 arr 数组 
           200	2	3
           main 的 arr 数组 
           200	2	3
           main 的 p.age=10000
          

递归机制

  1. 介绍

    1. 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解决复杂问题,同时可以让代码变 得简洁
  2. 代码示例

    1.  public class hello {
           //编写一个main方法
           public static void main(String[] args) {
               T t1 = new T();
               t1.test(4); // 输出 n=2 n=3 n=4
               int res = t1.factorial(5);
               System.out.println("5 的阶乘 res = " + res);
           }
       }
      
       class T {
           // 分析
           public void test(int n) {
               if (n > 2) {
                   test(n - 1); // 递归调用
               }
               System.out.println("n=" + n);
           }
      
           // factorial 阶乘
           public int factorial(int n) {
               if (n == 1) {
                   return 1;
               } else {
                   return factorial(n - 1) * n;
               }
           }
       }
      
       输出结果:
       n=2
       n=3
       n=4
       5 的阶乘 res = 120
      
    2. 递归斐波那契函数

      1. 请使用递归的方式求出斐波那契数1,1,2,3,5,8,13…给你一个整数n,求出它的值是多少

      2. 猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再多吃一个。当到第10天时,想再吃时(即还没吃),发现只有1个桃子了。问题:最初共多少个桃子?

        1.  public class hello {
               // 编写一个 main 方法
               public static void main(String[] args) {
                   T t1 = new T();
          
                   // 斐波那契数列问题
                   int n = 7;
                   int res = t1.fibonacci(n);
                   if (res != -1) {
                       System.out.println("当 n = " + n + " 对应的斐波那契数 = " + res);
                   }
          
                   // 桃子问题
                   int day = 1;
                   int peachNum = t1.peach(day);
                   if (peachNum != -1) {
                       System.out.println("第 " + day + " 天有 " + peachNum + " 个桃子");
                   }
               }
           }
          
           class T {
               /*
               请使用递归的方式求出斐波那契数 1, 1, 2, 3, 5, 8, 13... 给你一个整数 n,求出它的值
               思路分析:
               1. 当 n = 1,斐波那契数是 1
               2. 当 n = 2,斐波那契数是 1
               3. 当 n >= 3,斐波那契数是前两个数的和
               4. 这就是一个递归的思路
               */
               public int fibonacci(int n) {
                   if (n >= 1) {
                       if (n == 1 || n == 2) {
                           return 1;
                       } else {
                           return fibonacci(n - 1) + fibonacci(n - 2);
                       }
                   } else {
                       System.out.println("要求输入的 n >= 1 的整数");
                       return -1;
                   }
               }
          
               /*
               猴子吃桃子问题:有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!
               以后每天猴子都吃其中的一半,然后再多吃一个。当到第 10 天时,
               想再吃时(即还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子?
               思路分析(逆推):
               1. day = 10 时,有 1 个桃子
               2. day = 9 时,有 (day10 + 1) * 2 = 4 个桃子
               3. day = 8 时,有 (day9 + 1) * 2 = 10 个桃子
               4. 规律就是:前一天的桃子 = (后一天的桃子 + 1) * 2
               5. 递归
               */
               public int peach(int day) {
                   if (day == 10) { // 第 10 天,只有 1 个桃子
                       return 1;
                   } else if (day >= 1 && day <= 9) {
                       return (peach(day + 1) + 1) * 2;
                   } else {
                       System.out.println("day 在 1-10 之间");
                       return -1;
                   }
               }
           }
          
           输出结果:
           当 n = 7 对应的斐波那契数 = 131 天有 1534 个桃子
          
      3. ((20240506132650-lz0vjc3 ‘走出迷宫’))

      4. ((20240506181958-4dv5m3n ‘汉诺塔’))

  3. 原理图

方法重载

  1. 介绍

    1. java中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!比如: System.out.printin“hello”); out是PrintStream类型
  2. 代码示例

    1.  public class hello {
           // 编写一个 main 方法
           public static void main(String[] args) {
               // 调用不同的 calculate 方法,验证方法重载
               MyCalculator mc = new MyCalculator();
               System.out.println(mc.calculate(1, 2)); // 调用 calculate(int, int)
               System.out.println(mc.calculate(1.1, 2)); // 调用 calculate(double, int)
               System.out.println(mc.calculate(1, 2.1)); // 调用 calculate(int, double)
               System.out.println(mc.calculate(1, 2, 3)); // 调用 calculate(int, int, int)
           }
       }
      
       class MyCalculator {
           // 下面的四个 calculate 方法构成了重载
      
           // 1. 两个整数的和
           public int calculate(int n1, int n2) {
               System.out.println("calculate(int n1, int n2) 被调用");
               return n1 + n2;
           }
      
           // 2. 一个整数和一个 double 的和
           public double calculate(int n1, double n2) {
               System.out.println("calculate(int n1, double n2) 被调用");
               return n1 + n2;
           }
      
           // 3. 一个 double 和一个整数的和
           public double calculate(double n1, int n2) {
               System.out.println("calculate(double n1, int n2) 被调用");
               return n1 + n2;
           }
      
           // 4. 三个整数的和
           public int calculate(int n1, int n2, int n3) {
               System.out.println("calculate(int n1, int n2, int n3) 被调用");
               return n1 + n2 + n3;
           }
       }
      
       输出结果:
       calculate(int n1, int n2) 被调用
       3
       calculate(double n1, int n2) 被调用
       3.1
       calculate(int n1, double n2) 被调用
       3.1
       calculate(int n1, int n2, int n3) 被调用
       6
      
  3. 注意事项

    1. 方法名:必须相同
    2. 形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)
    3. 返回类型:无要求

可变参数

  1. 基本概念

    1. java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现
  2. 基本语法

    1. 访问修饰符 返回类型 方法名(数据类型…形参名){ }
  3. 代码示例

    1.  public class hello {
           // 编写一个main方法
           public static void main(String[] args) {
               HspMethod m = new HspMethod();
               System.out.println(m.sum(1, 5, 100));  // 106
               System.out.println(m.sum(1, 19));      // 20
           }
       }
      
       class HspMethod {
           // 使用可变参数来计算多个数的和
           // 1. int... 表示接收可变数量的 int 类型参数
           // 2. nums 可当作数组来使用
           // 3. 遍历 nums 进行求和
           public int sum(int... nums) {
               // System.out.println("接收的参数个数=" + nums.length);
               int res = 0;
               for (int i = 0; i < nums.length; i++) {
                   res += nums[i];
               }
               return res;
           }
       }
       //106
       //20
      
    2. 有三个方法,分别实现返回姓名和两门课成绩(总分),返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。封装成一个可变参数的方法

      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 HspMethod hm = new HspMethod();
                 System.out.println(hm.showScore("milan", 90.1, 80.0));  // milan有2门课的成绩总分为=170.1
                 System.out.println(hm.showScore("terry", 90.1, 80.0, 10, 30.5, 70));  // terry有5门课的成绩总分为=280.6
             }
         }
        
         class HspMethod {
             /*
             有三个方法,分别实现返回姓名和两门课成绩(总分),
             返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。
             封装成一个可变参数的方法
             分析:
             1. 方法名 showScore
             2. 形参(String, double...)
             3. 返回 String
             */
             public String showScore(String name, double... scores) {
                 double totalScore = 0;
                 for (int i = 0; i < scores.length; i++) {
                     totalScore += scores[i];
                 }
                 return name + "有" + scores.length + "门课的成绩总分为=" + totalScore;
             }
         }
         //milan有2门课的成绩总分为=170.1
         //terry有5门课的成绩总分为=280.6
        
  4. 注意事项

    1. 可变参数的实参可以为0个或任意多个。
    2. 可变参数的实参可以为数组。可变参数的本质就是数组
    3. 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
    4. 一个形参列表中只能出现一个可变参数

作用域

  1. 介绍

    1. 面向对象中,变量作用域是非常重要知识点,相对来说不是特别好理解,请大家注意听,认真思考,要求深刻掌握变量作用域。
  2. 注意事项

    1. 全局变量(属性)可以不赋值,局部变量必须赋值后,才能使用,因为没有默认值
    2. 属性和局部变量可以重名,访问时遵循就近原则。
    3. 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。
    4. 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。即在一次方法调用过程中。
    5. 作用域范围不同
      全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)局部变量:只能在本类中对应的方法中使用
    6. 修饰符不同
      全局变量/属性可以加修饰符,局部变量不可以加修饰符
  3. 代码示例

    1.  public class hello {
           // 编写一个main方法
           public static void main(String[] args) {
               Person p1 = new Person();
               /*
               属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
               局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。
               即在一次方法调用过程中。
               */
               // p1.say(); // 当执行 say 方法时,say 方法的局部变量比如 name 会创建,当 say 执行完毕后,
               // name 局部变量就销毁,但是属性(全局变量)仍然可以使用。
      
               T t1 = new T();
               t1.test();   // 第 1 种跨类访问对象属性的方式
               t1.test2(p1); // 第 2 种跨类访问对象属性的方式
           }
       }
      
       class T {
           // 全局变量/属性:可以被本类使用,或通过对象被其他类使用
           public void test() {
               Person p1 = new Person();
               System.out.println(p1.name); // 输出: jack
           }
      
           public void test2(Person p) {
               System.out.println(p.name); // 输出: jack
           }
       }
      
       class Person {
           // 细节: 属性可以加修饰符 (public, protected, private...)
           // 局部变量不能加修饰符
           public int age = 20;
           String name = "jack";
      
           public void say() {
               // 细节: 属性和局部变量可以重名,访问时遵循就近原则
               String name = "king";
               System.out.println("say() name=" + name); // 输出: king (就近原则,使用局部变量)
           }
      
           public void hi() {
               String address = "北京";
               // String address = "上海"; // 错误,重复定义变量
               String name = "hsp"; // 这是可以的,局部变量和全局变量同名,使用局部变量
           }
       }
       //jack
       //jack
      

构造器

  1. 介绍

    1. 构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:

      1. 方法名和类名相同
      2. 没有返回值
      3. 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。
  2. 语法

    1. [修饰符] 方法名(形参列表){
      方法体;
      }
  3. 注意事项

    1. 一个类可以定义多个不同的构造器,即构造器重载
      比如:我们可以再给Person类定义一个构造器,用来创建对象的时候,只指定人名不需要指定年龄
    2. 构造器名和类名要相同
    3. 构造器没有返回值
    4. 构造器是完成对象的初始化,并不是创建对象
    5. 在创建对象时,系统自动的调用该类的构造方法
    6. 如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器),比如Dog (),使用javap指令 反编译看看
    7. 一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下,即:Dog()0写(这点很重要)
  4. 代码示例

    1. 在创建人类的对象时,就直接指定这个对象的年龄和姓名

      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 // 当我们 new 一个对象时,直接通过构造器指定名字和年龄
                 Person p1 = new Person("smith", 80);
                 System.out.println("p1 的信息如下");
                 System.out.println("p1 对象 name=" + p1.name); // smith
                 System.out.println("p1 对象 age=" + p1.age);   // 80
             }
         }
        
         // 在创建 Person 类的对象时,直接指定这个对象的年龄和姓名
         class Person {
             String name;
             int age;
        
             // 构造器
             // 老韩解读:
             // 1. 构造器没有返回值,也不能写 void
             // 2. 构造器的名称和类名 Person 一样
             // 3. (String pName, int pAge) 是构造器的形参列表,规则和成员方法一样
             public Person(String pName, int pAge) {
                 System.out.println("构造器被调用~~ 完成对象的属性初始化");
                 name = pName;
                 age = pAge;
             }
         }
        
         输出结果:
         构造器被调用~~ 完成对象的属性初始化
         p1 的信息如下
         p1 对象 name=smith
         p1 对象 age=80
        
    2.  public class hello {
           // 编写一个main方法
           public static void main(String[] args) {
               Person p1 = new Person("king", 40); // 第1个构造器
               Person p2 = new Person("tom"); // 第2个构造器
               Dog dog1 = new Dog(); // 使用的是默认的无参构造器
           }
       }
      
       class Dog {
           // 如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器)
           // 使用javap 指令 反编译看看
      
           // 一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,
           // 除非显式的定义一下,即: Dog(){} 写 (这点很重要)
      
           // 显式的定义一下无参构造器
           Dog() {
           }
      
           // 带参数的构造器
           public Dog(String dName) {
               //...
           }
       }
      
       class Person {
           String name;
           int age; // 默认 0
      
           // 第1个构造器
           public Person(String pName, int pAge) {
               name = pName;
               age = pAge;
           }
      
           // 第2个构造器,只指定人名,不需要指定年龄
           public Person(String pName) {
               name = pName;
           }
       }
      
       结果:编译成功
      
    3. 第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
      第二个带pName和pAge两个参数的构造器:使得每次创建Person对象的同时初始化对象的age属性值和name属性值。 分别使用不同的构造器,创建对象

      1.  public class hello {
             // 编写一个main方法
             public static void main(String[] args) {
                 Person p1 = new Person(); // 无参构造器
                 // 下面输出 name=null, age=18
                 System.out.println("p1 的信息 name=" + p1.name + " age=" + p1.age);
        
                 Person p2 = new Person("scott", 50);
                 // 下面输出 name=scott, age=50
                 System.out.println("p2 的信息 name=" + p2.name + " age=" + p2.age);
             }
         }
        
         /**
          * 在前面定义的Person类中添加两个构造器:
          * 第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
          * 第二个带pName和pAge两个参数的构造器:
          * 使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
          * 分别使用不同的构造器,创建对象.
          */
         class Person {
             String name; // 默认值 null
             int age; // 默认 0
        
             public Person() {
                 // 第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
                 age = 18;
             }
        
             // 第二个带pName和pAge两个参数的构造器
             public Person(String pName, int pAge) {
                 name = pName;
                 age = pAge;
             }
         }
         //p1 的信息 name=null age=18
         //p2 的信息 name=scott age=50
        
      2.  文件:hello.java
         无参构造器的使用:
         public class hello {
             private int number;
             private String name;
        
             // 显式定义的无参构造器
             public hello() {
                 this.number = 0;
                 this.name = "Default Name";
                 System.out.println("无参构造器被调用,对象已创建");
             }
        
             // 方法示例
             public void displayInfo() {
                 System.out.println("Number: " + number + ", Name: " + name);
             }
        
             public static void main(String[] args) {
                 hello obj = new hello();
                 obj.displayInfo();
             }
         }
        
         //无参构造器被调用,对象已创建
         //Number: 0, Name: Default Name
        

  1. 介绍

    1. 包的本质实际上就是创建不同的文件夹来保存类文件
  2. 常用的包

    1. java.lang.* //lang包是基本包,默认引入,不需要再引入.
    2. java.util.* //util 包,系统提供的工具包,工具类,使用 Scanner
    3. java.net.* //网络包,网络开发
    4. java.awt.* //是做java的界面开发,GUI
  3. 注意事项

    1. package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package
    2. import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
  4. 代码示例

    1. 基本使用
      1.  文件结构:
         D:.
         └─com
             └─hspedu
                 └─pkg
                     └─pkgdetail.java
         pkgdetail.java代码:
         // package的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,
         // 一个类中最多只有一句package
         package com.hspedu.pkg;
        
         // import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求
         import java.util.Scanner;
         import java.util.Arrays;
        
         // 类定义
         public class pkgdetail {
             public static void main(String[] args) {
                 Scanner scanner = new Scanner(System.in);
                 int[] arr = {0, -1, 1};
                 Arrays.sort(arr);  // 应该对数组arr进行排序,而不是args
             }
         }
         结果:编译不报错
        
  5. 访问修饰符

    1. 介绍
      1. java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

        1. 公开级别: 用public 修饰,对外公开
        2. 受保护级别: 用protected修饰,对子类和同一个包中的类公开
        3. 默认级别: 没有修饰符号,向同一个包的类公开.
        4. 私有级别: 用private修饰,只有类本身可以访问,不对外公开
    2. 访问范围
      1. 访问级别访问控制修饰符同类同包子类不同包
        公开public
        受保护portected×
        默认没有修饰符××
        私有private×××
  6. 注意事项

    1. 修饰符可以用来修饰类中的属性,成员方法以及类
    2. 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
    3. 成员方法的访问规则和属性完全一样
  7. 代码示例

    1.  文件结构:
       └─src
           └─com
               └─hspedu
                   ├─modifier
                       └─A
                       └─B
                       └─test
      
       A类:
       package com.hspedu.modifier;
      
       public class A {
           // 四个属性,分别使用不同的访问修饰符来修饰
           public int n1 = 100;
           protected int n2 = 200;
           int n3 = 300;
           private int n4 = 400;
      
           public void m1() {
               // 在同一类中,可以访问public, protected, 默认, private 修饰的属性和方法
               System.out.println("n1=" + n1 + " n2=" + n2 + " n3=" + n3 + " n4=" + n4);
           }
      
           protected void m2() { }
      
           void m3() { }
      
           private void m4() { }
      
           public void hi() {
               // 在同一类中,可以访问public, protected, 默认, private 修饰的属性和方法
               m1();
               m2();
               m3();
               m4();
           }
       }
      
       B类:
       package com.hspedu.modifier;
      
       public class B {
           public void say() {
               A a = new A();
               // 在同一个包下,可以访问public, protected和默认修饰属性或方法,不能访问private属性或方法
               System.out.println("n1=" + a.n1 + " n2=" + a.n2 + " n3=" + a.n3);
               a.m1();
               a.m2();
               a.m3();
               // a.m4(); // 错误的,因为m4是私有方法
           }
       }
      
       test类:
       package com.hspedu.modifier;
      
       public class Test {
           public static void main(String[] args) {
               A a = new A();
               a.m1();
               B b = new B();
               b.say();
           }
       }
      
       // 只有默认和public可以修饰类
       class Tiger {}
      
       运行test类结果:
       n1=100 n2=200 n3=300 n4=400
       n1=100 n2=200 n3=300
       n1=100 n2=200 n3=300 n4=400
      

对象编程三大特征

封装

  1. 介绍

    1. 面向对象编程有三大特征:封装、继承和多态。
    2. 封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
  2. 步骤

    1. 将属性进行私有化private【不能直接修改属性】
    2. 提供一个公共的(public)set方法,用于对属性判断并赋值
      public void setXxx(类型参数名){/Xxx表示某个属性
      /加入数据验证的业务逻辑
      属性=参数名;
      }
    3. 提供一个公共的(public)get方法,用于获取属性的值
      public 数据类型getXxx(){/权限判断,Xxx某个属性
      return xx;
      }
  3. 代码示例

    1. 请大家看一个小程序,不能 随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认年龄,必须在1—120,年龄,工资不能直接查看,
      name的长度在2—6字符之间

      1.  package com.com.hspedu;
        
         public class test {
             public static void main(String[] args) {
                 // 如果要使用快捷键alt+r,需要先配置主类
                 // 第一次,我们使用鼠标点击形式运行程序,后面就可以用
                 Person person = new Person();
                 person.setName("cong");
                 person.setAge(30);
                 person.setSalary(30000);
                 System.out.println(person.info());
                 System.out.println(person.getSalary());
        
                 // 如果我们自己使用构造器指定属性
                 Person smith = new Person("smith", 80, 50000);
                 System.out.println("====smith的信息======");
                 System.out.println(smith.info());
             }
         }
        
         class Person {
             public String name; // 名字公开
             private int age; // age 私有化
             private double salary; // 私有化
        
             // 构造器
             public Person() {
             }
        
             // 有三个属性的构造器
             public Person(String name, int age, double salary) {
                 setName(name);
                 setAge(age);
                 setSalary(salary);
             }
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 // 加入对数据的校验,相当于增加了业务逻辑
                 if (name.length() >= 2 && name.length() <= 6) {
                     this.name = name;
                 } else {
                     this.name = "无名人";
                     System.out.println("名字的长度不对,需要(2-6)个字符,默认名字");
                 }
             }
        
             public int getAge() {
                 return age;
             }
        
             public void setAge(int age) {
                 // 判断
                 if (age >= 1 && age <= 120) { // 如果是合理范围
                     this.age = age;
                 } else {
                     System.out.println("你设置的年龄不对,需要在 (1-120),给默认年龄18");
                     this.age = 18; // 给一个默认年龄
                 }
             }
        
             public double getSalary() {
                 // 可以这里增加对当前对象的权限判断
                 return salary;
             }
        
             public void setSalary(double salary) {
                 this.salary = salary;
             }
        
             // 写一个方法,返回属性信息
             public String info() {
                 return "Name: " + name + ", Age: " + age + ", Salary: " + salary;
             }
         }
        
         输出结果:
         Name: cong, Age: 30, Salary: 30000.0
         30000.0
         ====smith的信息======
         Name: smith, Age: 80, Salary: 50000.0
        

继承

  1. 介绍

    1. 继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。画出继承的示意图
  2. 代码示例

    1.  文件结构:
       └─src
           └─com
               └─hspedu
                   ├─extend_
                      └─improve_
                           └─extends01
                           └─Student
                           └─Pupil
                           └─graduate
       ==================================================================================================================
       student类(父类):
       package com.hspedu.extend_.improve_;
      
       // 父类,是Pupil 和 Graduate 的父类
       public class Student {
           // 共有属性
           public String name;
           public int age;
           private double score; // 成绩
      
           // 共有的方法
           public void setScore(double score) {
               this.score = score;
           }
      
           public void showInfo() {
               System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
           }
       }
       ==================================================================================================================
       pupil(继承student的子类):
       package com.hspedu.extend_.improve_;
      
       // 让 Pupil 继承 Student 类
       public class Pupil extends Student {
           public void testing() {
               System.out.println("小学生 " + name + " 正在考小学数学..");
           }
       }
       ==================================================================================================================
       graduate类(继承student的子类):
       package com.hspedu.extend_.improve_;
      
       public class Graduate extends Student {
           public void testing() { // 和Pupil不一样
               System.out.println("大学生 " + name + " 正在考大学数学..");
           }
       }
       ==================================================================================================================
       extends01类:
       package com.hspedu.extend_.improve_;
      
       import com.hspedu.extend_.Graduate;
       import com.hspedu.extend_.Pupil;
      
       public class Extends01 {
           public static void main(String[] args) {
               com.hspedu.extend_.Pupil pupil = new Pupil();
               pupil.name = "银角大王~";
               pupil.age = 11;
               pupil.testing();
               pupil.setScore(50);
               pupil.showInfo();
               System.out.println("=======");
         
               com.hspedu.extend_.Graduate graduate = new Graduate();
               graduate.name = "金角大王~";
               graduate.age = 23;
               graduate.testing();
               graduate.setScore(80);
               graduate.showInfo();
           }
       }
      
       输出结果:
       小学生 银角大王~ 正在考小学数学..
       学生名 银角大王~ 年龄 11 成绩 50.0
       =======
       大学生 金角大王~ 正在考大学数学..
       学生名 金角大王~ 年龄 23 成绩 80.0
      
  3. 使用细节

    1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
    2. 子类必须调用父类的构造器,完成父类的初始化
    3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
    4. 如果希望指定去调用父类的某个构造器,则显式的调用一下:super(参数列表)
    5. super在使用时,必须放在构造器第一行(super只能在构造器中使用)
    6. super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
    7. java所有类都是Object类的子类,Object是所有类的基类.
    8. 父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)
    9. 子类最多只能继承一个父类(指直接继承),即java中是单继承机制。 思考:如何让A类继承B类和C类?【A继承B,B继承C】
    10. 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系
  4. 代码示例

    1.  文件结构:
           └─src
               └─com
                   └─hspedu
                       └─extend_
                         └─improve_
                           └─ExtendsDetail.java
                           └─TopBase.java
                           └─Base.java
                           └─Sub.java
       继承结构:
           TopBase.java
               └─Base.java
                   └─Sub.java
       ============================================================================================================================================================================
       TopBase.java代码:
       package src.com.hspedu.extend_.improve_;
      
       public class TopBase { // 父类是 Object
           public TopBase() {
                //super(); // Object 的无参构造器,可以省略这行
               System.out.println("构造器 TopBase() 被调用..."); // 1
           }
       }
       ================================================================================================================================
       Base.java代码:
       package src.com.hspedu.extend_.improve_;
      
       public class Base extends TopBase { // 父类
           // 4 个属性
           public int n1 = 100;
           protected int n2 = 200;
           int n3 = 300;
           private int n4 = 400;
      
           public Base() { // 无参构造器
               System.out.println("父类 Base() 构造器被调用....");
           }
      
           public Base(String name, int age) { // 有参构造器
               // 默认super()
               System.out.println("父类 Base(String name, int age)构造器被调用....");
           }
      
           public Base(String name) { // 有参构造器
               System.out.println("父类 Base(String name)构造器被调用....");
           }
      
           // 父类提供一个 public 的方法,返回了 n4
           public int getN4() {
               return n4;
           }
      
           public void test100() {
               System.out.println("test100");
           }
      
           protected void test200() {
               System.out.println("test200");
           }
      
           void test300() {
               System.out.println("test300");
           }
      
           private void test400() {
               System.out.println("test400");
           }
      
           // call
           public void callTest400() {
               test400();
           }
       }
       ================================================================================================================================
       Sub.java代码:
       package src.com.hspedu.extend_.improve_;
      
       import java.util.Arrays;
      
       // 输入ctrl + H 可以看到类的继承关系
       public class Sub extends Base { // 子类
           public Sub(String name, int age) {
               // 1. 老师要调用父类的无参构造器, 如下或者什么都不写,默认就是调用super()
               // super(); // 父类的无参构造器
               // 2. 老师要调用父类的 Base(String name) 构造器
               // super("hsp");
               // 3. 老师要调用父类的 Base(String name, int age) 构造器
               super("king", 20);
               // 细节:super 在使用时,必须放在构造器第一行
               // 细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
               // this() 不能再使用了
               System.out.println("子类 Sub(String name, int age)构造器被调用....");
           }
      
           public Sub() { // 无参构造器
               // super(); // 默认调用父类的无参构造器
               super("smith", 10);
               System.out.println("子类 Sub()构造器被调用....");
           }
      
           public Sub(String name) {
               super("tom", 30);
               // do nothing...
               System.out.println("子类 Sub(String name)构造器被调用....");
           }
      
           public void sayOk() { // 子类方法
               // 非私有的属性和方法可以在子类直接访问
               // 但是私有属性和方法不能在子类直接访问
               System.out.println(n1 + " " + n2 + " " + n3);
               test100();
               test200();
               test300();
               // test400(); 错误
               // 要通过父类提供公共的方法去访问
               System.out.println("n4=" + getN4());
               callTest400();
           }
       }
       ================================================================================================================================
       ExtendsDetail.java代码:
       package src.com.hspedu.extend_.improve_;
      
       public class ExtendsDetail {
           public static void main(String[] args) {
               // System.out.println("===第1个对象====");
               // Sub sub = new Sub(); // 创建了子类对象sub
               // System.out.println("===第2个对象====");
               // Sub sub2 = new Sub("jack"); // 创建了子类对象sub2
               System.out.println("===第3个对象====");
               Sub sub3 = new Sub("king", 10); // 创建了子类对象sub3
               // sub.sayOk();
           }
       }
      
       执行结果:
       ===3个对象====
       构造器 TopBase() 被调用...
       父类 Base(String name, int age)构造器被调用....
       子类 Sub(String name, int age)构造器被调用....
      
    2.  public class hello {
           public static void main(String[] args){
           B b=new B();
           }
       }
      
       class A {
           A() {
               System.out.println("a");
           }
      
           A(String name) {
               System.out.println("a name");
           }
       }
       class B extends A{
           B(){
               this("abc");
               System.out.println("b");
           }
           B(String name){
               System.out .println("b name");
           }
       }
       输出结果:
       a
       b name
       b
      
    3.  public class hello {
           public static void main(String[] args) {
               C c = new C();
           }
       }
      
       class A { // A 类
           public A() {
               System.out.println("我是 A 类");
           }
       }
      
       class B extends A { // B 类, 继承 A 类
           public B() {
               System.out.println("我是 B 类的无参构造");
           }
      
           public B(String name) {
               System.out.println(name + " 我是 B 类的有参构造");
           }
       }
      
       class C extends B { // C 类,继承 B 类
           public C() {
               this("hello");
               System.out.println("我是 C 类的无参构造");
           }
      
           public C(String name) {
               super("hahah");
               System.out.println("我是 C 类的有参构造");
           }
       }
      
       输出结果:
       我是 A 类
       hahah 我是 B 类的有参构造
       我是 C 类的有参构造
       我是 C 类的无参构造
      
      
  5. 多态

    1. 介绍

      1. Java的多态是面向对象编程的核心概念之一,它允许不同类的对象对同一消息做出响应。具体来说,多态性使得父类引用可以指向子类对象,从而在运行时根据实际对象类型调用相应的方法,而不是编译时的引用类型。这种机制增强了代码的灵活性和可扩展性,使得程序可以更容易地适应变化,同时也提高了代码的重用性。多态通过方法重写、接口实现和抽象类等方式来实现,是Java语言实现"一个接口,多个方法"的重要手段。
    2. 代码示例

      1.  文件结构:
             └─src
                 └─com
                     └─hspedu
                         └─poly_
                             └─Animal.java
                             └─Bone.java
                             └─Cat.java
                             └─Dog.java
                             └─Fish.java
                             └─Food.java
                             └─Master.java
                             └─Poly01.java
                             └─Rice.java
                             └─Pig.java
         继承关系:
             Food
               └─Bone
               └─Rice
               └─Fish
             Animal
               └─Pig
               └─Cat
               └─Dog
        
         Animal.java:
         package com.hspedu.poly_;
        
         public class Animal {
             private String name;
        
             public Animal(String name) {
                 this.name = name;
             }
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 this.name = name;
             }
         }
         ===========================================================================================
         Food.java:
         package com.hspedu.poly_;
        
         public class Food {
             private String name;
        
             public Food(String name) {
                 this.name = name;
             }
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 this.name = name;
             }
         }
         ===========================================================================================
         Master.java:
         package com.hspedu.poly_;
        
         public class Master {
             private String name;
        
             public Master(String name) {
                 this.name = name;
             }
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 this.name = name;
             }
        
             //使用多态机制,可以统一的管理主人喂食的问题
             //animal 编译类型是Animal,可以指向(接收) Animal子类的对象
             //food 编译类型是Food ,可以指向(接收) Food子类的对象
             public void feed(Animal animal, Food food) {
                 System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
             }
        
             //主人给小狗 喂食 骨头
         //    public void feed(Dog dog, Bone bone) {
         //        System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
         //    }
         //    //主人给 小猫喂 黄花鱼
         //    public void feed(Cat cat, Fish fish) {
         //        System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
         //    }
        
             //如果动物很多,食物很多
             //===> feed 方法很多,不利于管理和维护
             //Pig --> Rice
             //Tiger ---> meat ...
             //...
        
         }
         ===========================================================================================
         Bone.java:
         package com.hspedu.poly_;
        
         public class Bone extends Food {
             public Bone(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         Cat.java:
         package com.hspedu.poly_;
        
         public class Cat extends Animal {
             public Cat(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         Dog.java:
         package com.hspedu.poly_;
        
         public class Dog extends Animal {
             public Dog(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         Fish.java:
         package com.hspedu.poly_;
        
         public class Fish extends Food {
             public Fish(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         Pig.java:
         package com.hspedu.poly_;
        
         public class Pig extends Animal {
             public Pig(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         Rice.java:
         package com.hspedu.poly_;
        
         public class Rice extends Food {
             public Rice(String name) {
                 super(name);
             }
         }
         ===========================================================================================
         poly01.java:
         package com.hspedu.poly_;
        
         public class Poly01 {
             public static void main(String[] args) {
        
                 Master tom = new Master("汤姆");
                 Dog dog = new Dog("大黄~");
                 Bone bone = new Bone("大棒骨~");
                 tom.feed(dog, bone);
        
                 Cat cat = new Cat("小花猫~");
                 Fish fish = new Fish("黄花鱼~");
                 System.out.println("===========-------");
                 tom.feed(cat, fish);
        
                 //添加 给小猪为米饭
                 Pig pig = new Pig("小花猪");
                 Rice rice = new Rice("米饭");
                 System.out.println("===================");
                 tom.feed(pig, rice);
             }
         }
         输出结果:
         主人 汤姆 给 大黄~ 吃 大棒骨~
         ===========-------
         主人 汤姆 给 小花猫~ 吃 黄花鱼~
         ===================
         主人 汤姆 给 小花猪 吃 米饭
        
    3. 多态的向上/下转型

      1. 介绍
        1. 父类的引用指向了子类的对象
      2. 基本语法
        1. 向上转型

          1. 父类类型 引用名 = new 子类类型();
        2. 向下转型

          1. 子类类型 引用名 = (子类类型)父类引用;
      3. 特点
        1. 向上转型

          1. 编译类型看左边,运行类型看右边
          2. 可以调用父类中所有成员(需遵守访问权限)
          3. 最终运行效果看子类的具体实现
        2. 向下转型

          1. 只能强转父类的引用,不能强转父类的对象
          2. 要求父类的引用必须指向的是当前目标类型的对象
          3. 当向下转型后,可以调用子类类型中所有的成员
      4. 代码示例
        1.  文件结构:
               └─src
                   └─com
                       └─hspedu
                           └─poly_
                               └─detail_
                                   └─Animal.java
                                   └─Cat.java
                                   └─PolyDetail.java
                                   └─Dog.java
           继承关系:
               Animal
                   └─Cat
                   └─Dog
          
           Animal。java:
           package src.com.hspedu.poly_.detail_;
          
           public class Animal {
               String name = "动物";
               int age = 10;
               public void sleep(){
                   System.out.println("睡");
               }
               public void run(){
                   System.out.println("跑");
               }
               public void eat(){
                   System.out.println("吃");
               }
               public void show(){
                   System.out.println("hello,你好");
               }
          
           }
           ================================================================
           Cat.java:
           package src.com.hspedu.poly_.detail_;
          
           public class Cat extends Animal {
               public void eat(){//方法重写
                   System.out.println("猫吃鱼");
               }
               public void catchMouse(){//Cat特有方法
                   System.out.println("猫抓老鼠");
               }
           }
          
           ================================================================
           Dog.java:
           package src.com.hspedu.poly_.detail_;
          
           public class Dog extends Animal {//Dog是Animal的子类
           }
          
           ================================================================
           PolyDetail.java:
           package src.com.hspedu.poly_.detail_;
          
           public class PolyDetail {
               public static void main(String[] args) {
          
                   //向上转型: 父类的引用指向了子类的对象
                   //语法:父类类型引用名 = new 子类类型();
                   Animal animal = new Cat();
                   Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类
          
                   //向上转型调用方法的规则如下:
                   //(1)可以调用父类中的所有成员(需遵守访问权限)
                   //(2)但是不能调用子类的特有的成员
                   //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
                   //animal.catchMouse();错误
                   //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
                   //,然后调用,规则我前面我们讲的方法调用规则一致。
                   animal.eat();//猫吃鱼..
                   animal.run();//跑
                   animal.show();//hello,你好
                   animal.sleep();////animal.catchMouse();//报错
                   System.out.println("============");
                   //老师希望,可以调用Cat的 catchMouse方法
                   //多态的向下转型
                   //(1)语法:子类类型 引用名 =(子类类型)父类引用;
                   //问一个问题? cat 的编译类型 Cat,运行类型是 Cat
                   Cat cat = (Cat) animal;
                   cat.catchMouse();//猫抓老鼠
                   cat.run();////(2)要求父类的引用必须指向的是当前目标类型的对象
                   //Dog dog = (Dog) animal; //可以吗?不可以,因为猫与狗没有任何关系,无法转型
          
               }
           }
           输出结果:
           猫吃鱼
           跑
           hello,你好
           睡
           ============
           猫抓老鼠
           跑
          
        2. 
           public class hello {
               public static void main(String[] args) {
                   Sub s = new Sub();
                   System.out.println(s.count);//20
                   s.display();//20
                   Base b = s;
                   System.out.println(b == s);//T
                   System.out.println(b.count);//10
                   System.out.println(((Sub)b).count); // 这会输出 20
                   b.display();//20
               }
          
           }
          
           class Base {//父类
               int count = 10;
          
               public void display() {
                   System.out.println(this.count);
               }
           }
          
           class Sub extends Base {//子类
               int count = 20;
          
               public void display() {
                   System.out.println(this.count);
               }
           }
          
    4. 动态绑定

      1. 介绍
        1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
        2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
      2. 代码示例
        1.  package src.com.hspedu.poly_.dynamic_;
          
           public class DynamicBinding {
               public static void main(String[] args) {
                   //a 的编译类型 A, 运行类型 B
                   A a = new B();//向上转型
                   System.out.println(a.sum());// 30
                   System.out.println(a.sum1());// 20
               }
           }
          
           class A {//父类
               public int i = 10;
               //动态绑定机制:
          
               public int sum() {//父类sum()
                   return getI() + 10;//20 + 10
               }
          
               public int sum1() {//父类sum1()
                   return i + 10;//10 + 10
               }
          
               public int getI() {//父类getI
                   return i;
               }
           }
          
           class B extends A {//子类
               public int i = 20;
          
           //    public int sum() {
           //        return i + 20;
           //    }
          
               public int getI() {//子类getI()
                   return i;
               }
          
           //    public int sum1() {
           //        return i + 10;
           //    }
           }
          
    5. 多态数组

      1. 介绍
        1. 数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
      2. 代码示例
        1.  要求:
           现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个Teacher对象,统一放在数组
           中,并调用每个对象
           ====================================================================================
           Person.java:
           package src.com.hspedu.poly_.polyarr_;
          
           public class Person {//父类
               private String name;
               private int age;
          
               public Person(String name, int age) {
                   this.name = name;
                   this.age = age;
               }
          
               public String getName() {
                   return name;
               }
          
               public void setName(String name) {
                   this.name = name;
               }
          
               public int getAge() {
                   return age;
               }
          
               public void setAge(int age) {
                   this.age = age;
               }
          
               public String say() {//返回名字和年龄
                   return name + "\t" + age;
               }
           }
           ====================================================================================
           Student.java:
           package src.com.hspedu.poly_.polyarr_;
          
           public class Student extends Person {
               private double score;
          
               public Student(String name, int age, double score) {
                   super(name, age);
                   this.score = score;
               }
          
               public double getScore() {
                   return score;
               }
          
               public void setScore(double score) {
                   this.score = score;
               }
               //重写父类say
          
               @Override
               public String say() {
                   return "学生 " + super.say() + " score=" + score;
               }
               //特有的方法
               public void study() {
                   System.out.println("学生 " + getName() + " 正在学java...");
               }
           }
           ====================================================================================
           Teacher.java:
           package src.com.hspedu.poly_.polyarr_;
          
           public class Teacher extends Person {
               private double salary;
          
               public Teacher(String name, int age, double salary) {
                   super(name, age);
                   this.salary = salary;
               }
          
               public double getSalary() {
                   return salary;
               }
          
               public void setSalary(double salary) {
                   this.salary = salary;
               }
               //写重写父类的say方法
          
               @Override
               public String say() {
                   return "老师 " + super.say() + " salary=" + salary;
               }
               //特有方法
               public void teach() {
                   System.out.println("老师 " + getName() + " 正在讲java课程...");
               }
           }
           ====================================================================================
           PloyArray.java:
           package src.com.hspedu.poly_.polyarr_;
          
           public class Teacher extends Person {
               private double salary;
          
               public Teacher(String name, int age, double salary) {
                   super(name, age);
                   this.salary = salary;
               }
          
               public double getSalary() {
                   return salary;
               }
          
               public void setSalary(double salary) {
                   this.salary = salary;
               }
               //写重写父类的say方法
          
               @Override
               public String say() {
                   return "老师 " + super.say() + " salary=" + salary;
               }
               //特有方法
               public void teach() {
                   System.out.println("老师 " + getName() + " 正在讲java课程...");
               }
           }
           输出结果:
           jack	20
           学生 mary	18 score=100.0
           学生 mary 正在学java...
           学生 smith	19 score=30.1
           学生 smith 正在学java...
           老师 scott	30 salary=20000.0
           老师 scott 正在讲java课程...
           老师 king	50 salary=25000.0
           老师 king 正在讲java课程...
          

this关键字

  1. 介绍

    1. java虚拟机会给每个对象分配 this,代表当前对象。
  2. 代码示例

    1.  public class hello {
           // 编写一个main方法
           public static void main(String[] args) {
               Dog dog1 = new Dog("大壮", 3);
               System.out.println("dog1 的 hashcode=" + dog1.hashCode());
               // dog1 调用了 info() 方法
               dog1.info();
               System.out.println("============");
               Dog dog2 = new Dog("大黄", 2);
               System.out.println("dog2 的 hashcode=" + dog2.hashCode());
               dog2.info();
           }
       }
      
       class Dog { // 类
           String name;
           int age;
           // public Dog(String dName, int dAge){//构造器
           // name = dName;
           //age = dAge;
        name = dName;
           // 构造器
           public Dog(String name, int age) {
               // 使用this关键字区分局部变量和实例变量
               this.name = name;
               this.age = age;
               System.out.println("this.hashCode=" + this.hashCode());
           }
      
           // 成员方法,输出属性信息
           public void info() {
               System.out.println("this.hashCode=" + this.hashCode());
               System.out.println(name + "\t" + age + "\t");
           }
       }
      
       输出结果:
       this.hashCode=990368553
       dog1 的 hashcode=990368553
       this.hashCode=990368553
       大壮	3
       ============
       this.hashCode=1595428806
       dog2 的 hashcode=1595428806
       this.hashCode=1595428806
       大黄	2
      
    2. 原理图

super关键字

  1. 介绍

    1. super代表父类的引用,用于访问父类的属性、方法、构造器
  2. 注意细节

    1. 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
    2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super,如果没有重名,使用super,this、直接访问是一样的效果!
    3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A—>B—>C,当然也需要遵守访问权限的相关规则
  3. 代码示例

    1.  文件结构:
           └─src
               └─com
                   └─hspedu
                       └─super_
                           └─A.java
                           └─B.java
                           └─Base.java
                           └─Super01.java
                           └─A.java
       继承机构:
           Base.java
               └─A.java
                   └─B.java
       ======================================================================================================
       Base.java:
       package src.com.hspedu.super_;
      
       public class Base { // 父类是Object
           public int n1 = 999;
           public int age = 111;
      
           public void cal() {
               System.out.println("Base类的cal()方法...");
           }
      
           public void eat() {
               System.out.println("Base类的eat().....");
           }
       }
       ======================================================================================================
       A.java:
       package src.com.hspedu.super_;
      
       public class A extends Base {
           // 4个属性
           // public int n1 = 100;
           protected int n2 = 200;
           int n3 = 300;
           private int n4 = 400;
      
           public A() {}
           public A(String name) {}
           public A(String name, int age) {}
      
           // public void cal() {
           //     System.out.println("A类的cal()方法...");
           // }
      
           public void test100() {}
      
           protected void test200() {}
      
           void test300() {}
      
           private void test400() {}
       }
       ======================================================================================================
       B.java:
       package src.com.hspedu.super_;
      
       public class B extends A {
           public int n1 = 888;
      
           // 编写测试方法
           public void test() {
               // super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用 super 去访问爷爷类的成员;
               // 如果多个基类(上级类)中都有同名的成员,使用 super 访问遵循就近原则。A->B->C
               System.out.println("super.n1=" + super.n1);
               super.cal();
           }
      
           // 访问父类的属性, 但不能访问父类的 private 属性 [案例] super.属性名
           public void hi() {
               System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
           }
      
           public void cal() {
               System.out.println("B 类的 cal() 方法...");
           }
      
           public void sum() {
               System.out.println("B 类的 sum()");
               // 希望调用父类-A 的 cal 方法
               // 这时,因为子类 B 没有 cal 方法,因此我可以使用下面三种方式
               // 找 cal 方法时(cal() 和 this.cal()),顺序是:
               // (1)先找本类,如果有,则调用
               // (2)如果没有,则找父类(如果有,并可以调用,则调用)
               //
               // cal();
               this.cal(); // 等价 cal
               // (3)如果父类没有,则继续找父类的父类, 整个规则,就是一样的,直到 Object 类
               // 提示:如果查找方法的过程中,找到了,但是不能访问,则报错, cannot access
               // 如果查找方法的过程中,没有找到,则提示方法不存在
               // 找 cal 方法(super.cal()) 的顺序是直接查找父类,其他的规则一样
               // super.cal();
               // 演示访问属性的规则
               // n1 和 this.n1 查找的规则是
               // (1) 先找本类,如果有,则调用
               // (2) 如果没有,则找父类(如果有,并可以调用,则调用)
               // (3) 如果父类没有,则继续找父类的父类, 整个规则,就是一样的,直到 Object 类
               // 提示:如果查找属性的过程中,找到了,但是不能访问,则报错, cannot access
               //
               // 如果查找属性的过程中,没有找到,则提示属性不存在
               System.out.println(n1);
               System.out.println(this.n1);
               // 找 n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
               System.out.println(super.n1);
           }
      
           // 访问父类的方法,不能访问父类的 private 方法 super.方法名(参数列表);
           public void ok() {
               super.test100();
               super.test200();
               super.test300();
               // super.test400(); // 不能访问父类 private 方法
           }
      
           public B() {
               // 访问父类的构造器(这点前面用过)super(参数列表); 只能放在构造器的第一句,只能出现一句!
               // super();
               // super("jack", 10);
               super("jack");
           }
       }
       ======================================================================================================
       Super01.java:
       package src.com.hspedu.super_;
      
       public class Super01 {
           public static void main(String[] args) {
               B b = new B(); // 子类对象
               // b.sum();
               b.test();
           }
       }
       //super.n1=999
       //Base类的cal()方法...
      
  4. this与super的区别

    1. 变量与方法thissuper
      访问局部变量访问本类中的局部变量,如果局部变量名和类属性名相同则需要使用this来区分从父类继承的属性前面无需使用super关键字
      访问属性访问本类中的属性变量,如果局部变量名和类属性名相同则需要使用this来区分从父类继承的属性前面需要使用super关键字
      访问局部变量访问本类的构造器,必须放在构造器的首行访问父类的构造器,也必须放在子类构造器的首行
      构造器构造当前对象子类中访问父类的构造器

方法重写

  1. 介绍

    1. 方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
  2. 注意事项

    1. 子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样。

    2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
      比如父类返回类型是Object,子类方法返回类型是String

    3. 子类方法不能缩小父类方法的访问权限【演示】 public> protected > 默认>private

      1.  Animal.java:
         package src.com.hspedu.override_;
        
         public class Animal {
             public void cry() {
                 System.out.println("动物叫唤..");
             }
        
             public Object m1() {
                 return null;
             }
        
             public String m2() {
                 return null;
             }
        
             public AAA m3() {
                 return null;
             }
        
             protected void eat() {
             }
         }
         ==========================================================================
         Dog.java:
         package src.com.hspedu.override_;
        
         public class Dog extends Animal {
             // 老韩解读
             // 1. 因为Dog 是 Animal子类
             // 2. Dog 的 cry 方法和 Animal的 cry定义形式一样(名称、返回类型、参数)
             // 3. 这时我们就说 Dog的cry方法,重写了Animal的cry方法
             public void cry() {
                 System.out.println("小狗汪汪叫..");
             }
        
             // 细节: 子类方法的返回类型和父类方法返回类型一样,
             // 或者是父类返回类型的子类
             // 比如 父类 返回类型是 Object,
             // 子类方法返回类型是String
             public String m1() {
                 return null;
             }
        
             // m2方法中Object是String的父类,所以需要调整逻辑或者注释说明
             //   public Object m2() {
                 //       return null; // 这里可以返回null,因为null可以表示任何类型
             //  }
        
             // m3方法的返回类型需要明确,如果BBB是AAA的子类,则应该有返回值
         //BBB m3() {
             //      return new BBB(); // 返回BBB的实例
             //  }
        
             // 细节:子类方法不能缩小父类方法的访问权限【演示】
             // public>protected>默认>private
             // 吃的方法需要具体实现,这里默认为public
             public void eat() {
                 System.out.println("小狗正在吃...");
             }
         }
        
         class AAA {
         }
        
         class BBB extends AAA {
         }
         ==========================================================================
         Override01.java:
         package src.com.hspedu.override_;
        
         public class Override01 {
             public static void main(String[] args) {
                 // 演示方法重写的情况
                 Dog dog = new Dog();
                 dog.cry(); // ctrl+b
             }
         }
         //小狗汪汪叫..
        
  3. 重写与重载的区别

    1. 名称定义范围方法名形参列表返回类型备注修饰符
      重载(overload)本类必须一样类型,个数,顺序至少有一个不同无要求无特殊无要求
      重写(override)父子类必须一样形同相同子类重写的方法,返回值的类型和父类返回值的类型一致,或者是其子类子类方法不能缩小父类方法的访问范围
    2. 代码示例
      1.  题目要求:
         1. 编写一个Person类,包括属性/private(name、age),构造器、方法say(返回自我介绍的字符串)。
         2. 编写一个Student类,继承Person类,增加id、score属性/private,以及构造器,定义say方法(返回自我介绍的信息)3. 在main中,分别创建Person和Student对象,调用say方法输出自我介绍
        
         代码示例:
         Person.java:
         package src.com.hspedu.override_;
        
         //编写一个Person类,包括属性/private(name、age),构造器、方法say(返回自我介绍的字符串)
         public class Person {
             private String name;
             private int age;
        
             public Person(String name, int age) {
                 this.name = name;
                 this.age = age;
             }
        
             public String say() {
                 return "name=" + name + " age=" + age;
             }
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 this.name = name;
             }
        
             public int getAge() {
                 return age;
             }
        
             public void setAge(int age) {
                 this.age = age;
             }
         }
         ===========================================================================================
         Student.java:
         package src.com.hspedu.override_;
        
         //编写一个Student 类,继承Person类,增加id、score属性/private,以及构造器,定义say方法(返回自我介绍的信息)。
         public class Student extends Person {
             private int id;
             private double score;
        
             public Student(String name, int age, int id, double score) {
                 super(name, age);//这里会调用父类构造器
                 this.id = id;
                 this.score = score;
             }
        
             //say
             public String say() { //这里体现 super 的一个好处,代码复用.
                 return super.say() + " id=" + id + " score=" + score;
             }
        
             public int getId() {
                 return id;
             }
        
             public void setId(int id) {
                 this.id = id;
             }
        
             public double getScore() {
                 return score;
             }
        
             public void setScore(double score) {
                 this.score = score;
             }
         }
         ===========================================================================================
         OverrideExercise.java:
         package src.com.hspedu.override_;
        
         public class OverrideExercise {
             public static void main(String[] args) {
                 //在main中,分别创建Person和Student对象,调用say方法输出自我介绍
                 Person jack = new Person("jack", 10);
                 System.out.println(jack.say());
                 Student smith = new Student("smith", 20, 123456, 99.8);
                 System.out.println(smith.say());
             }
         }
         //name=jack age=10
         //name=smith age=20 id=123456 score=99.8
        

方法

==与equals

  1. 概念

    1. ==
      1. ==是一个比较运算符
      2. 1.:既可以判断基本类型,又可以判断引用类型
      3. 2.:如果判断基本类型,判断的是值是否相等。示例:inti=10;double d=10.0;
      4. 3.:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象【案例说明】
    2. equals
      1. equals:是Object类中的方法,只能判断引用类型
      2. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String【看看String 和Integer的 equals 源代码】
  2. 代码示例

    1.  package com.hspedu.object_;
      
       public class EqualsExercise02 {
           public static void main(String[] args) {
      
               Person_ p1 = new Person_();
               p1.name = "hspedu";
      
               Person_ p2 = new Person_();
               p2.name = "hspedu";
      
               System.out.println(p1==p2); //False
               System.out.println(p1.name .equals( p2.name));//T
               System.out.println(p1.equals(p2));//False
      
               String s1 = new String("asdf");
      
               String s2 = new String("asdf");
               System.out.println(s1.equals(s2));//T
               System.out.println(s1==s2); //F
      
           }
       }
      
       class Person_{//类
           public String name;
       }
      

hashcode

  1. 介绍

    1. 返回该对象的哈希码值。支持此方法是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。实际上,由object类定义的hashCode方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是Java=编程语言不需要这种实现技巧。)
  2. 特点

    1. 提高具有哈希结构的容器的效率!
    2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
    3. 两个引用,如果指向的是不同对象,则哈希值是不一样的
    4. 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
  3. 代码示例

    1.  public class hello {
           public static void main(String[] args) {
      
               AA aa = new AA();
               AA aa2 = new AA();
               AA aa3 = aa;
               System.out.println("aa.hashCode()=" + aa.hashCode());
               System.out.println("aa2.hashCode()=" + aa2.hashCode());
               System.out.println("aa3.hashCode()=" + aa3.hashCode());
      
      
           }
       }
       class AA {}
       输出结果:
       aa.hashCode()=990368553
       aa2.hashCode()=1828972342
       aa3.hashCode()=990368553
      

tostring

  1. 介绍

    1. 默认返回:全类名+@+哈希值的十六进制,【查看Object的toString方法】
    2. 子类往往重写toString方法,用于返回对象的属性信息
  2. 代码示例

    1.  public class hello {
           public static void main(String[] args) {
      
               /*
               Object的toString() 源码
               (1)getClass().getName() 类的全类名(包名+类名 )
               (2)Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串
               public String toString() {
                   return getClass().getName() + "@" + Integer.toHexString(hashCode());
               }
                */
      
               Monster monster = new Monster("小妖怪", "巡山的", 1000);
               System.out.println(monster.toString() + " hashcode=" + monster.hashCode());
      
               System.out.println("==当直接输出一个对象时,toString 方法会被默认的调用==");
               System.out.println(monster); //等价 monster.toString()
      
      
      
           }
       }
      
       class Monster {
           private String name;
           private String job;
           private double sal;
      
           public Monster(String name, String job, double sal) {
               this.name = name;
               this.job = job;
               this.sal = sal;
           }
      
           //重写toString方法, 输出对象的属性
           //使用快捷键即可 alt+insert -> toString
           @Override
           public String toString() { //重写后,一般是把对象的属性值输出,当然程序员也可以自己定制
               return "Monster{" +
                       "name='" + name + '\'' +
                       ", job='" + job + '\'' +
                       ", sal=" + sal +
                       '}';
           }
      
           @Override
           protected void finalize() throws Throwable {
               System.out.println("fin..");
           }
       }
       输出结果:
       Monster{name='小妖怪', job='巡山的', sal=1000.0} hashcode=1867083167
       ==当直接输出一个对象时,toString 方法会被默认的调用==
       Monster{name='小妖怪', job='巡山的', sal=1000.0}
      

综合项目

  1. 零钱通

    1. 项目说明
      1. 使用Java 开发 零钱通项目 , 可以完成收益入账,消费,查看明细,退出系统等功能.
    2. 代码示例
      1. 首先我们现在一个文件,将所有功能简单的实现

        1.  package src.com.hspedu.smallchange;
          
           import java.text.SimpleDateFormat;
           import java.util.Date;
           import java.util.Scanner;
          
           public class SmallChangeSys {
          
               //化繁为简
               //1. 先完成显示菜单,并可以选择菜单,给出对应提示
               //2. 完成零钱通明细
               //3. 完成收益入账
               //4. 消费
               //5. 退出
               //6. 用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,否则循环输入指令,直到输入y 或者 n
               //7. 在收益入账和消费时,判断金额是否合理,并给出相应的提示
               public static void main(String[] args) {
          
                   //定义相关的变量
                   boolean loop = true;
                   Scanner scanner = new Scanner(System.in);
                   String key = "";
          
                   //2. 完成零钱通明细
                   //老韩思路, (1) 可以把收益入账和消费,保存到数组 (2) 可以使用对象 (3) 简单的话可以使用String拼接
                   String details = "-----------------零钱通明细------------------";
          
                   //3. 完成收益入账  完成功能驱动程序员增加新的变化和代码
                   //老韩思路, 定义新的变量
                   double money = 0;
                   double balance = 0;
                   Date date = null; // date 是 java.util.Date 类型,表示日期
                   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //可以用于日期格式化的
          
                   //4. 消费
                   //定义新变量,保存消费的原因
                   String note = "";
                   do {
          
                       System.out.println("\n================零钱通菜单===============");
                       System.out.println("\t\t\t1 零钱通明细");
                       System.out.println("\t\t\t2 收益入账");
                       System.out.println("\t\t\t3 消费");
                       System.out.println("\t\t\t4 退     出");
          
                       System.out.print("请选择(1-4): ");
                       key = scanner.next();
          
                       //使用switch 分支控制
                       switch (key) {
                           case "1":
                               System.out.println(details);
                               break;
                           case "2":
                               System.out.print("收益入账金额:");
                               money = scanner.nextDouble();
                               //money 的值范围应该校验 -》 一会在完善
                               //老师思路, 编程思想
                               //找出不正确的金额条件,然后给出提示, 就直接break
                               if(money <= 0) {
                                   System.out.println("收益入账金额 需要 大于 0");
                                   break;
                               }
                               //找出正确金额的条件
                               balance += money;
                               //拼接收益入账信息到 details
                               date = new Date(); //获取当前日期
                               details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance;
          
          
                               break;
                           case "3":
                               System.out.print("消费金额:");
                               money = scanner.nextDouble();
                               //money 的值范围应该校验 -》 一会在完善
                               //找出金额不正确的情况
                               //过关斩将 校验方式.
                               if(money <= 0 || money > balance) {
                                   System.out.println("你的消费金额 应该在 0-" + balance);
                                   break;
                               }
                               System.out.print("消费说明:");
                               note = scanner.next();
                               balance -= money;
                               //拼接消费信息到 details
                               date = new Date(); //获取当前日期
                               details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance;
                               break;
                           case "4":
                               //用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,
                               // 否则循环输入指令,直到输入y 或者 n
                               // 老韩思路分析
                               // (1) 定义一个变量 choice, 接收用户的输入
                               // (2) 使用 while + break, 来处理接收到的输入时 y 或者 n
                               // (3) 退出while后,再判断choice是y还是n ,就可以决定是否退出
                               // (4) 建议一段代码,完成一个小功能,尽量不要混在一起
                               String choice = "";
                               while (true) { //要求用户必须输入y/n ,否则就一直循环
                                   System.out.println("你确定要退出吗? y/n");
                                   choice = scanner.next();
                                   if ("y".equals(choice) || "n".equals(choice)) {
                                       break;
                                   }
                                   //第二个方案
           //                        if("y".equals(choice)) {
           //                            loop = false;
           //                            break;
           //                        } else if ("n".equals(choice)) {
           //                            break;
           //                        }
                               }
          
                               //当用户退出while ,进行判断
                               if (choice.equals("y")) {
                                   loop = false;
                               }
                               break;
                           default:
                               System.out.println("选择有误,请重新选择");
                       }
          
                   } while (loop);
          
                   System.out.println("-----退出了零钱通项目-----");
          
               }
           }
          
      2. 将上面的代码转换为oop即可

        1.  oop编程:
          
           SmallChangeSysOOP.java:
           package src.com.hspedu.smallchange.oop;
          
          
           import java.text.SimpleDateFormat;
           import java.util.Date;
           import java.util.Scanner;
          
           /**
            * 该类是完成零钱通的各个功能的类
            * 使用OOP(面向对象编程)
            * 将各个功能对应一个方法.
            */
           public class SmallChangeSysOOP {
          
               //属性..
               //定义相关的变量
               boolean loop = true;
               Scanner scanner = new Scanner(System.in);
               String key = "";
          
               //2. 完成零钱通明细
               //老韩思路, (1) 可以把收益入账和消费,保存到数组 (2) 可以使用对象 (3) 简单的话可以使用String拼接
               String details = "-----------------零钱通明细------------------";
          
               //3. 完成收益入账  完成功能驱动程序员增加新的变化和代码
               //老韩思路, 定义新的变量
               double money = 0;
               double balance = 0;
               Date date = null; // date 是 java.util.Date 类型,表示日期
               SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //可以用于日期格式化的
          
               //4. 消费
               //定义新变量,保存消费的原因
               String note = "";
          
               //先完成显示菜单,并可以选择
               public void mainMenu() {
                   do {
          
                       System.out.println("\n================零钱通菜单(OOP)===============");
                       System.out.println("\t\t\t1 零钱通明细");
                       System.out.println("\t\t\t2 收益入账");
                       System.out.println("\t\t\t3 消费");
                       System.out.println("\t\t\t4 退     出");
          
                       System.out.print("请选择(1-4): ");
                       key = scanner.next();
          
                       //使用switch 分支控制
                       switch (key) {
                           case "1":
                               this.detail();
                               break;
                           case "2":
                               this.income();
                               break;
                           case "3":
                               this.pay();
                               break;
                           case "4":
                               this.exit();
                               break;
                           default:
                               System.out.println("选择有误,请重新选择");
                       }
          
                   } while (loop);
               }
          
               //完成零钱通明细
               public void detail() {
                   System.out.println(details);
               }
               //完成收益入账
               public void income() {
                   System.out.print("收益入账金额:");
                   money = scanner.nextDouble();
                   //money 的值范围应该校验 -》 一会在完善
                   //老师思路, 编程思想
                   //找出不正确的金额条件,然后给出提示, 就直接return
                   if(money <= 0) {
                       System.out.println("收益入账金额 需要 大于 0");
                       return; //退出方法,不在执行后面的代码。
                   }
                   //找出正确金额的条件
                   balance += money;
                   //拼接收益入账信息到 details
                   date = new Date(); //获取当前日期
                   details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t" + balance;
          
               }
               //消费
               public void pay() {
                   System.out.print("消费金额:");
                   money = scanner.nextDouble();
                   //money 的值范围应该校验 -》 一会在完善
                   //找出金额不正确的情况
                   //过关斩将 校验方式.
                   if(money <= 0 || money > balance) {
                       System.out.println("你的消费金额 应该在 0-" + balance);
                       return;
                   }
                   System.out.print("消费说明:");
                   note = scanner.next();
                   balance -= money;
                   //拼接消费信息到 details
                   date = new Date(); //获取当前日期
                   details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t" + balance;
               }
          
               //退出
               public void exit() {
                   //用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,
                   // 否则循环输入指令,直到输入y 或者 n
                   // 老韩思路分析
                   // (1) 定义一个变量 choice, 接收用户的输入
                   // (2) 使用 while + break, 来处理接收到的输入时 y 或者 n
                   // (3) 退出while后,再判断choice是y还是n ,就可以决定是否退出
                   // (4) 建议一段代码,完成一个小功能,尽量不要混在一起
                   String choice = "";
                   while (true) { //要求用户必须输入y/n ,否则就一直循环
                       System.out.println("你确定要退出吗? y/n");
                       choice = scanner.next();
                       if ("y".equals(choice) || "n".equals(choice)) {
                           break;
                       }
                       //第二个方案
           //                        if("y".equals(choice)) {
           //                            loop = false;
           //                            break;
           //                        } else if ("n".equals(choice)) {
           //                            break;
           //                        }
                   }
          
                   //当用户退出while ,进行判断
                   if (choice.equals("y")) {
                       loop = false;
                       System.out.println("-----退出了零钱通项目-----");
                   }
               }
           }
           =====================================================================================================
           SmallChangeSysApp.java:
           package src.com.hspedu.smallchange.oop;
          
          
           /**
            * 这里我们直接调用SmallChangeSysOOP 对象,显示主菜单即可
            */
           public class SmallChangeSysApp {
          
               public static void main(String[] args) {
                   System.out.println("====hello公司====");
                   new SmallChangeSysOOP().mainMenu();
               }
           }
          

房屋出租系统

  1. 项目需求

    1. 实现基于文本界面的《房屋出租软件》。 能够实现对房屋信息的添加、修改和删除(用数组实现),并能够打印房屋明细表
    2. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    3. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  2. 代码示例

    1.  文件结构:
           └─src
               └─com
                   └─hspedu
                     └─houserent
                       ├─domain
                           └─House.java
                       ├─service
                           └─HouseService.java
                       ├─utils
                           └─Utility.java
                       └─view
                           └─HouseView.java
                       └─HouseRentApp.java
       House.java:
       package src.com.hspedu.houserent.domain;
      
       /**
        * House的对象表示一个房屋信息
        */
       public class House {
           //编号  房主  电话  地址  月租  状态(未出租/已出租)
           private int id;
           private String name;
           private String phone;
           private String address;
           private int rent;
           private String state;
           //构造器和setter,getter
      
           public House(int id, String name, String phone, String address, int rent, String state) {
               this.id = id;
               this.name = name;
               this.phone = phone;
               this.address = address;
               this.rent = rent;
               this.state = state;
           }
      
           public int getId() {
               return id;
           }
      
           public void setId(int id) {
               this.id = id;
           }
      
           public String getName() {
               return name;
           }
      
           public void setName(String name) {
               this.name = name;
           }
      
           public String getPhone() {
               return phone;
           }
      
           public void setPhone(String phone) {
               this.phone = phone;
           }
      
           public String getAddress() {
               return address;
           }
      
           public void setAddress(String address) {
               this.address = address;
           }
      
           public int getRent() {
               return rent;
           }
      
           public void setRent(int rent) {
               this.rent = rent;
           }
      
           public String getState() {
               return state;
           }
      
           public void setState(String state) {
               this.state = state;
           }
           //为了方便的输出对象信息,我们实现toString
           //编号  房主  电话  地址  月租  状态(未出租/已出租)
           @Override
           public String toString() {
               return  id +
                       "\t\t" + name +
                       "\t" + phone +
                       "\t\t" + address +
                       "\t" + rent +
                       "\t" + state ;
           }
       }
       ====================================================================================================================
       HouseView.java:
       package src.com.hspedu.houserent.view;
      
      
       import src.com.hspedu.houserent.domain.House;
       import src.com.hspedu.houserent.service.HouseService;
       import src.com.hspedu.houserent.utils.Utility;
      
       /**
        * 1. 显示界面
        * 2. 接收用户的输入
        * 3. 调用HouseService完成对房屋信息的各种操作
        */
       public class HouseView {
      
           private boolean loop = true; //控制显示菜单
           private char key = ' '; //接收用户选择
           private HouseService houseService = new HouseService(2);//设置数组的大小为2
      
      
           //根据id修改房屋信息
           public void update() {
               System.out.println("=============修改房屋信息============");
               System.out.println("请选择待修改房屋编号(-1表示退出)");
               int updateId = Utility.readInt();
               if (updateId == -1) {
                   System.out.println("=============你放弃修改房屋信息============");
                   return;
               }
      
               //根据输入得到updateId,查找对象
      
               //老师特别提示:返回的是引用类型[:就是数组的元素]
               //因此老师在后面对house.setXxx() ,就会修改HouseService中houses数组的元素!!!!!!!!!!
               House house = houseService.findById(updateId);
               if (house == null) {
                   System.out.println("=============修改房屋信息编号不存在..============");
                   return;
               }
      
               System.out.print("姓名(" + house.getName() + "): ");
               String name = Utility.readString(8, "");//这里如果用户直接回车表示不修改该信息,默认""
               if (!"".equals(name)) {//修改
                   house.setName(name);
               }
      
               System.out.print("电话(" + house.getPhone() + "):");
               String phone = Utility.readString(12, "");
               if (!"".equals(phone)) {
                   house.setPhone(phone);
               }
               System.out.print("地址(" + house.getAddress() + "): ");
               String address = Utility.readString(18, "");
               if (!"".equals(address)) {
                   house.setAddress(address);
               }
               System.out.print("租金(" + house.getRent() + "):");
               int rent = Utility.readInt(-1);
               if (rent != -1) {
                   house.setRent(rent);
               }
               System.out.print("状态(" + house.getState() + "):");
               String state = Utility.readString(3, "");
               if (!"".equals(state)) {
                   house.setState(state);
               }
               System.out.println("=============修改房屋信息成功============");
      
      
           }
      
           //根据id查找房屋信息
           public void findHouse() {
               System.out.println("=============查找房屋信息============");
               System.out.print("请输入要查找的id: ");
               int findId = Utility.readInt();
               //调用方法
               House house = houseService.findById(findId);
               if (house != null) {
                   System.out.println(house);
               } else {
                   System.out.println("=============查找房屋信息id不存在============");
               }
           }
      
           //完成退出确认
           public void exit() {
               //这里我们使用Utility提供方法,完成确认
               char c = Utility.readConfirmSelection();
               if (c == 'Y') {
                   loop = false;
               }
           }
      
           //编写delHouse() 接收输入的id,调用Service 的del方法
           public void delHouse() {
               System.out.println("=============删除房屋信息============");
               System.out.print("请输入待删除房屋的编号(-1退出):");
               int delId = Utility.readInt();
               if (delId == -1) {
                   System.out.println("=============放弃删除房屋信息============");
                   return;
               }
               //注意该方法本身就有循环判断的逻辑,必须输出Y/N
               char choice = Utility.readConfirmSelection();
               if (choice == 'Y') {//真的删除
                   if (houseService.del(delId)) {
                       System.out.println("=============删除房屋信息成功============");
                   } else {
                       System.out.println("=============房屋编号不存在,删除失败============");
                   }
               } else {
                   System.out.println("=============放弃删除房屋信息============");
               }
      
           }
      
           //编写addHouse() 接收输入,创建House对象,调用add方法
           public void addHouse() {
               System.out.println("=============添加房屋============");
               System.out.print("姓名: ");
               String name = Utility.readString(8);
               System.out.print("电话: ");
               String phone = Utility.readString(12);
               System.out.print("地址: ");
               String address = Utility.readString(16);
               System.out.print("月租: ");
               int rent = Utility.readInt();
               System.out.print("状态: ");
               String state = Utility.readString(3);
               //创建一个新的House对象, 注意id 是系统分配的,
               House newHouse = new House(0, name, phone, address, rent, state);
               if (houseService.add(newHouse)) {
                   System.out.println("=============添加房屋成功============");
               } else {
                   System.out.println("=============添加房屋失败============");
               }
      
           }
      
           //编写listHouses()显示房屋列表
           public void listHouses() {
               System.out.println("=============房屋列表============");
               System.out.println("编号\t\t房主\t\t电话\t\t地址\t\t月租\t\t状态(未出租/已出租)");
               House[] houses = houseService.list();//得到所有房屋信息
               for (int i = 0; i < houses.length; i++) {//大家想想,这里老韩有什么?雷,if (houses[i] == null) {//如果为null,就不用再显示了
                       break;
                   }
                   System.out.println(houses[i]);
               }
               System.out.println("=============房屋列表显示完毕============");
      
           }
      
           //显示主菜单
           public void mainMenu() {
      
               do {
                   System.out.println("\n=============房屋出租系统菜单============");
                   System.out.println("\t\t\t1 新 增 房 源");
                   System.out.println("\t\t\t2 查 找 房 屋");
                   System.out.println("\t\t\t3 删 除 房 屋 信 息");
                   System.out.println("\t\t\t4 修 改 房 屋 信 息");
                   System.out.println("\t\t\t5 房 屋 列 表");
                   System.out.println("\t\t\t6 退      出");
                   System.out.print("请输入你的选择(1-6): ");
                   key = Utility.readChar();
                   switch (key) {
                       case '1':
                           addHouse();
                           break;
                       case '2':
                           findHouse();
                           break;
                       case '3':
                           delHouse();
                           break;
                       case '4':
                           update();
                           break;
                       case '5':
                           listHouses();
                           break;
                       case '6':
                           exit();
                           break;
                   }
               } while (loop);
           }
       }
       ====================================================================================================================
       HouseService.java:
       package src.com.hspedu.houserent.service;
      
       import src.com.hspedu.houserent.domain.House;
      
       /**
        * HouseService.java<=>[业务层]
        * //定义House[] ,保存House对象
        * 1. 响应HouseView的调用
        * 2. 完成对房屋信息的各种操作(增删改查c[create]r[read]u[update]d[delete])
        */
       public class HouseService {
      
           private House[] houses; //保存House对象
           private int houseNums = 1; //记录当前有多少个房屋信息
           private int idCounter = 1; //记录当前的id增长到哪个值
           //构造器
           public HouseService(int size) {
               //new houses
               houses = new House[size];//当创建HouseService对象,指定数组大小
               //为了配合测试列表信息,老韩这里初始化一个House对象
               houses[0] = new House(1,"jack","112", "海淀区", 2000, "未出租");
           }
      
           //findById方法,返回House对象或者null
           public House findById(int findId) {
      
               //遍历数组
               for(int i = 0; i < houseNums; i++) {
                   if(findId == houses[i].getId()) {
                       return houses[i];
                   }
               }
      
               return null;
      
           }
      
           //del方法,删除一个房屋信息
           public boolean del(int delId) {
      
               //应当先找到要删除的房屋信息对应的下标
               //老韩强调,一定要搞清楚 下标和房屋的编号不是一回事
               int index = -1;
               for(int i = 0; i < houseNums; i++) {
                   if(delId == houses[i].getId()) {//要删除的房屋(id),是数组下标为i的元素
                       index = i;//就使用index记录i
                   }
               }
      
               if(index == -1) {//说明delId在数组中不存在(有点绕..)
                   return false;
               }
               //如果找到, 这里需要小伙伴动脑筋,有点难.
               //老师思路分析:
               for(int i = index; i < houseNums - 1; i++) {
                   houses[i] = houses[i+1];
               }
               //把当有存在的房屋信息的最后一个 设置null
               houses[--houseNums] = null;
               return true;
      
           }
      
           //add方法,添加新对象,返回boolean
           public boolean add(House newHouse) {
               //判断是否还可以继续添加(我们暂时不考虑数组扩容的问题) => 能否自己加入数组扩容机制(~~)
               if(houseNums == houses.length) {//不能再添加
                   System.out.println("数组已满,不能再添加了...");
                   return false;
               }
               //把newHouse对象加入到,新增加了一个房屋
               houses[houseNums++] = newHouse;
               //我们程序员需要设计一个id自增长的机制, 然后更新newHouse的id
               newHouse.setId(++idCounter);
               return true;
           }
      
           //list方法,返回houses
           public House[] list() {
               return houses;
           }
       }
      
       ====================================================================================================================
       HouseRentApp.java:
       package src.com.hspedu.houserent;
      
      
       import src.com.hspedu.houserent.view.HouseView;
      
       public class HouseRentApp {
           public static void main(String[] args) {
      
               byte b1 = 123;
               b1 += 100000; //如果 b1 = b1 + 100000;//编译都不能过
               System.out.println(b1);
      
               byte b2 = 123;
               b2 = (byte)(b2 + 100000);
               System.out.println(b2);
      
               //创建HouseView对象,并且显示主菜单,是整个程序的入口
               new HouseView().mainMenu();
               System.out.println("===你退出房屋出租系统==");
           }
       }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CongSec

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值