第16周Java学习总结--学生管理系统,面向对象进阶(static,继承,包`final`权限修饰符`代码块,抽象类,接口,多态,内部类)

这周学习了黑马116-143集的内容,内容包括:
学生管理系统,面向对象进阶

一.学生管理系统

1.业务分析

Java学习了不少东西了,是时候做个项目了

(1).创建需求文档

在这里插入图片描述
在这里插入图片描述

(2).思路分析

可以用画图工具理清一下需求,如下
在这里插入图片描述

2.代码实现

(1).所需的JavaBean类

首先,完成学生JavaBean类(快速生成空参构造,有参构造及get,set方法在idea中有快捷键alt+insert+…)

public class Student {
    private String id;
    private String name;
    private int age;
    private String address;
    public Student() {//alt+insert快捷键
    }
    public Student(String id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }
    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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

(2).所需测试类

思路:主菜单->查询,添加->删除,修改

import java.util.ArrayList;
import java.util.Scanner;
public class Test1 {
 public static void main(String[] args) {
        ArrayList<Student> list=new ArrayList<>();
       loop:while (true) {//ctrl+alt+t  //....:是给循环起名字
  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("请输入您的选择:");
            Scanner sc=new Scanner(System.in);
            String choose= sc.next();//用next容错率更高
            switch (choose){
                case "1"->addStu(list);
                case "2"-> deleteStu(list);
                case "3"-> changeStu(list);
                case "4"-> queryStu(list);
                case "5"-> {System.out.println("退出");
                              break loop;}
                //System.exit(0);}//停止虚拟机运行
                default -> System.out.println("没有这个选项");
            }
       }
    }
     public static void addStu(ArrayList<Student> list){
        Scanner sc=new Scanner(System.in);
        Student stu=new Student();//建造空的对象
         String id=null;
         while(true) {//ctrl+alt+t语句环绕!!!!!!!
             System.out.println("请输入学生id");
              id= sc.next();
             boolean flag = contain(list, id);
             if (flag) {
                 System.out.println("id已存在,请重新输入");
             } else {
                 stu.setId(id);
                 break;
             }
         }
         System.out.println("请输入学生姓名");
         String name=sc.next();
         stu.setName(name);
         System.out.println("请输入学生年龄");
         int age=sc.nextInt();
         stu.setAge(age);
         System.out.println("请输入学生家庭住址");
         String address = sc.next();
        stu.setAddress(address);
        list.add(stu);//将对象存入集合中
         System.out.println("学生信息添加成功");
     }
     public static void deleteStu(ArrayList<Student> list){
        Scanner sc=new Scanner(System.in);
         System.out.println("请输入要删除学生的id");
         String id=sc.next();
         boolean flag=contain(list,id);
         if (flag) {
             list.remove(getIndex(list,id));
             System.out.println("删除成功");
         }else{
             System.out.println("删除失败");
         }
     }
     public static void changeStu(ArrayList<Student> list){
        Scanner sc=new Scanner(System.in);
         System.out.println("请输入要修改的学生id");
         String id= sc.next();
         int index=getIndex(list,id);
         if (index==-1) {
             System.out.println("您输入的id"+id+"不存在");
         }else{
             //运行到这里说明id存在
             Student stu=list.get(index);
             System.out.println("输入修改后的名字");
             String newName=sc.next();
             stu.setName(newName);
             System.out.println("输入修改后的年龄");
             int newAge=sc.nextInt();
             stu.setAge(newAge);
             System.out.println("输入修改后的地址");
             String newAddress=sc.next();
             stu.setAddress(newAddress);
         }
     }
     public static void queryStu(ArrayList<Student> list){
        System.out.println("查询学生");
      if (list.size()==0){
          System.out.println("当前无学生信息,请添加后再查询");
      }else{
          System.out.println("id\t姓名\t年龄\t家庭住址");
          for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getId()+"\t"+list.get(i).getName()+"\t"+list.get(i).getAge()+
                      "\t"+list.get(i).getAddress());
          }
         }
     }
     //定义方法看id是否存在
     public static boolean contain(ArrayList<Student> list,String id){
        //for循环遍历集合得到各个学生对象,获取对象id,再做比较
         for (int i = 0; i < list.size(); i++) {
             Student s= list.get(i);
             String sid=s.getId();
             if(sid.equals(id)){
                 return true;
             }
         }return false;
     }
     //定义方法获取索引
     public static int getIndex(ArrayList<Student> list,String id){
         for (int i = 0; i < list.size(); i++) {
             Student stu=list.get(i);
             String sid= stu.getId();
             if (sid.equals(id)) {
                 return i;
             }
         }return -1;
     }
}

这里还有黑马升级版学生管理系统,有空单独实现○| ̄|_

二.面向对象进阶

1.static

static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量

(1).静态变量

被static修饰的成员变量,叫做静态变量

[1].特点
  • 被该类所有对象共享
  • 不属于对象,属于类(即不需要先创建对象就可以用)
  • 随着类的加载而加载,优先于对象存在
[2].调用方式
  • 类名调用(推荐)-------类名.静态变量名;
  • 对象名调用--------对象名.静态变量名;

(2).静态方法

被static修饰的成员方法,叫做静态方法

[1].特点
  • 多用在测试类和工具类
  • JavaBean类中很少用
补充:[工具类]

不同于测试类和JavaBean类,工具类是帮助我们做一些事情的,但是不描述任何事物的类
特点:1.类名见名知意2.私有化构造方法3.方法定义为静态

[2].调用方式
  • 类名调用(推荐)
  • 对象名调用
[3].注意事项
  • 静态方法中,只能访问静态
  • 非静态可以访问所有
  • 静态中没有this关键字1

2.继承

(1).概述

  • Java中提供一个extends关键字,可以让一个类和另一个类建立起继承关系

格式:

public class 子类 extends 父类{}

[1].好处

  • 可以把多个子类中重复的代码抽取到父类中,提高代码的复用性
  • 子类可以在父类的基础上增加其功能,使子类更强大

[2].什么时候用继承

当类与类之间,存在相同(共性)的内容,并 满足子类是父类中的一种,就可以考虑使用继承来优化代码

(2).特点

Java只支持单继承,不支持多继承,但支持多层继承2

Java中所有类都直接或间接继承于Object类

(3).继承体系的设计

例.
设计继承体系的设计例题
设计继承体系时不能光想,可以用画图法完成设计
如:在这里插入图片描述
结果:在这里插入图片描述
在这里插入图片描述

(4).子类能继承父类中的哪些内容?

非私有私有
构造方法不能不能
成员变量
成员方法方法能添加到虚方法表3就能否则不能

在这里插入图片描述

内存解释请看黑马P126

[1].继承中成员变量访问特点

就近原则:先在局部位置找,本类成员位置找,父类成员位置找,逐级往上

  • 如果出现了重名的成员变量怎么办?
System.out.println(name);//从局部位置开始往上找
System.out.println(this.name);//从本类成员位置开始往上找
System.out.println(super.name);//从父类成员位置开始往上找
[2].继承中成员方法访问特点

this调用:就近原则
super调用:直接找父类

在写继承中方法时,可能会用上方法重写

补充:方法重写

在继承中,子类出现了和父类中一模一样的方法声明,就称子类的这个方法是重写的方法.

应用场景:当父类中的方法,不能满足子类现在的需求时,就需要重写
注意:子类中重写的方法上面需要加上 @override

方法重写注意事项和要求:
1.子类重写的方法尽量跟父类中的方法保持一致
2.只有虚方法表里面的方法可以被重写

本质:覆盖虚方法表中的方法

在这里插入图片描述

[3].继承中构造方法的访问特点
  • 父类中的构造方法不会被子类继承
  • 子类中的构造方法默认先访问父类中的无参构造,再执行自己

原因

  • 子类在初始化的时候,可能会使用父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
  • 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化

调用方法

  • 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行
  • 如果想调用父类有参构造,必须手动写super进行调用

例.调用无参构造时
在这里插入图片描述
调用有参构造时
在这里插入图片描述

(5).this,super使用总结

  • this:理解为一个变量,表示当前方法调用者的地址值
  • super:代表父类存储空间
关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量(访问本类成员变量)this.成员方法(…)(访问本类成员方法)this.(…)(访问本类其他构造方法)
supersuper.成员变量(访问父类成员变量)super.成员方法(…)(访问父类成员方法)super.(…)(访问父类构造方法)

(6).练习

题目:带有继承结构的标准JavaBean类
在这里插入图片描述
父类

public class Employee {
    private String id;
    private String name;
    private double salary;
    public Employee() {
    }
    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
    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 double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    public void work(){
        System.out.println("员工在工作");
    }
    public void eat(){
        System.out.println("员工在吃饭");
    }
}

经理和厨师类

public class Manager extends Employee{
    private double bonus;
    public Manager() {
    }
    public Manager(String id, String name, double salary, double bonus) {
        super(id, name, salary);
        this.bonus = bonus;
    }
    public double getBonus() {
        return bonus;
    }
    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    @Override
    public void work() {
        System.out.println("管理其他人");
    }
}
   public class Cook extends Employee{
    public Cook() {
    }
    public Cook(String id, String name, double salary) {
        super(id, name, salary);
    }
    @Override
    public void work() {
        System.out.println("炒菜");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
      Manager m=new Manager("zhuzhu01","张三",18000,8000);
        System.out.println(m.getId()+","+m.getName()+","+m.getSalary()+","+m.getBonus());
        m.work();
        m.eat();
        Cook c=new Cook("zhuzhu002","李四",3000);
        System.out.println(c.getId()+","+c.getName()+","+c.getSalary());
        c.work();
        c.eat();
    }
}

结果:
zhuzhu01,张三,18000.0,8000.0
管理其他人
员工在吃饭
zhuzhu002,李四,3000.0
炒菜
员工在吃饭

3.多态

(1).概述

对象的多种形态
[1].前提

  • 有继承/实现关系
  • 有父类引用指向子类对象
  • 有方法的重写

[2].表现形式

父类类型 对象名称=子类对象;

如:Fu f=new Zi ();

(2).调用成员的特点

[1].变量调用:

编译看左边,运行也看左边

编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有就编译失败
运行看左边:Java运行代码的时候,实际获取的就是左边父类中成员变量的值

[2].方法调用:

编译看左边,运行看右边

编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有就编译失败
运行看右边:Java运行代码的时候,实际上运行的是子类

(3).多态的优势和弊端

好处:使用父类型作为参数,可以接收所有子类对象

弊端:不能使用子类的特有功能
解决办法:强制类型转换,转换时要用instanceof关键字判断

例.
在这里插入图片描述

4.包,final,权限修饰符,代码块

(1).包

包就是文件夹,用来管理各种不同功能的Java类

包名书写的规则:
公司域名反写+包的作用,需要全部英文小写,见名知意

全类名:包名+类名

什么时候需要导包?什么时候不需要导包?

  • 使用同一个包中的类时,不需要导包
  • 使用Java.lang包中的类时,不需要导包
  • 其他情况都需要导包
  • 如果同时使用两个包中的同名类,需要用全类名

(2).final

final修饰方法:最终方法,不能被重写
final修饰类:最终类,不能被继承

final修饰变量:是常量,不能被修改

  • 基本数据类型:变量的值不能修改
  • 引用数据类型:地址值不能修改,内部的属性值可以修改

(3).权限修饰符

用来控制一个成员能够被访问的范围的
可以修饰成员变量,方法,构造方法,内部类

分类
有四种作用范围由小到大(private<空着不写<protected<public)
在这里插入图片描述
使用规则
实际开发中,一般只用privatepublic

  • 成员变量私有
  • 方法公开

(4).代码块

有局部代码块,构造代码块,静态代码块.

静态代码块
格式: static{}
特点:需要static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
作用:在类加载的时候,做一数据的初始化使用

5.抽象类

  • 抽象方法:将共性的行为(方法)抽取到父类之后.由于每一个子类执行的内容是不一样的,所以在父类中不能确定具体的方法体,该方法就可以定义为抽象方法

定义格式:
public abstract 返回值类型 方法名(参数列表);

  • 抽象类:如果一个类中存在抽象方法,那么该类必须声明为抽象类

定义格式:
public abstract class 类名{}

[注意事项]

  • 抽象类不能实例化(即不能被创建对象)
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  • 可以有构造方法
  • 抽象类的子类: 要么重写抽象类中的所有抽象方法(推荐),要么是抽象类

[练习]
在这里插入图片描述
JavaBean类

public abstract class Animal {//父类
    private String name;
    private int age;
    public Animal() {
    }
    public Animal(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 drink(){
        System.out.println("动物在喝水");
    }
    public abstract void eat();//按alt+enter
}
public class Frog extends Animal {//青蛙
    public Frog() {
    }
    public Frog(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }
}
public class Dog extends Animal{//狗
    public Dog() {
    }
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }
}

测试类

public class Main {
    public static void main(String[] args) {
        Frog f=new Frog("咕呱",12);
        System.out.println(f.getName()+","+f.getAge());
        f.eat();
        f.drink();
        Dog d=new Dog("哈皮",3);
        System.out.println(d.getName()+","+d.getAge());
        d.eat();
        d.drink();
    }
}

结果:
咕呱,12
青蛙在吃虫子
动物在喝水
哈皮,3
狗在吃骨头
动物在喝水

6.接口

(1).接口的定义和使用

  • 接口用关键字interface来定义
    public interface 接口名{}

  • 接口不能实例化(即不能被创建对象)

  • 接口和类之间是实现关系,通过implements关键字表示
    public class 类名 implements 接口名{}

  • 接口的子类(实现类)
    要么重写接口中的所有抽象方法(推荐),要么是抽象类

注意1:接口和类的实现关系,可以单实现,也可以多实现.
public class 类名 implements 接口名1,接口名2{}

注意2:实现类还可以在继承一个类的同时实现多个接口
public class 类名 extends 父类 implements 接口名1,接口名2{}

以上题为例改写:
接口

public interface Swim {
    public abstract void Swim();
}

其他的一些改变

public class Dog extends Animal implements Swim{
//................
@Override
    public void Swim() {
     System.out.println("狗刨");
    }
    
public class Frog extends Animal implements Swim {
//................
@Override
    public void Swim() {
     System.out.println("蛙泳");
    }

因为兔子不能游泳,而青蛙和狗能游泳,所以不能直接用抽象方法,要用接口

(2).接口中成员的特点

  • 成员变量
    只能是常量,默认修饰符: public static final
  • 构造方法
    没有
  • 成员方法
    只能是抽象方法,默认修饰符: public abstract

(3).接口和类之间的关系(总结)

  • 类和类的关系
    继承关系,只能单继承,不能多继承,但是可以多层继承

  • 类和接口的关系
    实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口(但要重写所有方法)

  • 接口和接口的关系
    继承关系,可以单继承,也可以多继承(若实现类实现的是最下边的子接口时要重写所有方法)

(4).多学三招

[1].JDK8开始接口中新增的方法
  • JDK8:接口中可以定义有方法体的方法(默认,静态)
    ----默认
    用关键字default修饰定义默认方法
    作用:解决接口升级的问题

定义格式:public default 返回值类型 方法名(参数列表){ }

注意事项:

  • 默认方法不是抽象方法,所以不强制被重写.如果被重写,需要去掉default关键字
  • public可以省略,default不能省略
  • 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法重写

----静态
用关键字static定义静态方法

定义格式:public static 返回值类型 方法名(参数列表){ }

注意事项:

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  • public可以省略,static不能省略
  • JDK9:接口中可以定义私有方法
    分为普通的私有方法,静态的私有方法

定义格式1: private 返回值类型 方法名(参数列表){ }
定义格式2:private static 返回值类型 方法名(参数列表){ }

[2].接口的应用

1.接口代表规则,是行为的抽象,想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了
2.当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方法称之为接口多态

[3].适配器设计模式

设计模式就是各种套路
适配器设计模式:解决接口与接口实现类之间的矛盾问题

使用场景:当一个接口中抽象方法过多,但是我只要其中一部分的时候,就可以适配器设计模式

书写步骤:

  • 编写中间类XXXAdapter,实现对应的接口
  • 对接口中的抽象方法进行空实现
  • 让真正的实现类继承中间类,并重写需要用的方法
  • 为了避免其它类创建适配器类的对象,中间的适配器类用abstract进行修饰

7.内部类

类的五大成员:
属性,方法,构造方法,代码块,内部类

内部类:写在一个类里面的类就叫做内部类
使用内部类的条件:B类表示的事务是A类的一部分,且B单独存在没有意义

分类:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类(掌握)

[1].匿名内部类

本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置

格式:

new 类名或者接口名(){
重写方法;
};
在这里插入图片描述
在这里插入图片描述

细节:

包含了继承或实现,方法重写,创建对象
整体就是一个类的子类对象或者接口的实现类对象

使用场景:

当方法的参数是接口或者类时,
以接口为例,可以传递这个接口的实现类对象,
如果实现类只要使用一次,就可以用匿名内部类简化代码.

[2].成员内部类

  • 写在成员位置的,属于外部类的成员
  • 成员内部类可以被一些修饰符所修饰,如private,默认,protected,public等
  • 在成员内部类里面,JDK 16开始才可以定义静态变量
    在这里插入图片描述
    获取成员内部类对象

方式一:
在外部类中编写方法,对外提供内部类的对象

方式二:
直接创建格式:外部类名.内部类名 对象名=外部类对象.内部类对象;

外部类成员变量和内部类成员变量重名时,在内部类如何访问?

System.out.println(外部类名.this.变量名);

[3].静态内部类

成员内部类中特殊的一类,静态内部类只能访问外部类中的静态变量和方法,如果想要访问非静态的需要创建对象

创建静态内部类对象的格式:
外部类名.内部类名 对象名=new 外部类名.内部类名();

调用非静态方法的格式:
先创建对象,用对象调用

调用静态方法的格式:
外部类名.内部类名.方法名();

[4].局部内部类

  • 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
  • 外界是无法直接使用,需要在方法内部创建对象并使用
  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量

三.本周小结

这面向对象进阶的内容是真的多(´Д`)
这次博客学会了使用标记文本和注释
有点发烧,下周再见ヾ( ̄▽ ̄)ByeBye
觉得可以别忘点赞( ͡° ͜ʖ ͡°)


  1. this表示当前方法调用者的地址值 ↩︎

  2. 多层继承:子类A继承父类B,父类B可以继承父类C ↩︎

  3. 这个类中经常使用的方法会抽取出来放到虚方法表中,这种经常使用的方法需要满足非private,非static,非final ↩︎

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值