Java SE进阶

面向对象基础

类和对象

类和对象的关系

客观存在的事物皆为对象 ,所以我们也常常说万物皆对象。

    • 类的理解
    • 类是对现实生活中一类具有共同属性和行为的事物的抽象
    • 类是对象的数据类型,类是具有相同属性和行为的一组对象的集合
    • 简单理解:类就是对现实事物的一种描述
    • 类的组成
    • 属性:指事物的特征,例如:手机事物(品牌,价格,尺寸)
    • 行为:指事物能执行的操作,例如:手机事物(打电话,发短信)
  • 类和对象的关系
    • 类:类是对现实生活中一类具有共同属性和行为的事物的抽象
    • 对象:是能够看得到摸的着的真实存在的实体
    • 简单理解:类是对事物的一种描述,对象则为具体存在的事物

类的定义【应用】

类的组成是由属性和行为两部分组成

  • 属性:在类中通过成员变量来体现(类中方法外的变量)
  • 行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)

类的定义步骤:

​ ① 定义类

​ ② 编写类的成员变量

​ ③ 编写类的成员方法

public class Student {
    // 属性 : 姓名, 年龄
    // 成员变量: 跟之前定义变量的格式一样, 只不过位置发生了改变, 类中方法外
    String name;
    int age;

    // 行为 : 学习
    // 成员方法: 跟之前定义方法的格式一样, 只不过去掉了static关键字.
    public void study(){
        System.out.println("学习");
    }
}

对象的创建和使用

  • 创建对象的格式:
    • 类名 对象名 = new 类名();
  • 调用成员的格式:
    • 对象名.成员变量
    • 对象名.成员方法();
  • 示例代码 :
package com.bcsbj;

public class TestStudent {
    /*
        创建对象的格式:
                类名 对象名 = new 类名();
        调用成员变量的格式:
                对象名.变量名
        调用成员方法的格式:
                对象名.方法名();
     */
    public static void main(String[] args) {
        // 类名 对象名 = new 类名();
        Student stu = new Student();
        // 对象名.变量名
        // 默认初始化值
        System.out.println(stu.name);  // null
        System.out.println(stu.age);   // 0

        stu.name = "张三";
        stu.age = 23;

        System.out.println(stu.name);  // 张三
        System.out.println(stu.age);   // 23

        // 对象名.方法名();
        stu.study();
        // com.bcsbj
        // 全类名(包名 + 类名)
        System.out.println(stu);
    }
}

案例:手机类的创建和使用

需求 :首先定义一个手机类,然后定义一个手机测试类,在手机测试类中通过对象完成成员变量和成员方法的使用

分析 :

  • 成员变量:品牌, 价格
  • 成员方法:打电话, 发短信
  • 示例代码:
package com.bcsbj;

public class Phone {
    // 品牌, 价格
    String brand;
    int price;

    // 打电话, 发短信
    public void call(String name){
        System.out.println("给"+name+"打电话");
    }

    public void sendMessage(){
        System.out.println("群发短信");
    }
}
package com.bcsbj;

public class TestPhone {
    public static void main(String[] args) {
        // 1. 创建对象
        Phone p = new Phone();
        // 2. 给成员变量进行赋值
        p.brand = "大米";
        p.price = 2999;
        // 3. 打印赋值后的成员变量
        System.out.println(p.brand + "..." + p.price);
        // 4. 调用成员方法
        p.call("小强");
        p.sendMessage();
    }
}

对象内存图

单个对象内存图【理解】

多个对象内存图【理解】

总结 :

当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)

只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。

成员变量和局部变量

成员变量和局部变量的区别

  • 类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
  • 内存中位置不同:成员变量(堆内存)局部变量(栈内存)
  • 生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而存在,醉着方法的调用完毕而消失)
  • 初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)

封装

private关键字

概述 : private是一个修饰符,可以用来修饰成员(成员变量,成员方法)

特点 : 被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用, 提供相应的操作

​ 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰

​ 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰

示例代码:

/*
    学生类
 */
class Student {
    //成员变量
    String name;
    private int age;

    //提供get/set方法
    public void setAge(int a) {
        if(a<0 || a>120) {
            System.out.println("你给的年龄有误");
        } else {
            age = a;
        }
    }

    public int getAge() {
        return age;
    }

    //成员方法
    public void show() {
        System.out.println(name + "," + age);
    }
}
/*
    学生测试类
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();
        //给成员变量赋值
        s.name = "林青霞";
        s.setAge(30);
        //调用show方法
        s.show();
    }
}

private关键字的使用

  • 需求:

    • 定义标准的学生类,要求name和age使用private修饰
    • 并提供set和get方法以及便于显示数据的show方法
    • 测试类中创建对象并使用,最终控制台输出  林青霞,30
  • 示例代码:

/*
    学生类
 */
class Student {
    //成员变量
    private String name;
    private int age;

    //get/set方法
    public void setName(String n) {
        name = n;
    }

    public String getName() {
        return name;
    }

    public void setAge(int a) {
        age = a;
    }

    public int getAge() {
        return age;
    }

    public void show() {
        System.out.println(name + "," + age);
    }
}
/*
    学生测试类
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();

        //使用set方法给成员变量赋值
        s.setName("林青霞");
        s.setAge(30);

        s.show();

        //使用get方法获取成员变量的值
        System.out.println(s.getName() + "---" + s.getAge());
        System.out.println(s.getName() + "," + s.getAge());

    }
}

this关键字【应用】

概述 : this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)

  • 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
  • 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量

代码实现 :

public class Student {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void show() {
        System.out.println(name + "," + age);
    }
}

this内存原理【理解】

  • 注意 : this代表当前调用方法的引用,哪个对象调用的方法,this就代表哪一个对象

  • 图解 :


封装思想

  1. 封装概述
    是面向对象三大特征之一(封装,继承,多态)
    是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
  2. 封装原则
    将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
    成员变量private,提供对应的getXxx()/setXxx()方法
  3. 封装好处
    通过方法来控制成员变量的操作,提高了代码的安全性
    把代码用方法进行封装,提高了代码的复用性

构造方法

构造方法的格式和执行时机

  • 格式注意 :
    • 方法名与类名相同,大小写也要一致
    • 没有返回值类型,连void都没有
    • 没有具体的返回值(不能由retrun带回结果数据)
  • 执行时机 :
    • 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
    • 不能手动调用构造方法
  • 示例代码:
class Student {
    private String name;
    private int age;

    //构造方法
    public Student() {
        System.out.println("无参构造方法");
    }

    public void show() {
        System.out.println(name + "," + age);
    }
}
/*
    测试类
 */
public class StudentDemo {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();
        s.show();
    }
}

构造方法的作用

用于给对象的数据(属性)进行初始化

package com.bcsbj.constructor;
public class Student {
    /*
        格式:

               1. 方法名需要跟类名相同, 大小写也要一致
               2. 没有返回值类型, 连void都没有
               3. 没有具体的返回值(不能由return带回具体的结果)
     */

    private String name;
    private int age;

    // 1. 如果一个类中没有编写任何构造方法, 系统将会提供一个默认的无参数构造方法
    public Student(){}

    // 2. 如果手动编写了构造方法, 系统就不会再提供默认的无参数构造方法了
    public Student(String name, int age){
        this.name = name;
        this.age = age;
        System.out.println("我是Student类的构造方法");
    }

    public void show(){
        System.out.println(name + "..." + age);
    }
}
package com.bcsbj.constructor;

public class TestStudent {
    public static void main(String[] args) {
        Student stu1 = new Student("张三",18);
        stu1.show();

        Student stu2 = new Student();
    }
}

构造方法的注意事项

构造方法的创建 :

​ 如果没有定义构造方法,系统将给出一个默认的无参数构造方法

​ 如果定义了构造方法,系统将不再提供默认的构造方法

构造方法的创建 :

​ 如果没有定义构造方法,系统将给出一个默认的无参数构造方法如果定义了构造方法,系统将不再提供默认的构造方法

推荐的使用方式 :

​ 无论是否使用,都手动书写无参数构造方法,和带参数构造方法

标准类的代码编写和使用

package com.bcsbj.test3;

/*
    JavaBean类: 封装数据
 */
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(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 void show(){
        System.out.println(name + "..." + age);
    }
}
package com.bcsbj.test3;

public class TestStudent {
    public static void main(String[] args) {
        // 1. 无参数构造方法创建对象, 通过setXxx方法给成员变量进行赋值
        Student stu1 = new Student();
        stu1.setName("张三");
        stu1.setAge(23);
        stu1.show();

        // 2. 通过带参数构造方法, 直接给属性进行赋值
        Student stu2 = new Student("李四",99);
        stu2.show();
    }
}

API

API概述,帮助文档的使用

  • 什么是API

    ​ API (Application Programming Interface) :应用程序编程接口

  • java中的API

    ​ 指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。

如何使用API帮助文档 :

  • 打开帮助文档

  • 找到索引选项卡中的输入框

  • 在输入框中输入Random

  • 看类在哪个包下

  • 看类的描述

  • 看构造方法

  • 看成员方法

键盘录入字符串

Scanner类 :

​ next() : 遇到了空格, 就不再录入数据了 , 结束标记: 空格, tab键

​ nextLine() : 可以将数据完整的接收过来 , 结束标记: 回车换行符

代码实现 :

package com.bcsbj.api;

import java.util.Scanner;

public class Demo1Scanner {
    /*
        next() : 遇到了空格, 就不再录入数据了

                结束标记: 空格, tab键

        nextLine() : 可以将数据完整的接收过来

                结束标记: 回车换行符
     */
    public static void main(String[] args) {
        // 1. 创建Scanner对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入:");
        // 2. 调用nextLine方法接收字符串
        // ctrl + alt + v : 快速生成方法的返回值
        String s = sc.nextLine();

        System.out.println(s);
    }
}
package com.bcsbj.api;
import java.util.Scanner;
public class Demo2Scanner {
    /*
        nextInt和nextLine方法配合使用的时候, nextLine方法就没有键盘录入的机会了
        建议: 今后键盘录入数据的时候, 如果是字符串和整数一起接受, 建议使用next方法接受字符串.
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入整数:");
        int num = sc.nextInt(); // 10 + 回车换行
        System.out.println("请输入字符串:");
        String s = sc.nextLine();
        System.out.println(num);
        System.out.println(s);
    }
}

String类

String概述

​ 1.String 类在 java.lang 包下,所以使用的时候不需要导包

​ 2.String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象

​ 3.字符串不可变,它们的值在创建后不能被更改

String类的构造方法

常用的构造方法

package com.itheima.string;

public class Demo2StringConstructor {
    /*
        String类常见构造方法:
            public String() : 创建一个空白字符串对象,不含有任何内容
            public String(char[] chs) : 根据字符数组的内容,来创建字符串对象
            public String(String original) : 根据传入的字符串内容,来创建字符串对象
            String s = “abc”;  直接赋值的方式创建字符串对象,内容就是abc

         注意:
                String这个类比较特殊, 打印其对象名的时候, 不会出现内存地址
                而是该对象所记录的真实内容.
                面向对象-继承, Object类
     */
    public static void main(String[] args) {
        // public String() : 创建一个空白字符串对象,不含有任何内容
        String s1 = new String();
        System.out.println(s1);

        // public String(char[] chs) : 根据字符数组的内容,来创建字符串对象
        char[] chs = {'a','b','c'};
        String s2 = new String(chs);
        System.out.println(s2);

        // public String(String original) : 根据传入的字符串内容,来创建字符串对象
        String s3 = new String("123");
        System.out.println(s3);
    }
}

创建字符串对象的区别对比

  • 通过构造方法创建

    ​ 通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同

  • 直接赋值方式创建

    ​ 以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护

字符串的比较

  • == 比较基本数据类型:比较的是具体的值
  • == 比较引用数据类型:比较的是对象地址值

String类 : public boolean equals(String s) 比较两个字符串内容是否相同、区分大小写

代码 :

package com.bcsbj.stringmethod;

public class Demo1Equals {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "ABC";
        String s3 = "abc";

        // equals : 比较字符串内容, 区分大小写
        System.out.println(s1.equals(s2));
        System.out.println(s1.equals(s3));

        // equalsIgnoreCase : 比较字符串内容, 忽略大小写
        System.out.println(s1.equalsIgnoreCase(s2));
    }
}

用户登录案例【应用】

案例需求 :

​ 已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示

实现步骤 :

  1. 已知用户名和密码,定义两个字符串表示即可
  2. 键盘录入要登录的用户名和密码,用 Scanner 实现
  3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
  4. 字符串的内容比较,用equals() 方法实现
  5. 用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循

代码实现 :

package com.bcsbj.test;
import java.util.Scanner;
public class Test1 {
    /*
        需求:已知用户名和密码,请用程序实现模拟用户登录。
              总共给三次机会,登录之后,给出相应的提示

        思路:
        1. 已知用户名和密码,定义两个字符串表示即可
        2. 键盘录入要登录的用户名和密码,用 Scanner 实现
        3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
            字符串的内容比较,用equals() 方法实现
        4. 用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环

     */
    public static void main(String[] args) {
        // 1. 已知用户名和密码,定义两个字符串表示即可
        String username = "admin";
        String password = "123456";
        // 2. 键盘录入要登录的用户名和密码,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        // 4. 用循环实现多次机会,这里的次数明确,采用for循环实现
        for(int i = 1; i <= 3; i++){
            System.out.println("请输入用户名:");
            String scUsername = sc.nextLine();
            System.out.println("请输入密码:");
            String scPassword = sc.nextLine();
            // 3. 拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
            if(username.equals(scUsername) && password.equals(scPassword)){
                System.out.println("登录成功");
                break;
            }else{
                if(i == 3){
                    System.out.println("您的登录次数已达到今日上限, 请明天再来");
                }else{
                    System.out.println("登录失败,您还剩余" + (3-i) +"次机会");
                }

            }
        }

    }
}

遍历字符串案例【应用】

案例需求 :

​ 键盘录入一个字符串,使用程序实现在控制台遍历该字符串

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 遍历字符串,首先要能够获取到字符串中的每一个字符, public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的
  3. 遍历字符串,其次要能够获取到字符串的长度, public int length():返回此字符串的长度
  4. 遍历打印

代码实现 :

package com.bcsbj.test;

import java.util.Scanner;

public class Test2 {
    /*
        需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串

        思路:
        1. 键盘录入一个字符串,用 Scanner 实现
        2. 遍历字符串,首先要能够获取到字符串中的每一个字符
            public char charAt(int index):返回指定索引处的char值,字符串的索引也是从0开始的
        3. 遍历字符串,其次要能够获取到字符串的长度
            public int length():返回此字符串的长度
        4. 遍历打印
9
     */
    public static void main(String[] args) {
        //  1. 键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入:");
        String s = sc.nextLine();
        // 2. 遍历字符串,首先要能够获取到字符串中的每一个字符
        for(int i = 0; i < s.length(); i++){
            // i : 字符串的每一个索引
            char c = s.charAt(i);
            System.out.println(c);
        }
    }
}

统计字符次数案例【应用】

案例需求 :

​ 键盘录入一个字符串,使用程序实现在控制台遍历该字符串

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 将字符串拆分为字符数组 , public char[] toCharArray( ):将当前字符串拆分为字符数组并返回
  3. 遍历字符数

代码实现 :

package com.bcsbj.test;

import java.util.Scanner;

public class Test3 {
    /*
       需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串

       思路:
       1. 键盘录入一个字符串,用 Scanner 实现
       2. 将字符串拆分为字符数组
                public char[] toCharArray( ):将当前字符串拆分为字符数组并返回
       3. 遍历字符数组

    */
    public static void main(String[] args) {
        //  1. 键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入:");
        String s = sc.nextLine();
        // 2. 将字符串拆分为字符数组
        char[] chars = s.toCharArray();
        // 3. 遍历字符数组
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }
    }
}

手机号屏蔽-字符串截取

案例需求 :

​ 以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
​ 最终效果为:156****1234

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 截取字符串前三位
  3. 截取字符串后四位
  4. 将截取后的两个字符串,中间加上****进行拼接,输出结果

代码实现 :

package com.bcsbj.test;

import java.util.Scanner;

public class Test5 {
    /*
        需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
        最终效果为:156****1234

        思路:
        1. 键盘录入一个字符串,用 Scanner 实现
        2. 截取字符串前三位
        3. 截取字符串后四位
        4. 将截取后的两个字符串,中间加上****进行拼接,输出结果

     */
    public static void main(String[] args) {
        // 1. 键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入手机号:");
        String telString = sc.nextLine();
        // 2. 截取字符串前三位
        String start = telString.substring(0,3);
        // 3. 截取字符串后四位
        String end = telString.substring(7);
        // 4. 将截取后的两个字符串,中间加上****进行拼接,输出结果
        System.out.println(start + "****" + end);
    }
}

敏感词替换-字符串替换

案例需求 :

​ 键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换

实现步骤 :

  1. 键盘录入一个字符串,用 Scanner 实现
  2. 替换敏感词
    String replace(CharSequence target, CharSequence replacement)
    将当前字符串中的target内容,使用replacement进行替换,返回新的字符串
  3. 输出结果

代码实现 :

package com.bcsbj.test;

import java.util.Scanner;

public class Test6 {
    /*
        需求:键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换

        思路:
        1. 键盘录入一个字符串,用 Scanner 实现
        2. 替换敏感词
                String replace(CharSequence target, CharSequence replacement)
                将当前字符串中的target内容,使用replacement进行替换,返回新的字符串
        3. 输出结果

     */
    public static void main(String[] args) {
        // 1. 键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入:");
        String s = sc.nextLine();
        // 2. 替换敏感词
        String result = s.replace("TMD","***");
        // 3. 输出结果
        System.out.println(result);
    }
}

切割字符串

案例需求 :

​ 以字符串的形式从键盘录入学生信息,例如:“张三 , 23”

​ 从该字符串中切割出有效数据,封装为Student学生对象

实现步骤 :

  1. 编写Student类,用于封装数据

  2. 键盘录入一个字符串,用 Scanner 实现

  3. 根据逗号切割字符串,得到(张三)(23)

    String[] split(String regex) :根据传入的字符串作为规则进行切割
    将切割后的内容存入字符串数组中,并将字符串数组返回

  4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象

  5. 调用对象getXxx方法,取出数据并打印。

代码实现 :

package com.bcsbj.test;

import com.bcsbj.domain.Student;

import java.util.Scanner;

public class Test7 {
    /*
         需求:以字符串的形式从键盘录入学生信息,例如:“张三 , 23”
                从该字符串中切割出有效数据,封装为Student学生对象
         思路:
            1. 编写Student类,用于封装数据
            2. 键盘录入一个字符串,用 Scanner 实现
            3. 根据逗号切割字符串,得到(张三)(23)
                    String[] split(String regex) :根据传入的字符串作为规则进行切割
                    将切割后的内容存入字符串数组中,并将字符串数组返回
            4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象
            5. 调用对象getXxx方法,取出数据并打印。

     */
    public static void main(String[] args) {
        // 2. 键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入学生信息:");
        String stuInfo = sc.nextLine();
        // stuInfo = "张三,23";
        // 3. 根据逗号切割字符串,得到(张三)(23)
        String[] sArr = stuInfo.split(",");

//        System.out.println(sArr[0]);
//        System.out.println(sArr[1]);

        // 4. 从得到的字符串数组中取出元素内容,通过Student类的有参构造方法封装为对象
        Student stu = new Student(sArr[0],sArr[1]);

        // 5. 调用对象getXxx方法,取出数据并打印。
        System.out.println(stu.getName() + "..." + stu.getAge());
    }
}

String方法小结

String类的常用方法 :

​ public boolean equals(Object anObject) 比较字符串的内容,严格区分大小写

​ public boolean equalsIgnoreCase(String anotherString) 比较字符串的内容,忽略大小写

​ public int length() 返回此字符串的长度

​ public char charAt(int index) 返回指定索引处的 char 值

​ public char[] toCharArray() 将字符串拆分为字符数组后返回

​ public String substring(int beginIndex, int endIndex) 根据开始和结束索引进行截取,得到新的字符串(包含头,不包含尾)

​ public String substring(int beginIndex) 从传入的索引处截取,截取到末尾,得到新的字符串

​ public String replace(CharSequence target, CharSequence replacement) 使用新值,将字符串中的旧值替换,得到新的字符串

​ public String[] split(String regex) 根据传入的规则切割字符串,得到字符串数组

StringBuilder类

StringBuilder类概述

概述 : StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的内容是可变的

StringBuilder类和String类的区别

  • String类:内容是不可变的
  • StringBuilder类:内容是可变的

    StringBuilder类的构造方法

    常用的构造方法

方法名 说明
public StringBuilder() 创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象

示例代码

public class StringBuilderDemo01 {
    public static void main(String[] args) {
        //public StringBuilder():创建一个空白可变字符串对象,不含有任何内容
        StringBuilder nb = new StringBuilder();
        System.out.println("nb:" + nb);
        System.out.println("nb.length():" + nb.length());

        //public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象
        StringBuilder nb2 = new StringBuilder("hello");
        System.out.println("nb2:" + nb2);
        System.out.println("nb2.length():" + nb2.length());
    }
}

StringBuilder常用的成员方法

  • 添加和反转方法

    方法名 说明
    public StringBuilder append(任意类型) 添加数据,并返回对象本身
    public StringBuilder reverse() 返回相反的字符序列
  • 示例代码

public class StringBuilderDemo01 {
    public static void main(String[] args) {
        //创建对象
        StringBuilder nb = new StringBuilder();

        //链式编程
        nb.append("hello").append("world").append("java").append(100);

        System.out.println("nb:" + nb);

        //public StringBuilder reverse():返回相反的字符序列
        sb.reverse();
        System.out.println("nb:" + nb);
    }
}

StringBuilder和String相互转换【应用】

  • StringBuilder转换为String

    ​ public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String

  • String转换为StringBuilder

    ​ public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder

  • 示例代码

public class StringBuilderDemo02 {
    public static void main(String[] args) {
        /*
        //StringBuilder 转换为 String
        StringBuilder sb = new StringBuilder();
        sb.append("hello");

        //String s = sb; //这个是错误的做法

        //public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String
        String s = sb.toString();
        System.out.println(s);
        */

        //String 转换为 StringBuilder
        String s = "hello";

        //StringBuilder sb = s; //这个是错误的做法

        //public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder
        StringBuilder nb = new StringBuilder(s);

        System.out.println(nb);
    }
}

StringBuilder拼接字符串案例

案例需求 :

​ 定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,

​ 并在控制台输出结果。例如,数组为int[] arr = {1,2,3}; ,执行方法后的输出结果为:[1, 2, 3]

实现步骤 :

  1. 定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
  2. 定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
    返回值类型 String,参数列表 int[] arr
  3. 在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
  4. 调用方法,用一个变量接收结果
  5. 输出结果

代码实现 :

/*
    思路:
        1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
        2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
          返回值类型 String,参数列表 int[] arr
        3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
        4:调用方法,用一个变量接收结果
        5:输出结果
 */
public class StringBuilderTest01 {
    public static void main(String[] args) {
        //定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
        int[] arr = {1, 2, 3};

        //调用方法,用一个变量接收结果
        String s = arrayToString(arr);

        //输出结果
        System.out.println("s:" + s);

    }

    //定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回
    /*
        两个明确:
            返回值类型:String
            参数:int[] arr
     */
    public static String arrayToString(int[] arr) {
        //在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
        StringBuilder nb = new StringBuilder();

        sb.append("[");

        for(int i=0; i<arr.length; i++) {
            if(i == arr.length-1) {
                nb.append(arr[i]);
            } else {
                nb.append(arr[i]).append(", ");
            }
        }

        nb.append("]");

        String s = nb.toString();

        return  s;
    }
}

ArrayList

集合和数组的区别 :**

​ 共同点:都是存储数据的容器

​ 不同点:数组的容量是固定的,集合的容量是可变的

ArrayList的构造方法和添加方法

public ArrayList() 创建一个空的集合对象
public boolean add(E e) 将指定的元素追加到此集合的末尾
public void add(int index,E element) 在此集合中的指定位置插入指定的元素

ArrayList

​ 可调整大小的数组实现

: 是一种特殊的数据类型,泛型。

怎么用呢 ?

​ 在出现E的地方我们使用引用数据类型替换即可

​ 举例:ArrayList, ArrayList

ArrayList类常用方法【应用】

成员方法 :

public boolean remove(Object o) 删除指定的元素,返回删除是否成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数

示例代码 :

public class ArrayListDemo02 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> array = new ArrayList<String>();

        //添加元素
        array.add("hello");
        array.add("world");
        array.add("java");

        //public boolean remove(Object o):删除指定的元素,返回删除是否成功
//        System.out.println(array.remove("world"));
//        System.out.println(array.remove("javaee"));

        //public E remove(int index):删除指定索引处的元素,返回被删除的元素
//        System.out.println(array.remove(1));

        //IndexOutOfBoundsException
//        System.out.println(array.remove(3));

        //public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
//        System.out.println(array.set(1,"javaee"));

        //IndexOutOfBoundsException
//        System.out.println(array.set(3,"javaee"));

        //public E get(int index):返回指定索引处的元素
//        System.out.println(array.get(0));
//        System.out.println(array.get(1));
//        System.out.println(array.get(2));
        //System.out.println(array.get(3)); //?????? 自己测试

        //public int size():返回集合中的元素的个数
        System.out.println(array.size());

        //输出集合
        System.out.println("array:" + array);
    }
}

ArrayList存储字符串并遍历

案例需求 :

​ 创建一个存储字符串的集合,存储3个字符串元素,使用程序实现在控制台遍历该集合

实现步骤 :
1:创建集合对象
2:往集合中添加字符串对象
3:遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
4:遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
5:遍历集合的通用格式

/*
    思路:
        1:创建集合对象
        2:往集合中添加字符串对象
        3:遍历集合,首先要能够获取到集合中的每一个元素,这个通过get(int index)方法实现
        4:遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
        5:遍历集合的通用格式
 */
public class ArrayListTest01 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> array = new ArrayList<String>();

        //往集合中添加字符串对象
        array.add("刘正风");
        array.add("左冷禅");
        array.add("风清扬");

        //遍历集合,其次要能够获取到集合的长度,这个通过size()方法实现
//        System.out.println(array.size());

        //遍历集合的通用格式
        for(int i=0; i<array.size(); i++) {
            String s = array.get(i);
            System.out.println(s);
        }
    }
}

ArrayList存储学生对象并遍历

案例需求 :

​ 创建一个存储学生对象的集合,存储3个学生对象,使用程序实现在控制台遍历该集合

实现步骤 :

​ 1:定义学生类

​ 2:创建集合对象

​ 3:创建学生对象

​ 4:添加学生对象到集合中

​ 5:遍历集合,采用通用遍历格式实现

代码实现 :

/*
    思路:
        1:定义学生类
        2:创建集合对象
        3:创建学生对象
        4:添加学生对象到集合中
        5:遍历集合,采用通用遍历格式实现
 */
public class ArrayListTest02 {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<Student> array = new ArrayList<>();

        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("风清扬", 33);
        Student s3 = new Student("张曼玉", 18);

        //添加学生对象到集合中
        array.add(s1);
        array.add(s2);
        array.add(s3);

        //遍历集合,采用通用遍历格式实现
        for (int i = 0; i < array.size(); i++) {
            Student s = array.get(i);
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

学生管理系统

学生管理系统实现步骤

案例需求

​ 针对目前我们的所学内容,完成一个综合案例:学生管理系统!该系统主要功能如下:

​ 添加学生:通过键盘录入学生信息,添加到集合中

​ 删除学生:通过键盘录入要删除学生的学号,将该学生对象从集合中删除

​ 修改学生:通过键盘录入要修改学生的学号,将该学生对象其他信息进行修改

​ 查看学生:将集合中的学生对象信息进行展示

​ 退出系统:结束程序

  • 实现步骤

    1. 定义学生类,包含以下成员变量

      学生类: Student成员变量:

      ​ 学号:sid

      ​ 姓名:name

      ​ 年龄:age

      ​ 生日:birthday

      ​ 构造方法:

      ​ 无参构造

      ​ 带四个参数的构造成员方法:

      ​ 每个成员变量对应给出get/set方法

    2. 学生管理系统主界面的搭建步骤

      2.1 用输出语句完成主界面的编写

      2.2 用Scanner实现键盘录入数据

      2.3 用switch语句完成操作的选择

      2.4 用循环完成再次回到主界面

    3. 学生管理系统的添加学生功能实现步骤

      3.1 用键盘录入选择添加学生

      3.2 定义一个方法,用于添加学生

      ​ 显示提示信息,提示要输入何种信息

      ​ 键盘录入学生对象所需要的数据

      ​ 创建学生对象,把键盘录入的数据赋值给学生对象的成员变量

      ​ 将学生对象添加到集合中(保存)

      ​ 给出添加成功提示

      3.3 调用方法

    4. 学生管理系统的查看学生功能实现步骤

      4.1 用键盘录入选择查看所有学生信息

      4.2 定义一个方法,用于查看学生信息

      ​ 显示表头信息

      ​ 将集合中数据取出按照对应格式显示学生信息,年龄显示补充“岁”

      4.3 调用方法

    5. 学生管理系统的删除学生功能实现步骤

      5.1 用键盘录入选择删除学生信息

      5.2 定义一个方法,用于删除学生信息

      ​ 显示提示信息

      ​ 键盘录入要删除的学生学号

      ​ 调用getIndex方法,查找该学号在集合的索引

      ​ 如果索引为-1,提示信息不存在

      ​ 如果索引不是-1,调用remove方法删除并提示删除成功

      5.3 调用方法

    6. 学生管理系统的修改学生功能实现步骤

      6.1 用键盘录入选择修改学生信息

      6.2 定义一个方法,用于修改学生信息

      ​ 显示提示信息

      ​ 键盘录入要修改的学生学号

      ​ 调用getIndex方法,查找该学号在集合的索引

      ​ 如果索引为-1,提示信息不存在

      ​ 如果索引不是-1,键盘录入要修改的学生信息

      ​ 集合修改对应的学生信息

      ​ 给出修改成功提示

      6.3 调用方法

    7. 退出系统

      使用System.exit(0);退出JVM

学生类的定义

package com.bcsbj.domain;

public class Student {
    private String sid; // 学号
    private String name; // 姓名
    private int age; // 年龄
    private String birthday; // 生日

    public Student() {
    }

    public Student(String sid, String name, int age, String birthday) {
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    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 getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;

测试类的定义

package com.bcsbj.test;

import com.bcsbj.domain.Student;

import java.util.ArrayList;
import java.util.Scanner;

public class StudentManager {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        // 创建集合容器对象
        ArrayList<Student> list = new ArrayList<>();

        lo:
        while (true) {
            // 1. 搭建主界面菜单
            System.out.println("--------欢迎来到学生管理系统--------");
            System.out.println("1 添加学生");
            System.out.println("2 删除学生");
            System.out.println("3 修改学生");
            System.out.println("4 查看学生");
            System.out.println("5 退出");
            System.out.println("请输入您的选择:");

            String choice = sc.next();

            switch (choice) {
                case "1":
                    //System.out.println("添加学生");
                    addStudent(list);
                    break;
                case "2":
                    //System.out.println("删除学生");
                    deleteStudent(list);
                    break;
                case "3":
                    //System.out.println("修改学生");
                    updateStudent(list);
                    break;
                case "4":
                    // System.out.println("查看学生");
                    queryStudents(list);
                    break;
                case "5":
                    System.out.println("感谢您的使用");
                    break lo;
                default:
                    System.out.println("您的输入有误");
                    break;
            }
        }

    }

    // 修改学生的方法
    public static void updateStudent(ArrayList<Student> list) {
        System.out.println("请输入您要修改的学生学号:");
        Scanner sc = new Scanner(System.in);
        String updateSid = sc.next();
        // 3. 调用getIndex方法, 查找该学号在集合中出现的索引位置
        int index = getIndex(list,updateSid);
        // 4. 根据索引判断, 学号在集合中是否存在
        if(index == -1){
            // 不存在: 给出提示
            System.out.println("查无信息, 请重新输入");
        }else{
            // 存在: 接收新的学生信息
            System.out.println("请输入新的学生姓名:");
            String name = sc.next();
            System.out.println("请输入新的学生年龄:");
            int age = sc.nextInt();
            System.out.println("请输入新的学生生日:");
            String birthday = sc.next();
            // 封装为新的学生对象
            Student stu = new Student(updateSid, name, age, birthday);
            // 调用集合的set方法, 完成修改
            list.set(index, stu);
            System.out.println("修改成功!");
        }
    }

    // 删除学生的方法
    public static void deleteStudent(ArrayList<Student> list) {
        // 1. 给出提示信息 (请输入您要删除的学号)
        System.out.println("请输入您要删除的学生学号:");
        // 2. 键盘接收要删除的学号
        Scanner sc = new Scanner(System.in);
        String deleteSid = sc.next();
        // 3. 调用getIndex方法, 查找该学号在集合中出现的索引位置
        int index = getIndex(list,deleteSid);
        // 4. 根据索引判断, 学号在集合中是否存在
        if(index == -1){
            // 不存在: 给出提示
            System.out.println("查无信息, 请重新输入");
        }else{
            // 存在:删除
            list.remove(index);
            System.out.println("删除成功!");
        }
    }

    // 查看学生的方法
    public static void queryStudents(ArrayList<Student> list) {
        // 1. 判断集合中是否存在数据, 如果不存在直接给出提示
        if(list.size() == 0){
            System.out.println("无信息, 请添加后重新查询");
            return;
        }
        // 2. 存在: 展示表头数据
        System.out.println("学号\t\t姓名\t年龄\t生日");
        // 3. 遍历集合, 获取每一个学生对象的信息, 打印在控制台
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            System.out.println(stu.getSid() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t\t" + stu.getBirthday());
        }
    }

    // 添加学生的方法
    public static void addStudent(ArrayList<Student> list) {
        Scanner sc = new Scanner(System.in);
        // 1. 给出录入的提示信息

        String sid;

        while(true){
            System.out.println("请输入学号:");
            sid = sc.next();

            int index = getIndex(list, sid);

            if(index == -1){
                // sid不存在, 学号可以使用
                break;
            }
        }

        System.out.println("请输入姓名:");
        String name = sc.next();
        System.out.println("请输入年龄:");
        int age = sc.nextInt();
        System.out.println("请输入生日:");
        String birthday = sc.next();
        // 2. 将键盘录入的信息封装为学生对象
        Student stu = new Student(sid,name,age,birthday);
        // 3. 将封装好的学生对象, 添加到集合容器当中
        list.add(stu);
        // 4. 给出添加成功的提示信息
        System.out.println("添加成功!");
    }

    /*
        getIndex : 接收一个集合对象, 接收一个学生学号

        查找这个学号, 在集合中出现的索引位置
     */
    public static int getIndex(ArrayList<Student> list, String sid){
        // 1. 假设传入的学号, 在集合中不存在
        int index = -1;
        // 2. 遍历集合, 获取每一个学生对象, 准备进行查找
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            // 3. 获取每一个学生对象的学号
            String id = stu.getSid();
            // 4. 使用获取出的学生学号, 和传入的学号(查找的学号)进行比对
            if(id.equals(sid)){
                // 存在: 让index变量记录正确的索引位置
                index = i;
            }
        }

        return index;
    }
}

面向对象高级

案例驱动模式

案例驱动模式概述 (理解)

通过我们已掌握的知识点,先实现一个案例,然后找出这个案例中,存在的一些问题,在通过新知识点解决问题

案例驱动模式的好处 (理解)

  • 解决重复代码过多的冗余,提高代码的复用性
  • 解决业务逻辑聚集紧密导致的可读性差,提高代码的可读性
  • 解决代码可维护性差,提高代码的维护性

分类思想

分类思想概述 (理解)

分工协作,专人干专事

编程狮笔记信息管理系统 (理解)

  • Student类 标准学生类,封装键盘录入的学生信息(id , name , age , birthday)

  • StudentDao类 Dao : (Data Access Object 缩写) 用于访问存储数据的数组或集合

  • StudentService类 用来进行业务逻辑的处理(例如: 判断录入的id是否存在)

  • StudentController类 和用户打交道(接收用户需求,采集用户信息,打印数据到控制台)

分包思想

分包思想概述 (理解)

如果将所有的类文件都放在同一个包下,不利于管理和后期维护,所以,对于不同功能的类文件,可以放在不同的包下进行管理

包的概述 (记忆)

  • 本质上就是文件夹

  • 创建包

    多级包之间使用 " . " 进行分割
    多级包的定义规范:公司的网站地址翻转(去掉www)
    比如:黑马程序员的网站址为www.bcsbj.com
    后期我们所定义的包的结构就是:com.bcsbj.其他的包名

  • 包的命名规则

    字母都是小写

包的注意事项 (理解)

  • package语句必须是程序的第一条可执行的代码
  • package语句在一个java文件中只能有一个
  • 如果没有package,默认表示无包名

类与类之间的访问 (理解)

  • 同一个包下的访问

    不需要导包,直接使用即可

  • 不同包下的访问

    1.import 导包后访问

    2.通过全类名(包名 + 类名)访问

  • 注意:import 、package 、class 三个关键字的摆放位置存在顺序关系

    package 必须是程序的第一条可执行的代码

    import 需要写在 package 下面

    class 需要在 import 下面

编程狮笔记管理系统

系统介绍 (理解)

学生管理系统 (应用)

需求说明

  • 添加学生: 键盘录入学生信息(id,name,age,birthday)

    使用数组存储学生信息,要求学生的id不能重复

  • 删除学生: 键盘录入要删除学生的id值,将该学生从数组中移除,如果录入的id在数组中不存在,需要重新录入

  • 修改学生: 键盘录入要修改学生的id值和修改后的学生信息

    将数组中该学生的信息修改,如果录入的id在数组中不存在,需要重新录入

  • 查询学生: 将数组中存储的所有学生的信息输出到控制台

实现步骤

  • 环境搭建实现步骤

    存储的类 作用
    com.bcsbj.edu.info.manager.domain Student.java 封装学生信息
    com.bcsbj.edu.info.manager.dao StudentDao.java 访问存储数据的数组,进行赠删改查(库管)
    com.bcsbj.edu.info.manager.service StudentService.java 业务的逻辑处理(业务员)
    com.bcsbj.edu.info.manager.controller StudentController.java 和用户打交道(客服接待)
    com.bcsbj.edu.info.manager.entry InfoManagerEntry.java 程序的入口类,提供一个main方法
  • 菜单搭建实现步骤

    • 需求
    • 编程狮笔记管理系统菜单搭建
    • 学生管理系统菜单搭建
    • 实现步骤
      1. 展示欢迎页面,用输出语句完成主界面的编写
      2. 获取用户的选择,用Scanner实现键盘录入数据
      3. 根据用户的选择执行对应的操作,用switch语句完成操作的选择
  • 添加功能实现步骤

  • 添加功能优化:判断id是否存在

  • 查询功能实现步骤

  • 删除功能实现步骤

  • 修改功能实现步骤

  • 系统优化
    把updateStudent和deleteStudentById中录入学生id代码抽取到一个方法(inputStudentId)中
    该方法的主要作用就是录入学生的id,方法的返回值为String类型

  • 把addStudent和updateStudent中录入学生信息的代码抽取到一个方法(inputStudentInfo)中
    该方法的主要作用就是录入学生的信息,并封装为学生对象,方法的返回值为Student类型

代码实现

学生类

public class Student {
    private String id;
    private String name;
    private String age;
    private String birthday;

    public Student() {
    }

    public Student(String id, String name, String age, String birthday) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

}

程序入口InfoManagerEntry类

public class InfoManagerEntry {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (true) {
            // 主菜单搭建
            System.out.println("--------欢迎来到编程狮笔记管理系统--------");
            System.out.println("请输入您的选择: 1.学生管理  2.老师管理  3.退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    // System.out.println("学生管理");
                    // 开启学生管理系统
                    StudentController studentController = new StudentController();
                    studentController.start();
                    break;
                case "2":
                    System.out.println("老师管理");
                    TeacherController teacherController = new TeacherController();
                    teacherController.start();
                    break;
                case "3":
                    System.out.println("感谢您的使用");
                    // 退出当前正在运行的JVM虚拟机
                    System.exit(0);
                    break;
                default:
                    System.out.println("您的输入有误, 请重新输入");
                    break;
            }
        }
    }
}

StudentController类

public class StudentController {
    // 业务员对象
    private StudentService studentService = new StudentService();

    private Scanner sc = new Scanner(System.in);

    // 开启学生管理系统, 并展示学生管理系统菜单
    public void start() {
        //Scanner sc = new Scanner(System.in);
        studentLoop:
        while (true) {
            System.out.println("--------欢迎来到 <学生> 管理系统--------");
            System.out.println("请输入您的选择: 1.添加学生  2.删除学生  3.修改学生  4.查看学生  5.退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    // System.out.println("添加");
                    addStudent();
                    break;
                case "2":
                    // System.out.println("删除");
                    deleteStudentById();
                    break;
                case "3":
                    // System.out.println("修改");
                    updateStudent();
                    break;
                case "4":
                    // System.out.println("查询");
                    findAllStudent();
                    break;
                case "5":
                    System.out.println("感谢您使用学生管理系统, 再见!");
                    break studentLoop;
                default:
                    System.out.println("您的输入有误, 请重新输入");
                    break;
            }
        }
    }

    // 修改学生方法
    public void updateStudent() {
        String updateId = inputStudentId();
        Student newStu = inputStudentInfo(updateId);
        studentService.updateStudent(updateId, newStu);

        System.out.println("修改成功!");
    }

    // 删除学生方法
    public void deleteStudentById() {
        String delId = inputStudentId();
        // 3. 调用业务员中的deleteStudentById根据id, 删除学生
        studentService.deleteStudentById(delId);
        // 4. 提示删除成功
        System.out.println("删除成功!");
    }

    // 查看学生方法
    public void findAllStudent() {
        // 1. 调用业务员中的获取方法, 得到学生的对象数组
        Student[] stus = studentService.findAllStudent();
        // 2. 判断数组的内存地址, 是否为null
        if (stus == null) {
            System.out.println("查无信息, 请添加后重试");
            return;
        }
        // 3. 遍历数组, 获取学生信息并打印在控制台
        System.out.println("学号\t\t姓名\t年龄\t生日");
        for (int i = 0; i < stus.length; i++) {
            Student stu = stus[i];
            if (stu != null) {
                System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t\t" + stu.getBirthday());
            }
        }
    }

    // 添加学生方法
    public void addStudent() {
        // StudentService studentService = new StudentService();
        // 1. 键盘接收学生信息
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean flag = studentService.isExists(id);
            if (flag) {
                System.out.println("学号已被占用, 请重新输入");
            } else {
                break;
            }
        }

        Student stu = inputStudentInfo(id);

        // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法
        boolean result = studentService.addStudent(stu);
        // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败
        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
    }

    // 键盘录入学生id
    public String inputStudentId() {
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean exists = studentService.isExists(id);
            if (!exists) {
                System.out.println("您输入的id不存在, 请重新输入:");
            } else {
                break;
            }
        }
        return id;
    }

    // 键盘录入学生信息
    public Student inputStudentInfo(String id) {
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();
        System.out.println("请输入学生生日:");
        String birthday = sc.next();
        Student stu = new Student();
        stu.setId(id);
        stu.setName(name);
        stu.setAge(age);
        stu.setBirthday(birthday);
        return stu;
    }
}

StudentService类

public class StudentService {
    // 创建StudentDao (库管)
    private StudentDao studentDao = new StudentDao();
    // 添加学生方法
    public boolean addStudent(Student stu) {
        // 2. 将学生对象, 传递给StudentDao 库管中的addStudent方法
        // 3. 将返回的boolean类型结果, 返还给StudentController
        return studentDao.addStudent(stu);
    }
    // 判断学号是否存在方法
    public boolean isExists(String id) {
        Student[] stus = studentDao.findAllStudent();
        // 假设id在数组中不存在
        boolean exists = false;
        // 遍历数组, 获取每一个学生对象, 准备进行判断
        for (int i = 0; i < stus.length; i++) {
            Student student = stus[i];
            if(student != null && student.getId().equals(id)){
                exists = true;
                break;
            }
        }

        return exists;
    }
    // 查看学生方法
    public Student[] findAllStudent() {
        // 1. 调用库管对象的findAllStudent获取学生对象数组
        Student[] allStudent = studentDao.findAllStudent();
        // 2. 判断数组中是否有学生信息 (有: 返回地址,  没有: 返回null)
        // 思路: 数组中只要存在一个不是null的元素, 那就代表有学生信息
        boolean flag = false;
        for (int i = 0; i < allStudent.length; i++) {
            Student stu = allStudent[i];
            if(stu != null){
                flag = true;
                break;
            }
        }

        if(flag){
            // 有信息
            return allStudent;
        }else{
            // 没有信息
            return null;
        }

    }

    public void deleteStudentById(String delId) {
        studentDao.deleteStudentById(delId);
    }

    public void updateStudent(String updateId, Student newStu) {
        studentDao.updateStudent(updateId, newStu);
    }
}

StudentDao类

public class StudentDao {
    // 创建学生对象数组
    private static Student[] stus = new Student[5];
    // 添加学生方法
    public boolean addStudent(Student stu) {

        // 2. 添加学生到数组
        //2.1 定义变量index为-1,假设数组已经全部存满,没有null的元素
        int index = -1;
        //2.2 遍历数组取出每一个元素,判断是否是null
        for (int i = 0; i < stus.length; i++) {
            Student student = stus[i];
            if(student == null){
                index = i;
                //2.3 如果为null,让index变量记录当前索引位置,并使用break结束循环遍历
                break;
            }
        }

        // 3. 返回是否添加成功的boolean类型状态
        if(index == -1){
            // 装满了
            return false;
        }else{
            // 没有装满, 正常添加, 返回true
            stus[index] = stu;
            return true;
        }
    }
    // 查看学生方法
    public Student[] findAllStudent() {
        return stus;
    }

    public void deleteStudentById(String delId) {
        // 1. 查找id在容器中所在的索引位置
        int index = getIndex(delId);
        // 2. 将该索引位置,使用null元素进行覆盖
        stus[index] = null;
    }

    public int getIndex(String id){
        int index = -1;
        for (int i = 0; i < stus.length; i++) {
            Student stu = stus[i];
            if(stu != null && stu.getId().equals(id)){
                index = i;
                break;
            }
        }
        return index;
    }

    public void updateStudent(String updateId, Student newStu) {
        // 1. 查找updateId, 在容器中的索引位置
        int index = getIndex(updateId);
        // 2. 将该索引位置, 使用新的学生对象替换
        stus[index] = newStu;
    }
}

老师管理系统 (应用)

需求说明

  • 添加老师: 通过键盘录入老师信息(id,name,age,birthday)

    使用数组存储老师信息,要求老师的id不能重复

  • 删除老师: 通过键盘录入要删除老师的id值,将该老师从数组中移除,如果录入的id在数组中不存在,需要重新录入

  • 修改老师: 通过键盘录入要修改老师的id值和修改后的老师信息

    将数组中该老师的信息修改,如果录入的id在数组中不存在,需要重新录入

  • 查询老师: 将数组中存储的所有老师的信息输出到控制台

实现步骤

  • 环境搭建实现步骤

    存储的类 作用
    com.itheima.edu.info.manager.domain Student.java Teacher.java 封装学生信息 封装老师信息
    com.itheima.edu.info.manager.dao StudentDao.java TeacherDao.java 访问存储数据的数组,进行赠删改查(库管)
    com.itheima.edu.info.manager.service StudentService.java TeacherService.java 业务的逻辑处理(业务员)
    com.itheima.edu.info.manager.controller StudentController.java TeacherController.java 和用户打交道(客服接待)
    com.itheima.edu.info.manager.entry InfoManagerEntry.java 程序的入口类,提供一个main方法
  • 菜单搭建实现步骤

    1. 展示欢迎页面,用输出语句完成主界面的编写
    2. 获取用户的选择,用Scanner实现键盘录入数据
    3. 根据用户的选择执行对应的操作,用switch语句完成操作的选择
  • 添加功能实现步骤

  • 查询功能实现步骤

  • 删除功能实现步骤

  • 修改功能实现步骤

  • 系统优化

  • 把updateTeacher和deleteTeacherById中录入老师id代码抽取到一个方法(inputTeacherId)中
    该方法的主要作用就是录入老师的id,方法的返回值为String类型

  • 把addTeacher和updateTeacher中录入老师信息的代码抽取到一个方法(inputTeacherInfo)中
    该方法的主要作用就是录入老师的信息,并封装为老师对象,方法的返回值为Teacher类型

代码实现

老师类

public class Teacher extends Person{
    private String id;
    private String name;
    private String age;
    private String birthday;

    public Teacher() {
    }

    public Teacher(String id, String name, String age, String birthday) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

TeacherController类

public class TeacherController {

    private Scanner sc = new Scanner(System.in);
    private TeacherService teacherService = new TeacherService();

    public void start() {

        teacherLoop:
        while (true) {
            System.out.println("--------欢迎来到 <老师> 管理系统--------");
            System.out.println("请输入您的选择: 1.添加老师  2.删除老师  3.修改老师  4.查看老师  5.退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    // System.out.println("添加老师");
                    addTeacher();
                    break;
                case "2":
                    // System.out.println("删除老师");
                    deleteTeacherById();
                    break;
                case "3":
                    // System.out.println("修改老师");
                    updateTeacher();
                    break;
                case "4":
                    // System.out.println("查看老师");
                    findAllTeacher();
                    break;
                case "5":
                    System.out.println("感谢您使用老师管理系统, 再见!");
                    break teacherLoop;
                default:
                    System.out.println("您的输入有误, 请重新输入");
                    break;
            }
        }

    }

    public void updateTeacher() {
        String id = inputTeacherId();

        Teacher newTeacher = inputTeacherInfo(id);

        // 调用业务员的修改方法
        teacherService.updateTeacher(id,newTeacher);
        System.out.println("修改成功");
    }

    public void deleteTeacherById() {

        String id = inputTeacherId();

        // 2. 调用业务员中的删除方法, 根据id, 删除老师
        teacherService.deleteTeacherById(id);

        // 3. 提示删除成功
        System.out.println("删除成功");

    }

    public void findAllTeacher() {
        // 1. 从业务员中, 获取老师对象数组
        Teacher[] teachers = teacherService.findAllTeacher();

        // 2. 判断数组中是否有元素
        if (teachers == null) {
            System.out.println("查无信息, 请添加后重试");
            return;
        }

        // 3. 遍历数组, 取出元素, 并打印在控制台
        System.out.println("学号\t\t姓名\t年龄\t生日");
        for (int i = 0; i < teachers.length; i++) {
            Teacher t = teachers[i];
            if (t != null) {
                System.out.println(t.getId() + "\t" + t.getName() + "\t" + t.getAge() + "\t\t" + t.getBirthday());
            }
        }
    }

    public void addTeacher() {
        String id;
        while (true) {
            // 1. 接收不存在的老师id
            System.out.println("请输入老师id:");
            id = sc.next();
            // 2. 判断id是否存在
            boolean exists = teacherService.isExists(id);

            if (exists) {
                System.out.println("id已被占用, 请重新输入:");
            } else {
                break;
            }
        }

        Teacher t = inputTeacherInfo(id);

        // 5. 将封装好的老师对象, 传递给TeacherService继续完成添加操作
        boolean result = teacherService.addTeacher(t);

        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
    }

    // 录入老师id
    public String inputTeacherId(){
        String id;
        while(true){
            System.out.println("请输入id");
            id = sc.next();
            boolean exists = teacherService.isExists(id);
            if(!exists){
                System.out.println("您输入的id不存在, 请重新输入:");
            }else{
                break;
            }
        }
        return id;
    }

    // 录入老师信息, 封装为老师对象
    public Teacher inputTeacherInfo(String id){
        System.out.println("请输入老师姓名:");
        String name = sc.next();
        System.out.println("请输入老师年龄:");
        String age = sc.next();
        System.out.println("请输入老师生日:");
        String birthday = sc.next();

        Teacher t = new Teacher();
        t.setId(id);
        t.setName(name);
        t.setAge(age);
        t.setBirthday(birthday);

        return t;
    }
}

TeacherService类

public class TeacherService {

    private TeacherDao teacherDao = new TeacherDao();

    public boolean addTeacher(Teacher t) {
        return teacherDao.addTeacher(t);
    }

    public boolean isExists(String id) {
        // 1. 获取库管对象中的数组
        Teacher[] teachers = teacherDao.findAllTeacher();

        boolean exists = false;

        // 2. 遍历数组, 取出每一个元素, 进行判断
        for (int i = 0; i < teachers.length; i++) {
            Teacher teacher = teachers[i];
            if(teacher != null && teacher.getId().equals(id)){
                exists = true;
                break;
            }
        }

        return exists;
    }

    public Teacher[] findAllTeacher() {
        Teacher[] allTeacher = teacherDao.findAllTeacher();

        boolean flag = false;

        for (int i = 0; i < allTeacher.length; i++) {
            Teacher t = allTeacher[i];
            if(t != null){
                flag = true;
                break;
            }
        }

        if(flag){
            return allTeacher;
        }else{
            return null;
        }

    }

    public void deleteTeacherById(String id) {
        teacherDao.deleteTeacherById(id);
    }

    public void updateTeacher(String id, Teacher newTeacher) {
        teacherDao.updateTeacher(id,newTeacher);
    }
}

TeacherDao类

public class TeacherDao {

    private static Teacher[] teachers = new Teacher[5];

    public boolean addTeacher(Teacher t) {
        int index = -1;
        for (int i = 0; i < teachers.length; i++) {
            Teacher teacher = teachers[i];
            if(teacher == null){
                index = i;
                break;
            }
        }

        if(index == -1){
            return false;
        }else{
            teachers[index] = t;
            return true;
        }

    }

    public Teacher[] findAllTeacher() {
        return teachers;
    }

    public void deleteTeacherById(String id) {
        // 1. 查询id在数组中的索引位置
        int index = getIndex(id);
        // 2. 将该索引位置的元素, 使用null进行替换
        teachers[index] = null;
    }

    public int getIndex(String id){
        int index = -1;
        for (int i = 0; i < teachers.length; i++) {
            Teacher t = teachers[i];
            if(t != null && t.getId().equals(id)){
                index = i;
                break;
            }
        }

        return index;
    }

    public void updateTeacher(String id, Teacher newTeacher) {
        int index = getIndex(id);
        teachers[index] = newTeacher;
    }
}

static关键字

static关键字概述 (理解)

static 关键字是静态的意思,是Java中的一个修饰符,可以修饰成员方法,成员变量

static修饰的特点 (记忆)

  • 被类的所有对象共享

    是我们判断是否使用静态关键字的条件

  • 随着类的加载而加载,优先于对象存在

    对象需要类被加载后,才能创建

  • 可以通过类名调用

    也可以通过对象名调用

static关键字注意事项 (理解)

  • 静态方法只能访问静态的成员

  • 非静态方法可以访问静态的成员,也可以访问非静态的成员

  • 静态方法中是没有this关键字

  • 示例代码

    • Student类
package com.bcsbj.test;

public class Student {
    String name;
    int age;
    static String school;

    /*
        静态随着类的加载而加载, 优先于对象存在
        非静态需要在创建对象之后,才可以进行使用

        1. 静态方法中, 只能访问静态成员(成员变量, 成员方法)
        2. 非静态方法中, 可以使用静态成员, 也可以使用非静态成员
        3. 静态方法中, 没有this关键字
     */
    public void show() {
        System.out.println(name + "..." + age + "..." + school);
    }

    public static void method(){
        // this: 当前对象的引用
        // this需要在创建对象之后, 才会存在, 静态存在的时候, 对象可能还没有被创建
        // this.name = "张三";
        System.out.println(school);
    }
}

测试类

package com.bcsbj.test;

public class Test1Static {
    /*
        1. 被static修饰的成员, 会被该类的所有对象所[共享]
        2. 被static修饰的成员, 会随着类的加载而加载, 优先于对象存在
        3. 多了一种调用方式, 可以通过类名.进行调用
     */
    public static void main(String[] args) {
        Student.school = "编程狮专修学院";
        Student stu1 = new Student();
        stu1.name = "张三";
        stu1.age = 23;
        //stu1.school = "编程狮专修学院";
        stu1.show();

        Student stu2 = new Student();
        stu2.show();

        //调用静态方法
        Student.method();
    }
}

继承

继承的实现(掌握)

  • 继承的概念

    • 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
  • 实现继承的格式

    • 继承通过extends实现
    • 格式:class 子类 extends 父类 { }
    • 举例:class Dog extends Animal { }
  • 继承带来的好处

    • 继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
  • 示例代码

public class Fu {
    public void show() {
        System.out.println("show方法被调用");
    }
}
public class Zi extends Fu {
    public void method() {
        System.out.println("method方法被调用");
    }
}
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Fu f = new Fu();
        f.show();

        Zi z = new Zi();
        z.method();
        z.show();
    }
}

继承的好处和弊端(理解)

  • 继承好处
    • 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
    • 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
  • 继承弊端
    • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
  • 继承的应用场景:
    • 使用继承,需要考虑类与类之间是否存在is..a的关系,不能盲目使用继承
    • is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类

Java中继承的特点(掌握)

  • Java中继承的特点

    1. Java中类只支持单继承,不支持多继承
      • 错误范例:class A extends B, C { }
    2. Java中类支持多层继承
  • 多层继承示例代码:

public class Granddad {
    public void drink() {
        System.out.println("爷爷爱喝酒");
    }
}
public class Father extends Granddad {

    public void smoke() {
        System.out.println("爸爸爱抽烟");
    }
}
public class Mother {
    public void dance() {
        System.out.println("妈妈爱跳舞");
    }
}
public class Son extends Father {
// 此时,Son类中就同时拥有drink方法以及smoke方法
}

继承中的成员访问特点

继承中变量的访问特点(掌握)

在子类方法中访问一个变量,采用的是就近原则。

  1. 子类局部范围找
  2. 子类成员范围找
  3. 父类成员范围找
  4. 如果都没有就报错(不考虑父亲的父亲…)
  • 示例代码
class Fu {
    int num = 10;
}
class Zi {
    int num = 20;
    public void show(){
        int num = 30;
        System.out.println(num);
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();// 输出show方法中的局部变量30
    }
}

super(掌握)

  • this&super关键字:
    • this:代表本类对象的引用
    • super:代表父类存储空间的标识(可以理解为父类对象引用)
  • this和super的使用分别
    • 成员变量:
    • this.成员变量 - 访问本类成员变量
    • super.成员变量 - 访问父类成员变量
    • 成员方法:
    • this.成员方法 - 访问本类成员方法
    • super.成员方法 - 访问父类成员方法
  • 构造方法:
    • this(…) - 访问本类构造方法
    • super(…) - 访问父类构造方法

继承中构造方法的访问特点(理解)

注意:子类中所有的构造方法默认都会访问父类中无参的构造方法

子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()。

问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

  1. 通过使用super关键字去显示的调用父类的带参构造方法
  2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法

注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存

继承中成员方法的访问特点(掌握)

通过子类对象访问一个方法

  1. 子类成员范围找
  2. 父类成员范围找
  3. 如果都没有就报错(不考虑父亲的父亲…)

super内存图(理解)

对象在堆内存中,会单独存在一块super区域,用来存放父类的数据

方法重写(掌握)

  • 1、方法重写概念
    • 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
  • 2、方法重写的应用场景
    • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
  • 3、Override注解
    • 用来检测当前的方法,是否是重写的方法,起到【校验】的作用

方法重写的注意事项(掌握)

  • 方法重写的注意事项
  1. 私有方法不能被重写(父类私有成员子类是不能继承的)
  2. 子类方法访问权限不能更低(public > 默认 > 私有)
  3. 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法
  • 示例代码(@Override重写方法)
public class Fu {
    private void show() {
        System.out.println("Fu中show()方法被调用");
    }

    void method() {
        System.out.println("Fu中method()方法被调用");
    }
}

public class Zi extends Fu {

    /* 编译【出错】,子类不能重写父类私有的方法*/
    @Override
    private void show() {
        System.out.println("Zi中show()方法被调用");
    }
    /* 编译【出错】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    private void method() {
        System.out.println("Zi中method()方法被调用");
    }

    /* 编译【通过】,子类重写父类方法的时候,访问权限需要大于等于父类 */
    @Override
    public void method() {
        System.out.println("Zi中method()方法被调用");
    }
}

权限修饰符 (理解)

编程狮笔记管理系统使用继承改进 (掌握)

  • 需求

    把学生类和老师类共性的内容向上抽取,抽取到出一个 Person 父类,让学生类和老师类继承 Person 类

  • 实现步骤

    1. 抽取Person类

    2. 优化StudentController类中,inputStudentInfo方法,将setXxx赋值方式,改进为构造方法初始化

      注意:直接修改这种操作方式,不符合我们开发中的一个原则

      ​ 开闭原则 ( 对扩展开放对修改关闭 ) : 尽量在不更改原有代码的前提下以完成需求

      解决:重新创建一个OtherStudentController类

      编写新的inputStudentInfo方法

    3. 根据StudentController类、OtherStudentController类,向上抽取出BaseStudentController类
      再让StudentController类、OtherStudentController类,继承BaseStudentController类

  • 代码实现

    Person类及学生类和老师类

public class Person {
    private String id;
    private String name;
    private String age;
    private String birthday;

    public Person() {
    }

    public Person(String id, String name, String age, String birthday) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}
// Student类
public class Student extends Person {
    public Student() {
    }

    public Student(String id, String name, String age, String birthday) {
        super(id, name, age, birthday);
    }
}
// Teacher类
public class Teacher extends Person {
    public Teacher() {
    }

    public Teacher(String id, String name, String age, String birthday) {
        super(id, name, age, birthday);
    }
}

BaseStudentController类

public abstract class BaseStudentController {
    // 业务员对象
    private StudentService studentService = new StudentService();

    private Scanner sc = new Scanner(System.in);

    // 开启学生管理系统, 并展示学生管理系统菜单
    public void start() {
        //Scanner sc = new Scanner(System.in);
        studentLoop:
        while (true) {
            System.out.println("--------欢迎来到 <学生> 管理系统--------");
            System.out.println("请输入您的选择: 1.添加学生  2.删除学生  3.修改学生  4.查看学生  5.退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    // System.out.println("添加");
                    addStudent();
                    break;
                case "2":
                    // System.out.println("删除");
                    deleteStudentById();
                    break;
                case "3":
                    // System.out.println("修改");
                    updateStudent();
                    break;
                case "4":
                    // System.out.println("查询");
                    findAllStudent();
                    break;
                case "5":
                    System.out.println("感谢您使用学生管理系统, 再见!");
                    break studentLoop;
                default:
                    System.out.println("您的输入有误, 请重新输入");
                    break;
            }
        }
    }

    // 修改学生方法
    public void updateStudent() {
        String updateId = inputStudentId();
        Student newStu = inputStudentInfo(updateId);
        studentService.updateStudent(updateId, newStu);

        System.out.println("修改成功!");
    }

    // 删除学生方法
    public void deleteStudentById() {
        String delId = inputStudentId();
        // 3. 调用业务员中的deleteStudentById根据id, 删除学生
        studentService.deleteStudentById(delId);
        // 4. 提示删除成功
        System.out.println("删除成功!");
    }

    // 查看学生方法
    public void findAllStudent() {
        // 1. 调用业务员中的获取方法, 得到学生的对象数组
        Student[] stus = studentService.findAllStudent();
        // 2. 判断数组的内存地址, 是否为null
        if (stus == null) {
            System.out.println("查无信息, 请添加后重试");
            return;
        }
        // 3. 遍历数组, 获取学生信息并打印在控制台
        System.out.println("学号\t\t姓名\t年龄\t生日");
        for (int i = 0; i < stus.length; i++) {
            Student stu = stus[i];
            if (stu != null) {
                System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t\t" + stu.getBirthday());
            }
        }
    }

    // 添加学生方法
    public void addStudent() {
        // StudentService studentService = new StudentService();
        // 1. 键盘接收学生信息
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean flag = studentService.isExists(id);
            if (flag) {
                System.out.println("学号已被占用, 请重新输入");
            } else {
                break;
            }
        }

        Student stu = inputStudentInfo(id);

        // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法
        boolean result = studentService.addStudent(stu);
        // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败
        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
    }

    // 键盘录入学生id
    public String inputStudentId() {
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean exists = studentService.isExists(id);
            if (!exists) {
                System.out.println("您输入的id不存在, 请重新输入:");
            } else {
                break;
            }
        }
        return id;
    }

    // 键盘录入学生信息
    // 开闭原则: 对扩展内容开放, 对修改内容关闭
  public Student inputStudentInfo(String id){
    return null;
  }
}

StudentController类

public class StudentController extends BaseStudentController {

    private Scanner sc = new Scanner(System.in);

    // 键盘录入学生信息
    // 开闭原则: 对扩展内容开放, 对修改内容关闭
    @Override
    public Student inputStudentInfo(String id) {
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();
        System.out.println("请输入学生生日:");
        String birthday = sc.next();
        Student stu = new Student();
        stu.setId(id);
        stu.setName(name);
        stu.setAge(age);
        stu.setBirthday(birthday);
        return stu;
    }
}

OtherStudentController类

public class OtherStudentController extends BaseStudentController {

    private Scanner sc = new Scanner(System.in);

    // 键盘录入学生信息
    // 开闭原则: 对扩展内容开放, 对修改内容关闭
    @Override
    public Student inputStudentInfo(String id) {
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();
        System.out.println("请输入学生生日:");
        String birthday = sc.next();
        Student stu = new Student(id,name,age,birthday);
        return stu;
    }
}

抽象类

抽象类的概述(理解)

当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!

​ 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!

抽象类的特点(记忆)

抽象类和抽象方法必须使用 abstract 关键字修饰

//抽象类的定义
public abstract class 类名 {}

//抽象方法的定义
public abstract void eat();
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化

  • 抽象类可以有构造方法

  • 抽象类的子类

    ​ 要么重写抽象类中的所有抽象方法

    ​ 要么是抽象类

    抽象类的案例(应用)

  • 案例需求

    ​ 定义猫类(Cat)和狗类(Dog)

    ​ 猫类成员方法:eat(猫吃鱼)drink(喝水…)

    ​ 狗类成员方法:eat(狗吃肉)drink(喝水…)

  • 实现步骤

    1. 猫类和狗类中存在共性内容,应向上抽取出一个动物类(Animal)
    2. 父类Animal中,无法将 eat 方法具体实现描述清楚,所以定义为抽象方法
    3. 抽象方法需要存活在抽象类中,将Animal定义为抽象类
    4. 让 Cat 和 Dog 分别继承 Animal,重写eat方法
    5. 测试类中创建 Cat 和 Dog 对象,调用方法测试
  • 代码实现

    • 动物类
public abstract class Animal {
    public void drink(){
        System.out.println("喝水");
    }

    public Animal(){

    }

    public abstract void eat();
}

猫类

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

狗类

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

测试类

public static void main(String[] args) {
        Dog d = new Dog();
        d.eat();
        d.drink();

        Cat c = new Cat();
        c.drink();
        c.eat();

        //Animal a = new Animal();
        //a.eat();
    }

模板设计模式

  • 设计模式

    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
    使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

  • 模板设计模式

    把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法
    让使用模板的类(继承抽象类的类)去重写抽象方法实现需求

  • 模板设计模式的优势

    模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可

  • 示例代码

    模板类

/*
    作文模板类
 */
public abstract class CompositionTemplate {

    public final void write(){
        System.out.println("<<我的爸爸>>");

        body();

        System.out.println("啊~ 这就是我的爸爸");

    }

    public abstract void body();
}

实现类A

public class Tom extends CompositionTemplate {

    @Override
    public void body() {
        System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " +
                "那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬...");
    }
}

实现类B

public class Tony extends CompositionTemplate {
    @Override
    public void body() {

    }

    /*public void write(){

    }*/
}

测试类

public class Test {
    public static void main(String[] args) {
        Tom t = new Tom();
        t.write();
    }
}

final(应用)

  • fianl关键字的作用

    • final代表最终的意思,可以修饰成员方法,成员变量,类
  • final修饰类、方法、变量的效果

    • fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)

    • final修饰方法:该方法不能被重写

    • final修饰变量:表明该变量是一个常量,不能再次赋值

    • 变量是基本类型,不能改变的是值

    • 变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的

    • 举例

public static void main(String[] args){
    final Student s = new Student(23);
    s = new Student(24);  // 错误,不能创建新的对象
    s.setAge(24);  // 正确
}

编程狮笔记管理系统使用抽象类改进 (应用)

  • 需求

    1. 使用抽象类的思想,将BaseStudentController 中的 inputStudentInfo 方法,定义为抽象方法
    2. 将不希望子类重写的方法,使用 final 进行修饰
  • 代码实现

    BaseStudentController类

public abstract class BaseStudentController {
    // 业务员对象
    private StudentService studentService = new StudentService();

    private Scanner sc = new Scanner(System.in);

    // 开启学生管理系统, 并展示学生管理系统菜单
    public final void start() {
        //Scanner sc = new Scanner(System.in);
        studentLoop:
        while (true) {
            System.out.println("--------欢迎来到 <学生> 管理系统--------");
            System.out.println("请输入您的选择: 1.添加学生  2.删除学生  3.修改学生  4.查看学生  5.退出");
            String choice = sc.next();
            switch (choice) {
                case "1":
                    // System.out.println("添加");
                    addStudent();
                    break;
                case "2":
                    // System.out.println("删除");
                    deleteStudentById();
                    break;
                case "3":
                    // System.out.println("修改");
                    updateStudent();
                    break;
                case "4":
                    // System.out.println("查询");
                    findAllStudent();
                    break;
                case "5":
                    System.out.println("感谢您使用学生管理系统, 再见!");
                    break studentLoop;
                default:
                    System.out.println("您的输入有误, 请重新输入");
                    break;
            }
        }
    }

    // 修改学生方法
    public final void updateStudent() {
        String updateId = inputStudentId();
        Student newStu = inputStudentInfo(updateId);
        studentService.updateStudent(updateId, newStu);

        System.out.println("修改成功!");
    }

    // 删除学生方法
    public final void deleteStudentById() {
        String delId = inputStudentId();
        // 3. 调用业务员中的deleteStudentById根据id, 删除学生
        studentService.deleteStudentById(delId);
        // 4. 提示删除成功
        System.out.println("删除成功!");
    }

    // 查看学生方法
    public final void findAllStudent() {
        // 1. 调用业务员中的获取方法, 得到学生的对象数组
        Student[] stus = studentService.findAllStudent();
        // 2. 判断数组的内存地址, 是否为null
        if (stus == null) {
            System.out.println("查无信息, 请添加后重试");
            return;
        }
        // 3. 遍历数组, 获取学生信息并打印在控制台
        System.out.println("学号\t\t姓名\t年龄\t生日");
        for (int i = 0; i < stus.length; i++) {
            Student stu = stus[i];
            if (stu != null) {
                System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t\t" + stu.getBirthday());
            }
        }
    }

    // 添加学生方法
    public final void addStudent() {
        // StudentService studentService = new StudentService();
        // 1. 键盘接收学生信息
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean flag = studentService.isExists(id);
            if (flag) {
                System.out.println("学号已被占用, 请重新输入");
            } else {
                break;
            }
        }

        Student stu = inputStudentInfo(id);

        // 3. 将学生对象,传递给StudentService(业务员)中的addStudent方法
        boolean result = studentService.addStudent(stu);
        // 4. 根据返回的boolean类型结果, 在控制台打印成功\失败
        if (result) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
    }

    // 键盘录入学生id
    public String inputStudentId() {
        String id;
        while (true) {
            System.out.println("请输入学生id:");
            id = sc.next();
            boolean exists = studentService.isExists(id);
            if (!exists) {
                System.out.println("您输入的id不存在, 请重新输入:");
            } else {
                break;
            }
        }
        return id;
    }

    // 键盘录入学生信息
    // 开闭原则: 对扩展内容开放, 对修改内容关闭
  public abstract Student inputStudentInfo(String id);
}

代码块

代码块概述 (理解)

在Java中,使用 { } 括起来的代码被称为代码块

代码块分类 (理解)

局部代码块

  • 位置: 方法中定义

  • 作用: 限定变量的生命周期,及早释放,提高内存利用率

  • 示例代码

public class Test {
    /*
        局部代码块
            位置:方法中定义
            作用:限定变量的生命周期,及早释放,提高内存利用率
     */
    public static void main(String[] args) {
        {
            int a = 10;
            System.out.println(a);
        }

       // System.out.println(a);
    }
}

构造代码块

  • 位置: 类中方法外定义

  • 特点: 每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行

  • 作用: 将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性

  • 示例代码

public class Test {
    /*
        构造代码块:
            位置:类中方法外定义
            特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
            作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
     */
    public static void main(String[] args) {
        Student stu1 = new Student();
        Student stu2 = new Student(10);
    }
}

class Student {

    {
        System.out.println("好好学习");
    }

    public Student(){
        System.out.println("空参数构造方法");
    }

    public Student(int a){
        System.out.println("带参数构造方法...........");
    }
}

静态代码块

  • 位置: 类中方法外定义

  • 特点: 需要通过static关键字修饰,随着类的加载而加载,并且只执行一次

  • 作用: 在类加载的时候做一些数据初始化的操作

  • 示例代码

public class Test {
    /*
        静态代码块:
            位置:类中方法外定义
            特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
            作用:在类加载的时候做一些数据初始化的操作
     */
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person(10);
    }
}

class Person {
    static {
        System.out.println("我是静态代码块, 我执行了");
    }

    public Person(){
        System.out.println("我是Person类的空参数构造方法");
    }

    public Person(int a){
        System.out.println("我是Person类的带...........参数构造方法");
    }
}

编程狮笔记管理系统使用代码块改进 (应用)

  • 需求

    使用静态代码块,初始化一些学生数据

  • 实现步骤

    1. 在StudentDao类中定义一个静态代码块,用来初始化一些学生数据
    2. 将初始化好的学生数据存储到学生数组中
  • 示例代码

    StudentDao类

public class StudentDao {
    // 创建学生对象数组
    private static Student[] stus = new Student[5];

    static {
        Student stu1 = new Student("heima001","张三","23","1999-11-11");
        Student stu2 = new Student("heima002","李四","24","2000-11-11");

        stus[0] = stu1;
        stus[1] = stu2;
    }

    // 添加学生方法
    public boolean addStudent(Student stu) {

        // 2. 添加学生到数组
        //2.1 定义变量index为-1,假设数组已经全部存满,没有null的元素
        int index = -1;
        //2.2 遍历数组取出每一个元素,判断是否是null
        for (int i = 0; i < stus.length; i++) {
            Student student = stus[i];
            if(student == null){
                index = i;
                //2.3 如果为null,让index变量记录当前索引位置,并使用break结束循环遍历
                break;
            }
        }

        // 3. 返回是否添加成功的boolean类型状态
        if(index == -1){
            // 装满了
            return false;
        }else{
            // 没有装满, 正常添加, 返回true
            stus[index] = stu;
            return true;
        }
    }
    // 查看学生方法
    public Student[] findAllStudent() {
        return stus;
    }

    public void deleteStudentById(String delId) {
        // 1. 查找id在容器中所在的索引位置
        int index = getIndex(delId);
        // 2. 将该索引位置,使用null元素进行覆盖
        stus[index] = null;
    }

    public int getIndex(String id){
        int index = -1;
        for (int i = 0; i < stus.length; i++) {
            Student stu = stus[i];
            if(stu != null && stu.getId().equals(id)){
                index = i;
                break;
            }
        }
        return index;
    }

    public void updateStudent(String updateId, Student newStu) {
        // 1. 查找updateId, 在容器中的索引位置
        int index = getIndex(updateId);
        // 2. 将该索引位置, 使用新的学生对象替换
        stus[index] = newStu;
    }
}

接口

编程狮笔记管理系统集合改进 (应用)

  • 使用数组容器的弊端

    1. 容器长度是固定的,不能根据添加功能自动增长
    2. 没有提供用于赠删改查的方法
  • 优化步骤

    1. 创建新的StudentDao类,OtherStudentDao

    2. 创建ArrayList集合容器对象

    3. OtherStudentDao中的方法声明,需要跟StudentDao保持一致

      注意:如果不一致,StudentService中的代码就需要进行修改

    4. 完善方法(添加、删除、修改、查看)

    5. 替换StudentService中的Dao对象

  • 代码实现

    OtherStudentDao类

public class OtherStudentDao {
    // 集合容器
    private static ArrayList<Student> stus = new ArrayList<>();

    static {
        Student stu1 = new Student("heima001","张三","17","1999-11-11");
        Student stu2 = new Student("heima002","李四","18","2000-11-11");

        stus.add(stu1);
        stus.add(stu2);
    }

    // 添加学生方法
    public boolean addStudent(Student stu) {
       stus.add(stu);
       return true;
    }

    // 查看学生方法
    public Student[] findAllStudent() {

        Student[] students = new Student[stus.size()];

        for (int i = 0; i < students.length; i++) {
            students[i] = stus.get(i);
        }

        return students;
    }

    public void deleteStudentById(String delId) {
        // 1. 查找id在容器中所在的索引位置
        int index = getIndex(delId);
        stus.remove(index);
    }

    public int getIndex(String id){
        int index = -1;
        for (int i = 0; i < stus.size(); i++) {
            Student stu = stus.get(i);
            if(stu != null && stu.getId().equals(id)){
                index = i;
                break;
            }
        }
        return index;
    }

    public void updateStudent(String updateId, Student newStu) {
        // 1. 查找updateId, 在容器中的索引位置
        int index = getIndex(updateId);
        stus.set(index, newStu);
    }
}

StudentService类

public class StudentService {
    // 创建StudentDao (库管)
     private OtherStudentDao studentDao = new OtherStudentDao();
    // 其他方法没有变化,此处省略...
}

StudentService类

public class StudentService {
    // 创建StudentDao (库管)
     private OtherStudentDao studentDao = new OtherStudentDao();
    // 其他方法没有变化,此处省略...
}

编程狮笔记管理系统抽取Dao (应用)

  • 优化步骤

    1. 将方法向上抽取,抽取出一个父类 ( BaseStudentDao )
    2. 方法的功能实现在父类中无法给出具体明确,定义为抽象方法
    3. 让两个类分别继承 BaseStudentDao ,重写内部抽象方法
  • 代码实现

    BaseStudentDao类

public abstract class BaseStudentDao {
    // 添加学生方法
    public abstract boolean addStudent(Student stu);
    // 查看学生方法
    public abstract Student[] findAllStudent();
    // 删除学生方法
    public abstract void deleteStudentById(String delId);
    // 根据id找索引方法
    public abstract int getIndex(String id);
    // 修改学生方法
    public abstract void updateStudent(String updateId, Student newStu);
}

StudentDao类

public class StudentDao extends BaseStudentDao {
  // 其他内容不变,此处省略
}

OtherStudentDao类

public class OtherStudentDao extends BaseStudentDao {
  // 其他内容不变,此处省略
}

接口的概述(理解)

  • 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
  • Java中接口存在的两个意义
    1. 用来定义规范
    2. 用来做功能的拓展

接口的特点(记忆)

接口用关键字interface修饰

public interface 接口名 {}

类实现接口用implements表示

public class 类名 implements 接口名 {}
  • 接口不能实例化

    ​ 我们可以创建接口的实现类对象使用

  • 接口的子类

    ​ 要么重写接口中的所有抽象方法

    ​ 要么子类也是抽象类

接口的成员特点(记忆)

  • 成员特点

    • 成员变量

    ​ 只能是常量
    ​ 默认修饰符:public static final

    • 构造方法

    ​ 没有,因为接口主要是扩展功能的,而没有具体存在

    • 成员方法

    ​ 只能是抽象方法

    ​ 默认修饰符:public abstract

    ​ 关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解

  • 代码演示

    • 接口
public interface Inter {
    public static final int NUM = 10;
    public abstract void show();
}

实现类

class InterImpl implements Inter{

    public void method(){
        // NUM = 20;
        System.out.println(NUM);
    }
    public void show(){
    }
}

测试类

public class TestInterface {
    /*
        成员变量: 只能是常量 系统会默认加入三个关键字
                    public static final
        构造方法: 没有
        成员方法: 只能是抽象方法, 系统会默认加入两个关键字
                    public abstract
     */
    public static void main(String[] args) {
        System.out.println(Inter.NUM);
    }
}

类和接口的关系(记忆)

  • 类与类的关系

    ​ 继承关系,只能单继承,但是可以多层继承

  • 类与接口的关系

    ​ 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

  • 接口与接口的关系

    ​ 继承关系,可以单继承,也可以多继承

编程狮笔记管理系统使用接口改进 (应用)

  • 实现步骤

    1. 将 BaseStudentDao 改进为一个接口
    2. 让 StudentDao 和 OtherStudentDao 去实现这个接口
  • 代码实现

    BaseStudentDao接口

    public interface BaseStudentDao {
    // 添加学生方法
    public abstract boolean addStudent(Student stu);
    // 查看学生方法
    public abstract Student[] findAllStudent();
    // 删除学生方法
    public abstract void deleteStudentById(String delId);
    // 根据id找索引方法
    public abstract int getIndex(String id);
    // 修改学生方法
    public abstract void updateStudent(String updateId, Student newStu);
    }

StudentDao类

public class StudentDao implements BaseStudentDao {
  // 其他内容不变,此处省略
}

OtherStudentDao类

public class OtherStudentDao implements BaseStudentDao {
  // 其他内容不变,此处省略
}

编程狮笔记管理系统解耦合改进 (应用)

  • 实现步骤

    1. 创建factory包,创建 StudentDaoFactory(工厂类)
    2. 提供 static 修改的 getStudentDao 方法,该方法用于创建StudentDao对象并返回
  • 代码实现

    StudentDaoFactory类

public class StudentDaoFactory {
    public static OtherStudentDao getStudentDao(){
        return new OtherStudentDao();
    }
}

StudentService类

public class StudentService {
    // 创建StudentDao (库管)
    // private OtherStudentDao studentDao = new OtherStudentDao();

    // 通过学生库管工厂类, 获取库管对象
    private OtherStudentDao studentDao = StudentDaoFactory.getStudentDao();
}

接口组成更新

接口组成更新概述【理解】

  • 常量

    public static final

  • 抽象方法

    public abstract

  • 默认方法(Java 8)

  • 静态方法(Java 8)

  • 私有方法(Java 9)

接口中默认方法【应用】

  • 格式

    public default 返回值类型 方法名(参数列表) { }

  • 作用

    解决接口升级的问题

  • 范例

public default void show3() {
}

注意事项

  • 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字

  • public可以省略,default不能省略

  • 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写

    接口中静态方法【应用】

  • 格式

    public static 返回值类型 方法名(参数列表) { }

  • 范例

public static void show() {
}

注意事项:

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  • public可以省略,static不能省略

接口中私有方法【应用】

  • 私有方法产生原因

    Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性

  • 定义格式

    • 格式1

    private 返回值类型 方法名(参数列表) { }

    • 范例1
private void show() {
}
  • 格式2

    private static 返回值类型 方法名(参数列表) { }

  • 范例2

private static void method() {
}

注意事项

  • 默认方法可以调用私有的静态方法和非静态方法
  • 静态方法只能调用私有的静态方法

多态

多态的概述(记忆)

  • 什么是多态

    ​ 同一个对象,在不同时刻表现出来的不同形态

  • 多态的前提

    • 要有继承或实现关系
    • 要有方法的重写
    • 要有父类引用指向子类对象
  • 代码演示

class Animal {
    public void eat(){
        System.out.println("动物吃饭");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class Test1Polymorphic {
    /*
        多态的前提:

            1. 要有(继承 \ 实现)关系
            2. 要有方法重写
            3. 要有父类引用, 指向子类对象
     */
    public static void main(String[] args) {
        // 当前事物, 是一只猫
        Cat c = new Cat();
        // 当前事物, 是一只动物
        Animal a = new Cat();
        a.eat();

    }
}

多态中的成员访问特点(记忆)

  • 成员访问特点

    • 成员变量

    编译看父类,运行看父类

    • 成员方法

    编译看父类,运行看子类

  • 代码演示

class Fu {
    int num = 10;

    public void method(){
        System.out.println("Fu.. method");
    }
}

class Zi extends Fu {
    int num = 20;

    public void method(){
        System.out.println("Zi.. method");
    }
}

public class Test2Polymorpic {
    /*
         多态的成员访问特点:

                成员变量: 编译看左边 (父类), 运行看左边 (父类)

                成员方法: 编译看左边 (父类), 运行看右边 (子类)
     */
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num);
        f.method();
    }
}

多态的好处和弊端(记忆)

  • 好处

    ​ 提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作

  • 弊端

    ​ 不能使用子类的特有成员

    多态中的转型(应用)

  • 向上转型

    ​ 父类引用指向子类对象就是向上转型

  • 向下转型

    ​ 格式:子类型 对象名 = (子类型)父类引用;

  • 代码演示

class Fu {
    public void show(){
        System.out.println("Fu..show...");
    }
}

class Zi extends Fu {
    @Override
    public void show() {
        System.out.println("Zi..show...");
    }

    public void method(){
        System.out.println("我是子类特有的方法, method");
    }
}

public class Test3Polymorpic {
    public static void main(String[] args) {
        // 1. 向上转型 : 父类引用指向子类对象
        Fu f = new Zi();
        f.show();
        // 多态的弊端: 不能调用子类特有的成员
        // f.method();

        // A: 直接创建子类对象
        // B: 向下转型

        // 2. 向下转型 : 从父类类型, 转换回子类类型
        Zi z = (Zi) f;
        z.method();
    }
}

多态中转型存在的风险和解决方案 (应用)

  • 风险

    如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException

  • 解决方案

    • 关键字

    instanceof

    • 使用格式

    变量名 instanceof 类型

    通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果

  • 代码演示

abstract class Animal {
    public abstract void eat();
}

class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void watchHome(){
        System.out.println("看家");
    }
}

class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class Test4Polymorpic {
    public static void main(String[] args) {
        useAnimal(new Dog());
        useAnimal(new Cat());
    }

    public static void useAnimal(Animal a){  // Animal a = new Dog();
                                             // Animal a = new Cat();
        a.eat();
        //a.watchHome();

//        Dog dog = (Dog) a;
//        dog.watchHome();  // ClassCastException  类型转换异常

        // 判断a变量记录的类型, 是否是Dog
        if(a instanceof Dog){
            Dog dog = (Dog) a;
            dog.watchHome();
        }
    }
}

编程狮笔记管理系统多态改进 (应用)

  • 实现步骤

    1. StudentDaoFactory类中方法的返回值定义成父类类型BaseStudentDao
    2. StudentService中接收方法返回值的类型定义成父类类型BaseStudentDao
  • 代码实现

    StudentDaoFactory类

public class StudentDaoFactory {
    public static BaseStudentDao getStudentDao(){
        return new OtherStudentDao();
    }
}

StudentService类

public class StudentService {
    // 创建StudentDao (库管)
    // private OtherStudentDao studentDao = new OtherStudentDao();

    // 通过学生库管工厂类, 获取库管对象
    private BaseStudentDao studentDao = StudentDaoFactory.getStudentDao();
}
没有了

已是最早文章

为您推荐

JavaSE基础

Java入门 Java简介 Java是一门非常优秀的计算机语言 语言:人与人交流沟通的表达方式 计算机语言:人与计算机之...
返回顶部