Bootstrap

面向对象高级-抽象类、接口

一、final

1、认识final关键字

final关键字是最终的意思,可以修饰:类、方法、变量。

修饰类:该类被称为最终类,特点是不能被继承了。(一般是用在工具类中)

修饰方法:该方法被称为最终方法,特点是不能被重写了。

修饰变量(局部变量、成员变量(静态、实例)):该变量有且仅能被赋值一次。(一般是修饰静态变量)

final修饰变量的注意:

final修饰基本类型(int,double,boolean,char...)的变量,变量存储的数据不能被改变。

final修饰引用类型(String,Array...)的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。

2、常量

常量:使用了static final修饰的成员变量就被称为常量。

作用:常用于记录系统的配置信息;常量都统一到常量包内(Constant),方便修改。

使用常量记录系统配置信息的优势、执行原理:

代码可读性更好,可维护性也更好。

程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能一样。

public class FinalDemo1{
    //final修饰静态成员变量
    //final修饰静态变量,这个变量今后被称为常量,可以记住一个固定值,并且程序中不能修改了,通常这个值作为系统的配置信息
    //常量的名称都要大写,使用下划线分割
    public static final double PI=3.14;
    //final修饰实例变量(一般没有意义)
    public final double rate=3.14;
    public static void main(String[] args){
        //认识final关键字的作用
        //3、final修饰变量,变量的值有且只能赋值一次
        /*
        变量有哪些呢?
        1、成员变量
        静态成员变量 实例成员变量
        2、局部变量
        */
        final double rate=3.14;
        //rate=5.14;//第二次赋值 报错
        final int a=20;
        //a=30;//不能修改
        final int[] b={1,2,3};
        b[2]=4;
    }
}

//1、fianl修饰类,类不能被继承
final class A{}
//class B extends A{}

//2、final修饰方法,方法不能被重写
class C{
    public final void show(){
        System.out.println("show()");
    }
}

class D extends C{
    //@Override
    //public void show(){
    //System.out.println("show()");
    //}
}

二、单例类(设计模式)

1、什么是设计模式:一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。(设计模式解决什么问题、怎么写)

2、单例设计模式:确保某个类只能创建一个对象。

3、单例有啥应用场景,有啥好处:任务管理器对象、获取运行时对象(有且仅需要一个对象)。在这些业务场景下,使用单例模式,可以避免浪费内存。

4、单例设计模式的写法,实现步骤:

  • 把类的构造器私有。
  • 定义一个静态变量记住类的一个对象。
  • 定义一个静态方法,返回对象。

5、饿汉式单例类:在类加载的时候就创建对象,不管用不用,都会创建。

//设计单例设计模式
public class A{
    //1、私有化构造器:确保单例类对外不能创建太多对象,单例才有可能性
    private A(){
    }
    //2、定义一个静态变量,用于记住本类的一个唯一对象
    private static A a=new A();
    //3、提供静态方法,返回A对象
    public static A getInstance(){
        return a;
    }
}

public class Test{
    public static void main(String[] args){
        //设计单例类
        A a1=A.getInstance();
        A a2=A.getInstance();
        System.out.println(a1==a2);
    }
}

6、懒汉式单例类:在类加载的时候不会创建对象,只有当调用getInstance()方法时才会创建对象(延迟加载对象)。

写法:

  • 把类的构造器私有。
  • 定义一个静态变量用于存储对象。
  • 提供一个静态方法,保证返回的是同一个对象。
//懒汉式单例类
public class B{
    //1、私有化构造器
    private B(){
    }
    //2、创建一个静态的私有的B对象
    private static B instance;
    //3、提供一个静态的公共方法,返回B对象,真正需要对象的时候才开始创建对象
    public static B getInstance(){
        if(instance==null)
            {
                //第一次拿对象时,会创建对象,给静态变量instance记住
                instance=new B();
            }
        return instance;
    }
}

public class Test{
    public static void main(String[] args){
        B b1=B.getInstance();
        B b2=B.getInstance();
        System.out.println(b1==b2);
    }
}

三、枚举类

1、认识枚举类

枚举是一种特殊类。

枚举类的写法:修饰符 enum 枚举类名{名称1,名称2,其他成员;....}

特点:

  • 枚举类中的第一行,只能写枚举类的对象名称,且要用逗号隔开。
  • 这些名称,本质是常量,每个常量都记住了枚举类的一个对象。

枚举类的特点:

  • 枚举都是最终类,不可以被继承,枚举类都是继承java.lang.Enum类的。
  • 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量会记住枚举类的一个对象。
  • 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
  • 编译器为枚举类新增了几个方法。
//枚举类
public enum A{
    //枚举类的第一行,只能罗列枚举对象的名称,这些名称本质是常量
    X,Y,Z;
}

public class Test{
    public static void main(String[] args){
        //认识枚举类,搞清楚其本质特点
        A a=A.X;
        System.out.println(a);
        
        A b=A.Y;
        System.out.println(b);
    
        System.out.println(a.name());//X
        System.out.println(b.name());//Y
        System.out.println(a.ordinal());//索引0
        System.out.println(b.ordinal());//索引1
    }
}

2、枚举类的常见应用场景

枚举类很适合做信息分类和标志。

(枚举类常用于定义常量,枚举类中的常量只能是枚举类的实例,不能被修改。)

虽说也可以用常量类作为信息的标志与分类,但是参数值不受约束(就是传入的参数不是限定内的那四个都能行得通,写别的不报错),但是枚举类的话写限定外的就会报错。

public enum Direction{
    UP,DOWM,LEFT,RIGHT;
}

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 Test2{
    public static void main(String[] args){
        //掌握枚举类的应用场景:做信息的分类和标志
        //需求:模拟上下左右移动图片
        //第一种是常量做信息标志和分类,但参数值不受约束
        move(Constant.UP);
        //第二种是枚举做信息标志和分类,参数值受枚举类约束
        move2(Constant.RIGHT);
    }

    public static void move2(Direction direction)
    {
        //根据这个方向做移动:上下左右
        switch (direction)
        {
            case Direction.UP:
                System.out.println("向上移动");
                break;
            case Direction.DOWN:
                System.out.println("向下移动");
                break;
            case Direction.LEFT:
                System.out.println("向左移动");
                break;
            case Direction.RIGHT:
                System.out.println("向右移动");
                break;
            default:
                System.out.println("输入有误");
        }
    }


    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("输入有误");
        }
    }
}

四、抽象类

1、认识抽象类

在java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。

abstract修饰类,这个类就是抽象类。

abstract修饰方法,这个方法就是抽象方法。

抽象类的注意事项、特点:

  • 抽象类中不一定要有抽象方法,有抽象方法的类必须是抽象类。
  • 类有的成员:成员变量、方法、构造器,抽象类都可以有。
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义为抽象类。
//抽象类
public abstract class A {
    private String name;
    private int age;

    public A(){
        System.out.println("A的无参构造器");
    }

    public A(String name,int age){
        this.name=name;
        this.age=age;
    }

    //抽象方法:必须用abstract修饰,没有方法体,只有方法声明
    public abstract void show();

    public void show1(){
        System.out.println("show1方法");
    }

    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 class B extends A{
    @Override
    public void show() {
        System.out.println("B类重写show方法");
    }
}

public class abstractdemo1 {
    public static void main(String[] args)
    {
        //认识抽象类,抽象方法,搞清它们的特点
        //抽象类的核心特点:有的有失(得到了抽象方法的能力,失去了创建对象的能力
        //抽象类不能创建对象
        //A a = new A();//报错了
        //抽象类的使命就是被子类继承
        B b = new B();
        b.setName("jack");
        b.setAge(20);
        b.show();
        b.show1();
    }
}

2、使用抽象类的好处

父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好的支持多态。

抽象类简化了需要重写的父类方法的代码,更加便于调用子类时多态的实现,更具解耦性。

public abstract class Animal {
    //每个动物的叫声
    public abstract void cry();
}

public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("猫是喵喵喵的叫");
    }
}

public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("狗是汪汪汪的叫");
    }
}

public class Test {
    public static void main(String[] args)
    {
        //搞清楚使用抽象类的好处
        Animal a = new Cat();
        a.cry();
    }
}

3、模板方法设计模式

提供一个方法作为完成某类功能的模板,模板方法封装了每个实现步骤,但允许子类提供特定步骤的实现。

模板方法设计模式可以:提高代码的复用、并简化子类设计。

写法:

1、定义一个抽象类。

2、在里面定义2个方法。

        一个是模板方法:把共同的实现步骤放里面去。

        一个是抽象方法:不确定的实现步骤,交给具体的子类来完成。

建议使用final关键字修饰模板方法,为什么?

  • 模板方法是给子类直接使用的,不能被子类重写。
  • 一旦子类重写了模板方法,模板方法就失效了。
public abstract class People {
    //模板方法设计模式
    public final void write(){
        System.out.println("\t\t\t《我的爸爸》");
        System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下");
        //模板方法知道子类一定要写正文,但是每个子类写的信息是不同的,父类定义一个抽象方法
        //具体的实现交给子类来重写正文
        writeBody();
        System.out.println("\t我爸爸真好,你有这样的爸爸吗?");
    }

    public abstract void writeBody();
}

public class Student extends People{
    @Override
    public void writeBody() {
        System.out.println("\t我爸爸很牛逼");
    }
//    public void write(){
//        System.out.println("\t\t\t《我的爸爸》");
//        System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下");
//        System.out.println("\t我爸爸很牛逼");
//        System.out.println("\t我爸爸真好,你有这样的爸爸吗?");
//    }
}

public class Teacher extends People{
    @Override
    public void writeBody() {
        System.out.println("\t我爸爸给我买橘子");
    }
//    public void write(){
//        System.out.println("\t\t\t《我的爸爸》");
//        System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下");
//        System.out.println("\t我爸爸给我买橘子");
//        System.out.println("\t我爸爸真好,你有这样的爸爸吗?");
//    }
}

public class Test {
    public static void main(String[] args)
    {
        //理解抽象类的使用场景之一:模板方法设计模式
        //学生和老师都要写一篇作文:《我的爸爸》
        //第一段是一样的:我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下
        //第二段是不一样的:老师和学生各自写各自的
        //第三段是一样的:我爸爸真好,你有这样的爸爸吗?
        //解决:抽出一个父类,父类中还抽取一个模板方法给子类直接用
        Student s=new Student();
        s.write();
    }
}

五、接口

1、接口概述

Java提供了一个关键字interface定义出接口。

接口不能创建对象。

接口是用来被类实现(implements)的,实现接口的类称为实现类,一个类可以同时实现多个接口。

//接口:使用interface关键字定义
public interface A {
    //JDK 8之前,接口中只能定义常量和抽象方法
    //常量:接口中定义常量可以省略public static final不写,默认会加
    String SCHOOL_NAME="黑马程序员";

    //抽象方法:接口中定义抽象方法可以省略public abstract不写,默认会加
    void show();
    String go();
}

public interface B {
    void play();
}

public class Test {
    public static void main(String[] args)
    {
        //认识接口,搞清楚接口的特点,基本使用
        System.out.println(A.SCHOOL_NAME);
        //接口不能创建对象
        //接口是用来被类实现的
        C c = new C();
        c.show();
        System.out.println(c.go());
        c.play();
    }
}

//C被称为实现类,同时实现了多个接口
//实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须定义成抽象类
class C implements A,B{

    @Override
    public void show() {
        System.out.println("C show");
    }

    @Override
    public String go() {
        return "黑马程序员";
    }

    @Override
    public void play() {
        System.out.println("C play");
    }
}

2、接口的好处

弥补了类单继承的不足,一个类可以实现多个接口,使类的角色更多,功能更强大。

让程序可以面向接口编程,更利于程序的解耦合。

public class Test {
    public static void main(String[] args)
    {
        //理解Java设计接口的好处、用处
        //接口弥补了类单继承的不足,可以让类拥有更多角色,类的功能更强大
        People p = new Student();
        Driver d = new Student();//多态
        BoyFriend bf = new Student();

        //接口可以实现面向接口编程,更利于解耦合
        Driver a = new Teacher();
    }
}

interface Driver{}
interface BoyFriend{}

class People{}
class Student extends People implements Driver, BoyFriend{}

class Teacher implements Driver, BoyFriend{}

3、接口的综合小案例

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private String name;
    private char sex;
    private double score;
}

public interface ClassDataInter {
    void printAllStudentInfos();
    void printAverageScore();
}

public class ClassDataInterImpl1 implements ClassDataInter{
    private Student[] students;//记住送来的全班学生对象信息
    public ClassDataInterImpl1(Student[] students) {
        this.students = students;
    }
    @Override
    public void printAllStudentInfos() {
        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() {
        double sum=0;
        for (int i = 0; i < students.length; i++) {
            sum+=students[i].getScore();
        }
        System.out.println("全班平均成绩为:"+sum/students.length);
    }
}

//定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)
public class ClassDataInterImpl2 implements ClassDataInter{
    private Student[] students;//记住送来的全班学生对象信息
    public ClassDataInterImpl2(Student[] students)
    {
        this.students=students;
    }
    @Override
    public void printAllStudentInfos() {
        int maleCount=0;
        System.out.println("全班学生信息如下:");
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i].getName()+" "+students[i].getSex()+" "+students[i].getScore());
            if(students[i].getSex()=='男')
                maleCount++;
        }
        System.out.println("男学生人数为:"+maleCount);
        System.out.println("女学生人数为:"+(students.length-maleCount));
    }

    @Override
    public void printAverageScore() {
        double max=students[0].getScore();
        double min=students[0].getScore();
        double 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("最高分是:"+max);
        System.out.println("最低分是:"+min);
        System.out.println("全班平均成绩为:"+(sum-max-min)/(students.length-2));
    }
}

public class Test {
    public static void main(String[] args)
    {
        //完成接口的小案例
        //1、定义学生类,创建学生对象,封装学生数据,才能交给别人处理
        //2、准备学生数据,目前我们自己造一些测试数据
        Student[] allstudents=new Student[10];
        allstudents[0]=new Student("张三",'男',90);
        allstudents[1]=new Student("李四",'女',80);
        allstudents[2]=new Student("王五",'男',70);
        allstudents[3]=new Student("赵六",'女',60);
        allstudents[4]=new Student("钱七",'男',50);
        allstudents[5]=new Student("孙八",'女',40);
        allstudents[6]=new Student("周九",'男',30);
        allstudents[7]=new Student("吴十",'女',20);
        allstudents[8]=new Student("郑十一",'男',10);
        allstudents[9]=new Student("王十二",'女',0);
        //3、提供两套业务实现方案,支持灵活切换(解耦合):面向接口编程
        //定义一个接口(规范思想):必须完成打印全班学生信息,打印平均分
        //定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分
        //定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)
        ClassDataInter cdi=new ClassDataInterImpl2(allstudents);
        cdi.printAllStudentInfos();
        cdi.printAverageScore();
    }
}

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

默认方法:使用default修饰,使用实现类的对象调用。

静态方法:static修饰,必须用当前接口名调用。

私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。

他们都会默认被public修饰。

新增的方法增强接口能力,便于项目扩展与维护(若新增方法,可以直接写在接口中,不用修改实现类,更方便扩展)。

public interface A {
    //1、默认方法(普通实例方法):必须加default修饰
    //默认用public修饰
    //如何调用? 使用接口的实现类的对象来调用
    default void go(){
        System.out.println("go方法执行了");
        run();
    }

    //2、私有方法
    //私有的实例方法
    //如何调用? 使用接口中的其他实例方法来调用它
    private void run(){
        System.out.println("run方法执行了");
    }

    //3、静态方法
    //默认会用public修饰
    //如何调用? 只能使用当前接口名来调用
    static void show(){
        System.out.println("show方法执行了");
    }
}

public class Test {
    public static void main(String[] args)
    {
        //搞清楚接口新增的三种方法,并理解其好处
        AImpl a = new AImpl();
        a.go();

        A.show();
    }
}

class AImpl implements A{

}

5、接口的注意事项

1、接口与接口可以多继承:一个接口可以同时继承多个接口。

类与类:单继承,一个类只能有一个父类。

类与接口:多继承,一个类可以同时实现多个接口。

2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。

3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的默认方法,实现类会优先用父类的。

4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

public class Test {
    public static void main(String[] args)
    {
        //理解接口的几点注意事项
        Dog dog = new Dog();
        dog.go();

        C3 c3 = new C3();
        c3.show();
    }
}

//4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
interface A3{
    default void show(){
        System.out.println("接口A3的show方法");
    }
}

interface B3{
    default void show(){
        System.out.println("接口B3的show方法");
    }
}

class C3 implements A3,B3{

    @Override
    public void show() {
        A3.super.show();
        B3.super.show();
    }
}

//3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的
interface A2{
    default void show(){
        System.out.println("接口的show方法");
    }
}

class Animal{
    public void show(){
        System.out.println("父类的show方法");
    }
}

class Dog extends Animal implements A2{
    public void go(){
        show();//父类的
        super.show();//父类的
        A2.super.show();//接口的
    }
}

//2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现
interface A1{
    void show();
}
interface B1{
    String show();
}
//interface C1 extends A1,B1{
//
//}
//class D1 implements A1,B1{
//
//}

//1、接口与接口可以多继承:一个接口可以同时继承多个接口
//类与类:单继承 一个类只能继承一个直接父类
//类与接口:多实现 一个类可以同时实现多个接口
//接口与接口:多继承 一个接口可以同时继承多个接口
interface A{
    void show1();
}

interface B{
    void show2();
}

interface C extends A,B{
    void show3();
}

class D implements C{
    public void show1()
    {

    }

    public void show2()
    {

    }

    public void show3()
    {

    }
}

6、抽象类、接口的区别对比

相同点:

1、都是抽象形式,都可以有抽象方法,都不能创建对象。

2、都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现。

3、一个类继承抽象类,或者实现接口,都必须重写完它们的抽象方法,否则自己要成为抽象类或者报错。

4、都能支持多态,都能实现解耦合。

不同点:

1、抽象类中可以定义类的全部普通成员,接口只能定义常量,抽象方法(JDK8新增的三种方式)。

2、抽象类只能被类单继承,接口可以被类多实现。

3、一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)。

4、抽象类体现模板思想:更利于作父类,实现代码的复用性。

5、接口更适合做功能的解耦合:解耦合性更强更灵活。

六、综合案例

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

public interface Switch {
    void press();//按压
}

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//家电
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JD implements Switch{
    private String name;
    //状态:开或者关
    private boolean status;//false默认是关闭

    @Override
    public void press() {
        //控制当前设备开和关
        status = !status;
    }
}

//电视机
public class TV extends JD{
    public TV(String name, boolean status) {
        super(name, status);
    }
}

//洗衣机
public class WashMachine extends JD{
    public WashMachine(String name, boolean status) {
        super(name, status);
    }
}

//空调
public class Air extends JD{
    public Air(String name, boolean status) {
        super(name, status);
    }
}

//灯
public class Lamp extends JD{
    public Lamp(String name, boolean status) {
        super(name, status);
    }
}

//智能控制系统 单例类
public class SmartHome {
    private static final SmartHome sh=new SmartHome();
    private SmartHome()
    {

    }
    public static SmartHome getInstance()
    {
        return sh;
    }
    //多态
    public void control(JD jd)
    {
        System.out.println(jd.getName()+"状态目前是:"+(jd.isStatus()?"开":"关"));
        System.out.println("开始您的操作");
        jd.press();//按下开关
        System.out.println(jd.getName()+"状态目前是:"+(jd.isStatus()?"开":"关"));
    }
    public void printAllStatus(JD[] jds)
    {
        for(int i=0;i<jds.length;i++)
        {
            System.out.println(jds[i].getName()+"状态目前是:"+(jds[i].isStatus()?"开":"关"));
        }
    }
}

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        //目标:面向对象编程实现智能家具控制系统
        //角色:设备(吊灯,电视机,洗衣机,落地窗,。。。)
        //具备的功能:开和关
        //谁控制他们:智能控制系统(单例对象),控制调用设备的开和关
        //1、定义设备类:创建设备对象代表家里的设备
        //2、准备这些设备对象,放到数组中,代表整个家庭的设备
        JD[] jds = new JD[4];
        jds[0] = new Lamp("吊灯",true);
        jds[1] = new TV("小米电视机",true);
        jds[2] = new WashMachine("美的洗衣机",false);
        jds[3] = new Air("美的空调",false);
        //3、为每个设备制定一个开和关的功能
        //4、创建智能控制系统对象,控制设备开和关
        SmartHome sh = SmartHome.getInstance();
        //5、控制吊灯
        //sh.control(jds[0]);
        //6、提示用户操作 a、展示全部设备的当前情况 b、让用户选择哪一个操作
        //打印全部设备的开和关的现状
        while (true) {
            sh.printAllStatus(jds);
            System.out.println("请选择要控制的设备");
            Scanner sc = new Scanner(System.in);
            String choice = sc.next();
            switch (choice){
                case "1":
                    sh.control(jds[0]);
                    break;
                case "2":
                    sh.control(jds[1]);
                    break;
                case "3":
                    sh.control(jds[2]);
                    break;
                case "4":
                    sh.control(jds[3]);
                    break;
                case "exit":
                    System.out.println("退出程序");
                    return;
                default:
                    System.out.println("输入有误");
            }
        }
    }
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;