第八章 面向对象高级(final-单例类-枚举类-抽象类-接口)

final

在这里插入图片描述

/**
 * 变量分类:
 * 1、成员变量
 *    成员变量分为两种: 静态成员变量、实例成员变量
 *     1)静态成员变量:static修饰的成员变量,也叫类变量,也叫静态变量
 *     2)实例成员变量:非static修饰的成员变量,也叫实例变量,也叫普通变量
  * 2、局部变量
 * **/
public class Test {
    // 4、final修饰静态成员变量,变量的值不能被改变
    public static final String  name = "xxx";
     // name = "mmm";  // 错误,final修饰的变量,值不能被改变
    //5、final修饰实例成员变量,变量的值不能被改变
    public final int phone = 1698936544;
    //phone = 123456; // 错误,final修饰的变量,值不能被改变
        public static void main(String[] args) {
        //3、final修饰实例成员变量,变量的值不能被改变
        final int age = 10;
        //age = 20  // 错误,final修饰的变量,值不能被改变
    }

    // 3、final修饰局部变量
    public static void  buy(final double z){
        // z = 2 // 错误,final修饰的变量,值不能被改变
    }
}
// 1、final 修饰类,类不能被继承
final class Person{
}
class Student{
    //2、 final修饰方法,方法不能被重写
    public final void study(){
    }
}

常量

在这里插入图片描述

在这里插入图片描述

单例类

1、什么是设计模式?

在这里插入图片描述

2、单例设计模式

单例类的作用: new一个对象的时候会导致把里面不想要的所有方法和属性都new出来,占用内存,把它设计成单例类就可以避免内存被占用的问题

2.1 饿汉式单例

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

2.2 懒汉式单例

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

枚举类

1、认识枚举类

在这里插入图片描述

2、枚举类的特点

在这里插入图片描述

//用枚举类写一个单例类
public enum A{
   X;
}

3、枚举类的应用场景

3.1 应用

在这里插入图片描述
以下为使用常量和使用枚举类完成信息标志和分类的对比,体现枚举类的优势

 // 需求:模拟上下左右移动图片
// 使用常量实现上面案例
// 常量类
public class Constant {
   public static  final int  UP = 0;
   public static  final int  DOWN = 1;
   public static  final int  LEFT = 2;
   public static  final int  RIGHT = 3;
}
// 应用
public class Application {
   public static void main(String[] args) {
        // 用常量做信息标志和分类,缺点是参数值不受约束
       // 调用方法
       move(Constant.UP);//这里会被随意修改也不会报错,如move(5)
   }
   public static void move(int direction) {
       switch (direction) {
           case Constant.UP:
               System.out.println("向上移动");
               break;
           case Constant.DOWN:
               System.out.println("向下移动");
               break;
           case Constant.LEFT:
               System.out.println("向左移动");
               break;
           case Constant.RIGHT:
               System.out.println("向右移动");
               break;
           default:
               System.out.println("无效的移动方向");
       }
   }
}
// 使用枚举类实现
// 定义枚举B
public enum B {
   // 枚举类的第一行,只能罗列枚举对象名称
   UP, DOWN, LEFT, RIGHT;

}
// 应用
public class Application {
   public static void main(String[] args) {
       // 需求:模拟上下左右移动图片
       // 用枚举做信息标志和分类,参数值受枚举类约束
       // 调用方法
       move(B.UP);//这里会被随意修改也不会报错,如move(5)

   }
   public static void move(B direction) { 
       switch (direction) {
           case UP:
               System.out.println("向上移动");
               break;
           case DOWN:
               System.out.println("向下移动");
               break;
           case LEFT:
               System.out.println("向左移动");
               break;
           case RIGHT:
               System.out.println("向右移动");
               break;
           default:
               System.out.println("无效的移动方向");
       }
   }
}

抽象类

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

在这里插入图片描述

抽象类的好处

在这里插入图片描述

父类的抽象方法必须在子类全部重写,重写的方法在父类只需要一行代码定义,更优雅简洁
在这里插入图片描述

模板方法设计模式

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

案例如下:
在这里插入图片描述

//定义了一个父类抽象类Person
public   abstract  class Person {
       public void write()
       {
           System.out.println("今天天气真好,花儿都开了");
            travel();//调用抽象方法
           System.out.println("这么好的天气,不出去喝一杯咖啡吗");
       }
       public abstract void travel(); // 定义抽象方法
}
//定义了子类Student
public class Student extends Person {
    // 重写了父类抽象方法
    @Override
    public void travel() {
        System.out.println("小鸟也在唱歌,太阳也出来了");
    }
}
// 定义了子类Teacher
public class Teacher extends Person {
    // 重写了父类抽象方法
    @Override
    public void travel() {
        System.out.println("老师们都要约好一起出去玩儿了");
    }
}
// 应用
public class Test {
    public static void main(String[] args) {
  /**
   * 需求:老师和学生分别写一篇作文,老师的第一段作文和学生的第一段相同,
   * 老师的最后一段和学生的最后一段相同,其他的内容都不同
   * **/
    Teacher teacher = new Teacher();
    teacher.write();

    Student student = new Student();
    student.write();
    }
}

接口

1、认识接口(传统接口,JDK8以前的版本)

在这里插入图片描述

// 定义一个A接口
public interface A {
    // 接口中定义常量public static final可以省略
    // public static final int  UP = 0;
    int  UP = 0;
    // 接口中定义抽象方法public abstract void move()中,public abstract可以省略
    // public abstract void move();
    void move();
}
//定义一个B接口
public interface B {
    String name = "B";
    void run();
}
//定义一个Studnt类,继承A,B接口,student类又被称为实现类
/**
 * Student类被成为实现类
 * 1、实现类Student,实现多个接口,必须重写全部接口的抽象方法,否则这个类必须定义成抽象类
 * **/
public class Student implements A,B{
    @Override
    public void move() {
        System.out.println("student move");
       }
    @Override
    public void run() {
        System.out.println("student run");
    }
}
// 应用
public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.move();
    }
}

2、接口的好处

2.1 为什么要用接口?
因为Java类是单继承的,为了弥补类单继承的缺陷,让一个类在继承了一个父类的同时角色更多,功能更强大,因此用到了接口

// 有接口A,B,以及父类Person,那么子类Student继承父类且实现A,B接口的写法如下
// student不仅继承Person,还成为了A,B接口的实现类
 **public class Student extends Person implements A,B { 
 }**
 // 实现类:Teacher类
 public class Teacher implements A,B{
    }
 // 应用
 public class Test {
  public static void main(String[] args) {
      // 引用类型, 多态性
      Person p = new Student();
      A a = new Student();
      B b = new Student();
  // 接口可以实现面向对象编程,更利于解耦
      A  aTeacher = new Student();  // 右边的可以以是Teacher
      B  bTeacher = new Teacher();// 右边的可以以是Student
  }
}

2.2 接口练习
需求:

// Student类
public class Student {
    private String name;
    private String sex;
    private int score;
    public Student() {
    }
    public Student(String name, String sex, int score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
}
// 定义一个接口A
public interface A {
       void printStudentMsg();
       void printAverageScore();
}
// 实现类 imp1
public class imp1 extends Student implements A{
    // 定义一个私有引用类型变量存放多个学生数据
     private Student[] students;
    // 有参构造器,将传递过来的数据赋值给students
    public imp1(Student[] students) {
        this.students = students;
    }
    @Override
    public void printStudentMsg() {
        System.out.println("学生信息如下:");
        for (int i = 0; i < students.length; i++) {
            System.out.println("姓名:" + students[i].getName() + ",性别:" + students[i].getSex() + ",成绩:" + students[i].getScore());
        }
    }
    @Override
    public void printAverageScore() {
        // 定义一个变量,用于记录学生成绩的总和
        int sum = 0;
        for (int i = 0; i < students.length; i++) {
            sum += students[i].getScore();
        }
        System.out.println("平均成绩为:"+ sum / students.length);
    }
}
// 实现类 imp2
package com.oop.example3;

public class imp2 extends Student implements A{
    // 定义一个私有引用类型变量存放多个学生数据
    private Student[] students;
    // 有参构造器,将传递过来的数据赋值给students
    public imp2(Student[] students) {
        this.students = students;
    }

    @Override
    public void printStudentMsg() {
        // 打印学生信息,并计算出男生多少个,女士多少个
        System.out.println("学生信息如下:");
        int male = 0;
        int female = 0;
        for (int i = 0; i < students.length; i++) {
            System.out.println("姓名:" + students[i].getName() + ",性别:" + students[i].getSex() + ",成绩:" + students[i].getScore());
            if (students[i].getSex().equals("男")) {
                male++;
            } else {
                female++;
            }
        }
        System.out.println("男生:" + male + ",女士:" + female);

    }

    @Override
    public void printAverageScore() {
        // 去掉一个最高分,一个最低分,并计算平均成绩
        int max = students[0].getScore();
        int min = students[0].getScore();
        int sum = 0;
        for (int i = 0; i < students.length; i++) {
            if (students[i].getScore() > max) {
                max = students[i].getScore();
            }
            if (students[i].getScore() < min) {
                min = students[i].getScore();
            }
            sum += students[i].getScore();
        }
        System.out.println("去掉一个最高分一个最低分平均成绩为:" + (sum - max - min) / (students.length - 2));

    }
}
// 应用

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

        Student[]  allstudents = new Student[10];
        allstudents[0] = new Student("小明", "男", 100);
        allstudents[1] = new Student("小红", "女", 90);
        allstudents[2] = new Student("小刚", "男", 80);
        allstudents[3] = new Student("小花", "女", 70);
        allstudents[4] = new Student("小李", "男", 95);
        allstudents[5] = new Student("小赵", "男", 78);
        allstudents[6] = new Student("小钱", "女", 90);
        allstudents[7] = new Student("小孙", "男", 80);
        allstudents[8] = new Student("李四", "男", 80);
        allstudents[9] = new Student("王二", "男", 60);

        // new一个实现类imp1,指向接口A
        A imp1 = new imp2(allstudents ); // 父类引用指向子类对象,并传递参数allstudents
        imp1.printStudentMsg();
        imp1.printAverageScore();
    }
}

在这里插入图片描述

3、JDK8开始,接口新增的3种方法

3.1、默认方法(实例方法):使用default修饰,默认加public修饰。
3.2、**私有方法:**必须用private修饰(JDK 9才开始支持)
3.3、类方法(静态方法):使用static修饰,默认会被加上public修饰,只能用接口名来调用
在这里插入图片描述
在这里插入图片描述
3.4、接口注意事项
1、接口与接口可以多继承:一个接口可以同时继承多个接口

         /**
        * 类与类:单继承,一个雷只能继承一个直接父类
        * 类与接口:多实现,一个类可以同时实现多个接口
        * 接口与接口:多继承,一个接口可以同时继承多个接口
       **/
interface A{
   void a();
}
interface B{
   void b();
}
interface C extends A,B{
   void c();
}
class D implements C{
   @Override
   public void a() {
   }
   @Override
   public void b() {
   }
   @Override
   public void c() {
   }
}

2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。
不冲突:A1和B1虽然都有show方法,但返回类型都是相同的void,因此不会冲突在这里插入图片描述
冲突:方法签名冲突,A1和B1都有show方法,但是返回类型不一致导致冲突,如果将A1的show返回值类型改为String,或者将B1的返回值类型改为void类型就不会冲突
在这里插入图片描述

3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。
在这里插入图片描述
4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
在这里插入图片描述

抽象类和接口的区别

在这里插入图片描述

综合案例

需求:某智能家居系统,可以让用户选择要控制的家用设备(吊灯,电视机,洗衣机),并可以对它们进行打开或者关闭操作

// 目标:面向对象编程实现智能家居控制系统。
// 角色:设备(吊灯,电视机,洗衣机)
// 具备的功能:开和关。
// 谁控制他们:智能控制系统(单例对象),控制调用设备的开和关
// 1、设计接口Switch ,功能是控制开和关
public interface Switch {
    void  press();
}
// 2、设计一个家电父类JD,并实现Switch 接口
public class JD implements Switch {
      private   String name;
      private   Boolean  status;
      public JD() {
      }
    public JD(String name, Boolean status) {
        this.name = name;
        this.status = status;
    }

    public String getName() {
        return name;
    }

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

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }
    @Override
    public void press() {
        status = !status;

    }
}
// 3、创建TV,Lamp,WashMachine子类,继承JD类。
// 只写了TV类,其他类都相同写法
public class TV extends JD{
    public TV(String name, Boolean status) {
        super(name, status);
    }
}
// 4、创建智能控制系统(单例对象),控制调用设备的开和关
public class SmartHomeCtrol {
    //智能控制系统类,设计成单例类 start
    private static final SmartHomeCtrol smartHomeCtrol= new SmartHomeCtrol();
    private SmartHomeCtrol(){}
    public static SmartHomeCtrol getInstance(){
        return  smartHomeCtrol;
    }
   //智能控制系统类,设计成单例类end
   // 控制开关调用方法
 public void control(JD jd){
     //打印家电目前状态
     System.out.println(jd.getName() + "状态目前是:" + (jd.getStatus()?"开着":"关着"));
     System.out.println("请开始你的操作。。。");
     jd.press();
     System.out.println(jd.getName() + "操作后的状态是:" + (jd.getStatus()?"开着":"关着"));

 }
 public  void printAllStatus(JD[] jds){
     // 用for循环,索引的方法打印所有的家电状态
     for(int i=0;i<jds.length;i++){
         JD  jd = jds[i];
         System.out.println((i+1)+"-"+jd.getName() + "状态目前是:" + (jd.getStatus()?"开着":"关着"));
     }
 }

}
// 应用

import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        JD[] jds = new JD[3];
         jds[0] = new TV("TCL电视",true);
         jds[1] = new WashMachine("美的洗衣机",false);
         jds[2] = new Lamp("雷士灯泡",true);
         // 创建一个对象,控制开关
        SmartHomeCtrol s = SmartHomeCtrol.getInstance(); // 调用单列类的方法,得到唯一的一个对象
//        s.control(jds[0]);
        while (true) {
            s.printAllStatus(jds);
            // 让用户输入数字,根据数字控制开关
            System.out.println("请输入数字:");
            Scanner sc = new Scanner(System.in);
            String num = sc.next();
            switch (num) {
                case "1":
                    s.control(jds[0]);
                    break;
                case "2":
                    s.control(jds[1]);
                    break;
                case "3":
                    s.control(jds[2]);
                    break;
                case "exit":
                    System.out.println("退出APP");
                    return;
                default:
                    System.out.println("输入错误");
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值