当前位置: 首页 > article >正文

面向对象高级(1)

文章目录

  • final
    • 认识final关键字
      • 修饰类:
      • 修饰方法:
      • 修饰变量
      • final修饰变量的注意事项
    • 常量
  • 单例类
    • 什么是设计模式?
    • 单例怎么写?
    • 饿汉式单例的特点是什么?
    • 单例有啥应用场景,有啥好处?
    • 懒汉式单例类。
  • 枚举类
    • 认识枚举类
    • 枚举类的常见应用场景
  • 抽象类
    • 认识抽象类
    • 使用抽象类的好处
    • 模板方法设计模式
  • 接口
    • 什么是接口
    • 接口语法
    • 接口如何实现
    • 接口的好处
    • 接口的综合小案例
      • 需求
      • 分析
      • 代码
    • JDK8新增的三种方法
    • 接口的注意事项
      • 1
      • 2
      • 3
      • 4
  • 抽象类和接口的区别
  • 案例

final、单例类、枚举类、抽象类、接口

final

认识final关键字

final 关键字是最终的意思,可以修饰:类、方法、变量。
修饰类:该类被称为最终类,特点是不能被继承了。应用场景:工具类,不需要被继承。
修饰方法:该方法被称为最终方法,特点是不能被重写了。应用场景:在抽象类会讲。
修饰变量:该变量有且仅能被赋值一次。应用场景:局部变量修饰一些固定的值,比如圆周率。
成员变量,比如作为系统的配置信息。给实例变量加无意义。

修饰类:

public class FinalDemo1 {public static void main(String[] args) { }
}
// 1、final修饰类,类不能被继承。
final class A{
}
// class B extends A{} // 报错
// 应用场景 : 工具类不需要继承,所以加final
// 在比如java的内置math方法是个工具类。查看Ctrl+点击math 查看源码
// 你会发现math类使用了final:  public final class Math{...}
public final class XxxxUtil {public static void xxx(){   ......  }public static boolean xxxx(String email){  ... }  public static String xxxxx(int n){  ... }...
}

修饰方法:

public class FinalDemo1 {public static void main(String[] args) { }
}//  final修饰方法,方法不能被重写。应用场景会在抽象类中讲。
class C{public final void show(){System.out.println("show方法被执行");}
}
class D extends C{
//     @Override
//     public void show(){
//         System.out.println("show方法被执行");
//     }
}

修饰变量

我们知道变量分为很多种

  1. 成员变量:
    • 静态成员变量
    • 实例成员变量
  2. 局部变量
    下面对每种变量都加一个final修饰。
public class FinalDemo1 {public static void main(String[] args) {// final修饰变量:变量有且仅能被赋值一次。// 修饰局部变量final double rate = 3.14;// rate = 3.16; // 第二次赋值,报错。// 局部变量应用// 比如这里打八折buy(0.8);}public static void buy(final double z){// z = 0.1;  // 第二次赋值,报错。System.out.println(z);}
}public class FinalDemo1 {// final修饰静态成员变量// final修饰静态变量,这个变量今后被称为常量,// 常量可以记住一个固定值,并且程序中不能修改了,// 应用场景: 通常这个值作为系统的配置信息。// 常量的名称,建议全部大写,多个单词用下划线链接public static final String SCHOOL_NAME = "黑马程序员";public static void main(String[] args) { }
}public class FinalDemo1 {// final修饰实例变量(一般没有意义)private final String name = "猪刚鬣";public static void main(String[] args) {FinalDemo1 f = new FinalDemo1();System.out.println(f.name);// f.name = "高翠兰"; // 第二次赋值,报错。}
}

final修饰变量的注意事项

final修饰基本类型的变量,变量存储的数据不能被改变。
final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。

public class FinalDemo1 {public static void main(String[] args) {final int a = 20;// a = 30; // 第二次赋值,报错。final int[] arr = {11, 22, 33, 44};// arr = new int[]{33, 55, 44}; // 第二次赋值,报错。修改地址arr[2] = 90;// 不报错没有修改地址}
}

常量

使用了 static final 修饰的成员变量就被称为常量(上节已经讲过).
作用:常用于记录系统的配置信息。

public class Constant {public static final String SCHOOL_NAME  = “传智教育";
} 

注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。

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

代码可读性更好,可维护性也更好。
程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
运行下面代码,在out文件夹下查看编译后的代码。

public class Constant {public static final String SYSTEM_NAME = "黑马程序员智能家居AI系统";
}
public class FinalDemo2 {public static void main(String[] args) {// 目标:详解常量。System.out.println(Constant.SYSTEM_NAME);System.out.println(Constant.SYSTEM_NAME);System.out.println(Constant.SYSTEM_NAME);System.out.println(Constant.SYSTEM_NAME);System.out.println(Constant.SYSTEM_NAME);System.out.println(Constant.SYSTEM_NAME);}
}

out文件夹下查看编译后的代码如下:
常量会被“宏替换”

package com.itheima.finaldemo;public class FinalDemo2 {public FinalDemo2() {}public static void main(String[] args) {System.out.println("黑马程序员智能家居AI系统");System.out.println("黑马程序员智能家居AI系统");System.out.println("黑马程序员智能家居AI系统");System.out.println("黑马程序员智能家居AI系统");System.out.println("黑马程序员智能家居AI系统");System.out.println("黑马程序员智能家居AI系统");}
}

单例类

单例类属于设计模式这门课,设计模式架构师学的技术。
我们面试或者看底层源码可能会有一些知识涉及到设计模式。

什么是设计模式?

一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。简而言之:设计模式是具体问题的最优解决方案。
设计模式有20多种,对应20多种软件开发中会遇到的问题。

关于设计模式,主要学什么?

  1. 解决什么问题。
  2. 怎么写。

单例模式解决了什么问题 ?或者说他是干什么的。
确保某个类只能创建一个对象。

单例怎么写?

  1. 把类的构造器私有;
  2. 定义一个静态变量存储类的一个对象;
  3. 提供一个静态方法返回对象。
// 设计成单例设计模式
public class A {// 2、定义一个静态变量,用于存储本类的一个唯一对象。// 第三步可以用下面的这个代替。// public static final A a = new A();private static A a = new A();// 1、私有化构造器: 确保单例类对外不能创建太多对象,单例才有可能性。private A() {}// 3、提供一个公开的静态方法,返回这个类的唯一对象。public static A getInstance() {return a;}
}
package com.itheima.singleinstance;public class Test {public static void main(String[] args) {// 目标:设计单例类。A a1 = A.getInstance();A a2 = A.getInstance();System.out.println(a1); // com.itheima.singleinstance.A@404b9385System.out.println(a2); // com.itheima.singleinstance.A@404b9385System.out.println(a1 == a2);// trueSystem.out.println("============================");B b1 = B.getInstance();B b2 = B.getInstance();System.out.println(b1);System.out.println(b2);System.out.println(b1 == b2);}
}

饿汉式单例的特点是什么?

在获取类的对象时,对象已经创建好了。

单例有啥应用场景,有啥好处?

  • 任务管理器对象、获取运行时对象。
  • 在这些业务场景下,使用单例模式,可以避免浪费内存。

懒汉式单例类。

用对象时,才开始创建对象。

  1. 懒汉单例模式怎么写?
    1. 把构造器私有。
    2. 定义一个类变量用于存储对象。
    3. 提供一个类方法,保证返回的是同一个对象。
// 懒汉式单例类。
public class B {// 2、私有化静态变量private static B b;// 1、私有化构造器private B() { }// 3、提供静态方法返回对象: 真正需要对象的时候才开始创建对象。public static B getInstance() {if (b == null) {// 第一次拿对象时,会创建对象,给静态变量b记住。b = new B();}return b;}
}public class Test {public static void main(String[] args) {B b1 = B.getInstance();B b2 = B.getInstance();System.out.println(b1);// com.itheima.singleinstance.B@682a0b20System.out.println(b2);// com.itheima.singleinstance.B@682a0b20System.out.println(b1 == b2);//true}
}

枚举类

认识枚举类

枚举是一种特殊类。
枚举类的写法

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

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

// 枚举类
public enum A {// 枚举类的第一行:只能罗列枚举对象的名称,这些名称本质是常量。X, Y, Z;
}
// 这是
public class Test {public static void main(String[] args) {// 目标:认识枚举类,搞清楚其本质特点。A a1 = A.X;System.out.println(a1);A a2 = A.Y;System.out.println(a2);// 编译器为枚举类新增了几个方法System.out.println(a1.name()); // XSystem.out.println(a2.name()); // YSystem.out.println(a1.ordinal()); // 索引  0System.out.println(a2.ordinal()); // 索引  1}
}

我们来看一下public enum A{ }的编译后的代码

Compiled from “A.java"
public final class A extends java.lang.Enum<A> {public static final A X = new A();public static final A Y = new A();public static final A Z = new A();public static A[] values();public static A valueOf(java.lang.String);
}

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

枚举类的常见应用场景

先使用变量写:

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) {// 需求:模拟上下左右移动图片。// 第一种是常量做信息标志和分类: 但参数值不受约束。// 参数值可以传入0,1,110。move(Constant.UP);}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("输入有误");}}
}

使用枚举类写。

public enum Direction {UP, DOWN, LEFT, RIGHT;
}
public class Test2 {public static void main(String[] args) {// 第二种是枚举做信息标志和分类: 参数值受枚举类约束。move2(Direction.DOWN);}public static void move2(Direction 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;}}
}

抽象类

认识抽象类

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

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

语法

修饰符 abstract class 类名{ // 抽象方法:必须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方法"); }//省略getter()和setter()
}public class B extends A{
// 一个类继承抽象类,必须重写完继承的全部抽象方法,否则这个类也必须定义成抽象类@Overridepublic void show() {System.out.println("B类重写show方法");}
}
public class AbstractDemo1 {public static void main(String[] args) {// 目标:认识抽象类,抽象方法,搞清楚他们的特点。// 抽象类的核心特点:有得有失(得到了抽象方法的能力,失去了创建对象的能力)// 抽象类不能创建对象(重点)。// A a = new A();  // 报错了// 抽象类的使命就是被子类继承:就是为了生孩子。B b = new B(); // A的无参构造器b.setName("张三");b.setAge(18);System.out.println(b.getName() + "---" + b.getAge());// 张三---18b.show(); // B类重写show方法b.show1();// show1方法}
}

使用抽象类的好处

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

public abstract class Animal {// 每个动物的叫声。// 如果这里不写抽象方法cry(),无法使用父类调用子类的方法。//  Animal a = new Dog();右侧不能解耦。public abstract void cry();
}
public class Dog extends Animal{@Overridepublic void cry() {System.out.println("🐕是汪汪汪的叫~~~");}
}
public class Cat extends Animal{@Overridepublic void cry() {System.out.println("🐱是喵喵喵的叫~~~");}
}
public class Test {public static void main(String[] args) {Animal a = new Dog();a.cry();// 🐕是汪汪汪的叫~~~}
}

模板方法设计模式

  • 提供一个方法作为完成某类功能的模板,模板方法封装了每个实现步骤,但允许子类提供特定步骤的实现。
  • 模板方法设计模式可以:提高代码的复用、并简化子类设计。
    在这里插入图片描述
    写法
    1、定义一个抽象类。
    2、在里面定义2个方法
    • 一个是模板方法:把共同的实现步骤放里面去。
    • 一个是抽象方法:不确定的实现步骤,交给具体的子类来完成。

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

  • 模板方法是给子类直接使用的,不能被子类重写。
  • 一旦子类重写了模板方法,模板方法就失效了。
public abstract class People {// 1、模板方法设计模式。public final void write(){System.out.println("\t\t\t《我的爸爸》");System.out.println("\t我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下:");// 2、模板方法知道子类一定要写这个正文,但是每个子类写的信息是不同的,父类定义一个抽象方法// 具体的实现交给子类来重写正文。writeMain();System.out.println("\t我爸爸真好,你有这样的爸爸吗?");}public abstract void writeMain();
}
public class Student extends People{@Overridepublic void writeMain() {System.out.println("\t我爸爸很牛逼,是个管理者,我开车不用看红绿灯的,有这样的爸爸真好,下辈子还要做他儿子!");}
}
public class Teacher extends People {@Overridepublic void writeMain() {System.out.println("\t我爸爸经常让我站在这里别动,他要去买几斤橘子~~柚子我也吃,毕竟是亲生的!");}
}
public class Test {public static void main(String[] args) {// 抽象类的使用场景之二:模板方法设计模式。// 学生和老师都要写一篇作文:《我的爸爸》//         第一段是一样的:我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下://         第二段是不一样:老师和学生各自写各自的。//         第三段是一样的:我爸爸真好,你有这样的爸爸吗?// 解决:抽出一个父类。父类中还抽取一个模板方法给子类直接用。Student s = new Student();s.write();
//        			《我的爸爸》
//	我爸爸是一个好人,我特别喜欢他,他对我很好,我来介绍一下:
//	我爸爸很牛逼,是个管理者,我开车不用看红绿灯的,有这样的爸爸真好,下辈子还要做他儿子!
// 我爸爸真好,你有这样的爸爸吗?s.writeMain();
//我爸爸很牛逼,是个管理者,我开车不用看红绿灯的,有这样的爸爸真好,下辈子还要做他儿子!}
}

接口

什么是接口

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

接口语法

public interface 接口名 {// 成员变量(常量)// 成员方法(抽象方法)
} 

注意:接口不能创建对象。

接口如何实现

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

修饰符 class 实现类类名 implements 接口1, 接口2, 接口3 , ... {// 实现类实现多个接口,必须重写完全部接口的全部抽象方法,// 否则实现类需要定义成抽象类。// JDK 8之前,接口中只能定义常量和抽象方法。
} 
// 接口:使用interface关键字定义的
public interface A {// JDK 8之前,接口中只能定义常量和抽象方法。// 1、常量:接口中定义常量可以省略public static final不写,默认会加上去。String SCHOOL_NAME = "黑马程序员";// public static final String SCHOOL_NAME2 = "黑马程序员";// 2、抽象方法: 接口中定义抽象方法可以省略public abstract不写,默认会加上去。// public abstract void run();void run();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.run();System.out.println(c.go());c.play();}
}
// C被称为实现类。同时实现了多个接口。
// 实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须定义成抽象类
class C implements  B , A{@Overridepublic void run() {System.out.println("C类重写了run方法");}@Overridepublic String go() {return "黑马找磊哥!";}@Overridepublic void play() {System.out.println("C类重写了play方法");}
}

接口的好处

+ 弥补了类单继承的不足,一个类同时可以实现多个接口,使类的角色更多,功能更强大。
+ 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)。
public class Test {public static void main(String[] args) {// 接口弥补了类单继承的不足,可以让类拥有更多角色,类的功能更强大。// 学生是个人,但是学生可能兼职代代驾。所以亲爹是人,干爹是代驾等等。People p = new Student();Driver d = new Student(); // 多态BoyFriend bf = new Student();// 接口可以实现面向接口编程,更利于解耦合。// 比如说A公司要做一个对学生增删改查的功能,A公司设计一个接口,// 这个接口要求删接口 查接口 统计作业接口 // 给学生建议接口 集成ai接口。// 现在有B,C两个公司去实现这5个接口,我们用哪个呢?// A公司 a = new B公司 // A公司 a = new C公司 // 如上A公司接口不变,只要换个公司就能接着实现功能Driver a = new Student();Driver a2 = new Teacher();BoyFriend b1 = new Student();BoyFriend b2 = new Teacher();}
}
interface Driver{}
interface BoyFriend{}
class People{}
class Student extends People implements Driver, BoyFriend{}class Teacher implements Driver, BoyFriend{}

接口的综合小案例

需求

请设计一个班级学生的信息管理模块:学生的数据有:姓名、性别、成绩
功能1:要求打印出全班学生的信息;
功能2:要求打印出全班学生的平均成绩。

注意!以上功能的业务实现是有多套方案的,比如:

  • 第1套方案:能打印出班级全部学生的信息;能打印班级全部学生的平均分。
  • 第2套方案:能打印出班级全部学生的信息(包含男女人数);能打印班级全部学生的平均分(要求是去掉最高分、最低分)。
    要求:系统可以支持灵活的切换这些实现方案。

分析

提供两套业务实现方案,支持灵活切换(解耦合): 面向接口编程。
– 定义一个接口(规范思想):必须完成打印全班学生信息,打印平均分。(ClassDataInter)

  • 定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分。
  • 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)。

在这里插入图片描述

代码

在这里插入图片描述

// Student.java
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;}@Overridepublic void printAllStudentInfos() {System.out.println("全班学生信息如下:");for (int i = 0; i < students.length; i++) {Student s = students[i];System.out.println(s.getName() + " " + s.getSex() + " " + s.getScore());}}@Overridepublic void printAverageScore() {double sum = 0;for (int i = 0; i < students.length; i++) {Student s = students[i];sum += s.getScore();}System.out.println("全班平均成绩为:" + sum / students.length);}
}
//    -- 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)。
public class ClassDataInterImpl2 implements ClassDataInter{private Student[] students; // 记住送来的全班学生对象信息。public ClassDataInterImpl2(Student[] students) {this.students = students;}@Overridepublic void printAllStudentInfos() {System.out.println("学生信息如下:");int maleCount = 0; // 男生人数for (int i = 0; i < students.length; i++) {Student s = students[i];System.out.println(s.getName() + " " + s.getSex() + " " + s.getScore());if (s.getSex() == '男') {maleCount++;}}System.out.println("男学生人数:" + maleCount);System.out.println("女学生人数:" + (students.length - maleCount));}// 实现打印平均分(去掉最高分和最低分)@Overridepublic void printAverageScore() {System.out.println("平均分如下:");Student s1 = students[0];double sum = s1.getScore();double max = s1.getScore();double min = s1.getScore();for (int i = 1; i < students.length; i++) {Student s = students[i];sum += s.getScore();if(s.getScore() > max) {max = s.getScore();}if(s.getScore() < min) {min = s.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("张三", '男', 100);allStudents[1] = new Student("李四", '女', 99);allStudents[2] = new Student("王五", '男', 98);allStudents[3] = new Student("赵六", '女', 97);allStudents[4] = new Student("孙七", '男', 96);allStudents[5] = new Student("周八", '女', 95);allStudents[6] = new Student("吴九", '男', 94);allStudents[7] = new Student("郑十", '女', 93);allStudents[8] = new Student("赵敏", '女', 100);allStudents[9] = new Student("周芷若", '女', 90);// 3、提供两套业务实现方案,支持灵活切换(解耦合): 面向接口编程。//    -- 定义一个接口(规范思想):必须完成打印全班学生信息,打印平均分。(ClassDataInter)//    -- 定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分。//    -- 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)。ClassDataInter cdi = new ClassDataInterImpl2(allStudents);cdi.printAllStudentInfos();cdi.printAverageScore();}
}

JDK8新增的三种方法

一般开发不用,这是sun公司为了开发其他功能而设计的。

public interface A {// 1、默认方法(普通实例方法):必须加default修饰,// 默认会用public修饰。// 如何调用? 使用接口的实现类的对象来调用。default void go(){System.out.println("==go方法执行了===");run();}// 2、私有方法(JDK 9开始才支持的)// 私有的实例方法。// 如何调用? 使用接口中的其他实例方法来调用它private void run(){System.out.println("==run方法执行了===");}// 3、静态方法// 默认会用public修饰。// 如何调用? 只能使用当前接口名来调用。static void show(){System.out.println("==show方法执行了===");}
}
class AImpl implements A{}
public class Test {public static void main(String[] args) {// 目标:搞清楚接口JDK 8新增的三种方法,并理解其好处。// 我们知道当我们需要添加一个新接口去实现某个东西,// 我们需要修改几十个接口的实现类,// 当我们有了这三种就可以直接实现不用修改接口的实现类。AImpl a = new AImpl();a.go();A.show(); // 静态方法'}
}

接口的注意事项

1、接口与接口可以多继承:一个接口可以同时继承多个接口[重点]。
2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。[了解]
3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的默认方法,实现类会优先用父类的。
4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

1

public class Test {public static void main(String[] args) {  }
}
// 1、接口与接口可以多继承:一个接口可以同时继承多个接口[重点]。
// 类与类: 单继承 一个类只能继承一个直接父类
// 类与接口:多实现,一个类可以同时实现多个接口。
// 接口与接口: 多继承,一个接口可以同时继承多个接口。
interface A {void show1();
}
interface B {void show2();
}
interface C extends B , A{void show3();
}
class D implements C{@Overridepublic void show3() {}@Overridepublic void show1() {}@Overridepublic void show2() {}
}

2

public class Test {public static void main(String[] args) {  }
}// 2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。[了解]
interface A1 {void show();
}
interface B1 {String show();
}
// 下面报错
//interface C1 extends A1, B1 {
//}
//class D1 implements A1, B1{
//}

3

public class Test {public static void main(String[] args) {Dog d = new Dog();d.go();// 父类中的 show 方法// 父类中的 show 方法// 接口中的 A2 show 方法}
}// 3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。[了解]
interface A2 {default void show(){System.out.println("接口中的 A2 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(); // A2接口的方法}
}

4

public class Test {public static void main(String[] args) {Dog d = new Dog();d.go();}
}// 4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
interface A3 {default void show(){System.out.println("接口中的 A3 show 方法");}
}interface B3 {default void show(){System.out.println("接口中的 B3 show 方法");}
}class Dog2 implements A3, B3 {@Overridepublic void show() {A3.super.show(); // A3干爹的B3.super.show(); // B3干爹的}
}

抽象类和接口的区别

相同点:

  1. 都是抽象形式,都可以有抽象方法,都不能创建对象。
  2. 都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现。
  3. 一个类继承抽象类,或者实现接口,都必须重写完他们的抽象方法,否则自己要成为抽象类或者报错!
  4. 都能支持的多态,都能够实现解耦合。

不同点:

  1. 抽象类中可以定义类的全部普通成员,接口只能定义常量,抽象方法(JDK8新增的三种方式)
  2. 抽象类只能被类单继承,接口可以被类多实现。
  3. 一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)。
  4. 抽象类体现模板思想:更利于做父类,实现代码的复用性。 最佳实践
  5. 接口更适合做功能的解耦合:解耦合性更强更灵活。 最佳实践

案例

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

import java.util.Scanner;public class Test {public static void main(String[] args) {// 目标:面向对象编程实现智能家居控制系统。// 角色:设备(吊灯,电视机,洗衣机,落地窗,....)// 具备的功能:开和关。// 谁控制他们:智能控制系统(单例对象),控制调用设备的开和关。// 1、定义设备类:创建设备对象代表家里的设备。// 2、准备这些设备对象,放到数组中,代表整个家庭的设备。JD[] jds = new JD[4];jds[0] = new TV("小米电视", true);jds[1] = new WashMachine("美的洗衣机", false);jds[2] = new Lamp("欧灯", true);jds[3] = new Air("美的空调", false);// 3、为每个设备制定一个开个关的功能。定义一个接口,让JD实现开关功能。// 4、创建智能控制系统对象,控制设备开和关。SmartHomeControl smartHomeControl = SmartHomeControl.getSmartHomeControl();// 5、控制电视机。// smartHomeControl.control(jds[0]);// 6 、提示用户操作,a、展示全部设备的当前情况。b、让用户选择哪一个操作。// 打印全部设备的开和关的现状。while (true) {smartHomeControl.printAllStatus(jds);System.out.println("请您选择要控制的设备:");Scanner sc = new Scanner(System.in);String command = sc.next();switch (command){case "1":smartHomeControl.control(jds[0]);break;case "2":smartHomeControl.control(jds[1]);break;case "3":smartHomeControl.control(jds[2]);break;case "4":smartHomeControl.control(jds[3]);break;case "exit":System.out.println("退出App!");return;default:System.out.println("输入有误,请重新输入");}}}
}
public class Air extends JD{public Air(String name, boolean status) {super(name, status);}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;// 家电
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JD implements Switch{private String name;// 状态:开或者关。private boolean status; // false 默认是关闭。@Overridepublic void press() {// 控制当前设备开和关status = !status;}
}
// 灯
public class Lamp extends JD{public Lamp(String name, boolean status) {super(name, status);}
}
// 智能控制系统类。
public class SmartHomeControl {private static SmartHomeControl smartHomeControl= new SmartHomeControl();private SmartHomeControl() {}public static SmartHomeControl getSmartHomeControl() {return smartHomeControl;}// 多态。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循环,根据索引遍历每个设备。for (int i = 0; i < jds.length; i++) {JD jd = jds[i];System.out.println((i + 1) + "," + jd.getName() + "状态目前是:" + (jd.isStatus() ? "开着" : "关闭!"));}}
}
public interface Switch {// 这个开关设计到 JD类中是因为方便以后得解耦合。void press(); // 按压
}
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);}
}

相关文章:

面向对象高级(1)

文章目录 final认识final关键字修饰类&#xff1a;修饰方法&#xff1a;修饰变量final修饰变量的注意事项 常量 单例类什么是设计模式&#xff1f;单例怎么写?饿汉式单例的特点是什么&#xff1f;单例有啥应用场景&#xff0c;有啥好处&#xff1f;懒汉式单例类。 枚举类认识枚…...

HTTP 压力测试工具autocannon(AI)

简介 autocannon 是一款基于 Node.js 的高性能 HTTP 压力测试工具&#xff0c;适用于评估 Web 服务的并发处理能力和性能瓶颈。 一、工具特点 高性能‌&#xff1a;利用 Node.js 异步非阻塞机制模拟高并发请求‌。‌实时监控‌&#xff1a;测试过程中动态展示请求统计和性能…...

my2sql工具恢复误删数据

一、下载my2sql my2sql下载地址https://github.com/liuhr/my2sql/blob/master/releases/centOS_release_7.x/my2sql 二、my2sql工具注意事项 1. binlog格式必须为row&#xff0c;且binlog_row_imagefull 原因&#xff1a;binlog_row_image 参数决定了 binlog 中是否记录完整的…...

【AGI-Eval行业动态】OpenAI 语音模型三连发,AI 语音进入“声优”时代

前言&#xff1a;OpenAI又双叒叕搞事情了&#xff01;这次他们带着三款全新语音模型强势来袭&#xff0c;直接让 AI 语音界卷出新高度&#xff01;无论是语音识别的精准度、还是根据文字生成音频的脑洞&#xff0c;这三款模型都堪称“神仙打架”。 如果你还在用老掉牙的语音助手…...

蓝桥杯嵌入式十四届模拟一(eeprom)

一.LED 先配置LED的八个引脚为GPIO_OutPut&#xff0c;锁存器PD2也是&#xff0c;然后都设置为起始高电平&#xff0c;生成代码时还要去解决引脚冲突问题 二.按键 按键配置&#xff0c;由原理图按键所对引脚要GPIO_Input 生成代码&#xff0c;在文件夹中添加code文件夹&#…...

ArcGis Reclassify CDL

1. 下载CDL CropScape - NASS CDL Program 2. 把CDL放入arcgis&#xff0c;导出表格&#xff0c;变成csv 3. 把cvs表格里的内容合并&#xff0c;分类成 agriculture developed open natural other water woods fruits 等 4.变成新的表格&#xff0c;导入gis使用recla…...

DevOps与功能安全:Perforce ALM通过ISO 26262合规认证,简化安全关键系统开发流程

本文来源perforce.com&#xff0c;由Perforce中国授权合作伙伴、DevSecOps解决方案提供商-龙智翻译整理。 近日&#xff0c;Perforce ALM&#xff08;原Helix ALM&#xff09;通过了国际权威认证机构 TV SD的ISO 26262功能安全流程认证&#xff01;该认证涵盖Perforce ALM解决方…...

C++高精度算法(加、减、乘)

首先声明&#xff0c;没有除法是因为我不会&#xff08;手动狗头_doge&#xff09; 简介 顾名思义&#xff0c;高精度算法是用来算一些超级大的数&#xff0c;比如长到 longlong 都存不下的那种&#xff0c;还有就是小数点后好多位&#xff0c;double都存不下的那种&#xff…...

【图片识别改名工具】如何识别图片中文字内容,并根据文字对图片批量重命名批量改名,基于WPF和腾讯OCR的完整实现

​​办公场景​​ ​​批量处理图片文件​​:用户有一批图片文件,图片中包含文字信息(如编号、日期、名称等),需要根据图片中的文字内容对图片进行重命名。​​自动化办公​​:在办公场景中,用户需要将图片文件按内容分类或归档,手动重命名效率低下,自动化工具可以大幅…...

Dify+DeepSeek能做出什么来?快速构建可扩展的 AI 应用

将 Dify&#xff08;开源 LLM 应用开发平台&#xff09;与 DeepSeek&#xff08;深度求索公司的高性能大模型&#xff0c;如 DeepSeek-R1 或 DeepSeek-Lite&#xff09;结合使用&#xff0c;可以充分发挥两者的优势&#xff0c;快速构建高效、灵活且可扩展的 AI 应用。以下是具…...

【深度学习】Ubuntu 服务器配置开源项目FIGRET(PyTorch、torch-scatter、torch-sparse、Gurobi 安装)

开源项目网址&#xff1a;https://github.com/FIGRET/figret 该项目在SIGCOMM2024发表&#xff0c;用深度学习方法处理流量工程中的突发问题 1. 创建新的 Conda 环境 使用国内镜像源创建环境​ conda create -n figret python3.8.0 --override-channels -c https://mirrors.…...

浅析Centos7安装Oracle12数据库

Linux下的Oracle数据库实在是太难安装了&#xff0c;事贼多&#xff0c;我都怀疑能安装成功是不是运气的成分更高一些。这里虚拟机是VMware Workstation 15.5&#xff0c;操作系统是Centos7&#xff0c;Oracle版本是Oracle Database 12c Enterprise Edition Release 12.1.0.2.0…...

代码随想录算法训练营Day27 | Leetcode 56. 合并区间、738.单调递增的数字、968.监控二叉树

代码随想录算法训练营Day27 | Leetcode 56.合并区间、738.单调递增的数字、968.监控二叉树 一、合并区间 相关题目&#xff1a;Leetcode56 文档讲解&#xff1a;Leetcode56 视频讲解&#xff1a;Leetcode56 1. Leetcode56. 合并区间 以数组 intervals 表示若干个区间的集合&am…...

三大开源大模型应用框架深度对比:AnythingLLM、Dify 与 Open-WebUI

三大开源大模型应用框架深度对比&#xff1a;AnythingLLM、Dify 与 Open-WebUI 本文将全面解析三大主流开源大模型应用框架与Ollama的集成方案&#xff0c;帮助开发者根据实际需求选择最适合的工具。 一、框架概览与定位差异 1. AnythingLLM&#xff1a;企业级知识管理专家 …...

freertos低功耗模式简要概述

简介 FreeRTOS 的 Tickless 模式是一种特殊的运行模式&#xff0c;用于最小化系统的时钟中断频率&#xff0c;以降低功耗。在 Tickless 模式下&#xff0c;系统只在有需要时才会启动时钟中断&#xff0c;而在无任务要运行时则完全进入休眠状态&#xff0c;从而降低功耗。在滴答…...

ESP32S3 链接到 WiFi

以下是关于如何让 ESP32S3 连接到 WiFi 的完整流程和代码示例&#xff1a; ESP32S3 链接到 WiFi 1. 设置工作模式 ESP32 可以工作在两种模式下&#xff1a; Station (STA) 模式&#xff1a;作为无线终端连接到无线接入点&#xff08;AP&#xff09;&#xff0c;类似于手机或…...

2024年博客之星的省域空间分布展示-以全网Top300为例

目录 前言 一、2024博客之星 1、所有排名数据 2、空间属性管理 二、数据抓取与处理 1、相关业务表的设计 2、数据抓取处理 3、空间查询分析实践 三、数据成果挖掘 1、省域分布解读 2、技术开发活跃 四、总结 前言 2024年博客之星的评选活动已经过去了一个月&#xf…...

vue项目引入tailwindcss

vue3项目引入tailwindcss vue3 vite tailwindcss3 版本 初始化项目 npm create vitelatest --template vue cd vue npm install npm run dev安装tailwindcss3 和 postcss 引入 npm install -D tailwindcss3 postcss autoprefixer // 初始化引用 npx tailwindcss init -p…...

蓝桥赛前复习2:一维差分二维差分

一维差分 问题描述 给定一个长度为 nn 的序列 aa。 再给定 mm 组操作&#xff0c;每次操作给定 33 个正整数 l,r,dl,r,d&#xff0c;表示对 al∼ral∼r​ 中的所有数增加 dd。 最终输出操作结束后的序列 aa。 Update&#xff1a;由于评测机过快&#xff0c;n,mn,m 于 2024…...

算法---子序列[动态规划解决](最长递增子序列)

最长递增子序列 子序列包含子数组&#xff01; 说白了&#xff0c;要用到双层循环&#xff01; 用双层循环中的dp[i]和dp[j]把所有子序列情况考虑到位 class Solution { public:int lengthOfLIS(vector<int>& nums) {vector<int> dp(nums.size(),1);for(int i …...

100道C#高频经典面试题带解析答案——全面C#知识点总结

100道C#高频经典面试题带解析答案 以下是100道C#高频经典面试题及其详细解析&#xff0c;涵盖基础语法、面向对象编程、集合、异步编程、LINQ等多个方面&#xff0c;旨在帮助初学者和有经验的开发者全面准备C#相关面试。 &#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSD…...

jar包安全加密工具

目录 1. 代码混淆工具(Obfuscation) 推荐工具 (1) ProGuard (2) Allatori (3) DashO 2. JAR 加密工具(Class 文件加密) 推荐工具 (1) JxCore (2) ClassFinal (3) Zelix KlassMaster 3. 自定义类加载器加密 实现思路 4. 打包成 Native 可执行文件 推荐工具 (…...

MQTT的构成、使用场景、工作原理介绍

一、MQTT内容简介 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级、基于发布-订阅模式的消息传输协议【适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境】它在物联网应用中广受欢迎&#xff0c;能够实现传感器、执行器和其它设备之间的…...

RESTful API以及使用它构建 web 应用程序的方法

RESTful API是一种基于REST&#xff08;Representational State Transfer&#xff09;架构风格的应用程序接口&#xff0c;通过HTTP协议传输数据并使用标准的HTTP方法&#xff08;GET、POST、PUT、DELETE&#xff09;来对资源进行操作。 RESTful API 遵循一系列约定和规范&…...

Vanna + qwq32b 实现 text2SQL

Vanna 是一个开源的 Text-2-SQL 框架&#xff0c;主要用于通过自然语言生成 SQL 查询&#xff0c;它基于 RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;技术。Vanna 的核心功能是通过训练一个模型&#xff08;基于数据库的元数据和用户提…...

电脑知识 | TCP通俗易懂详解 <一>

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f68d;什么是TCP/TCP协议 三、&#x1f9cd;‍♂为什么TCP可靠 1.&#x1f970;关于可靠 2.&#x1f920;哪里可靠 3.&#x1f393;️图片的三次握手&#xff0c;四次挥手 4.&#x1f4da;️知识点总结 四、&…...

精品推荐-最新大模型MCP核心架构及最佳实践资料合集(18份).zip

精品推荐-最新大模型MCP核心架构及最佳实践资料合集&#xff0c;共18份。 1、2025年程序员必学技能&#xff1a;大模型MCP核心技术.pdf 2、MCP 架构设计剖析&#xff1a;从 Service Mesh 演进到 Agentic Mesh.pdf 3、MCP 架构设计深度剖析&#xff1a;使用 Spring AI MCP 四步…...

Linux 线程:从零构建多线程应用:系统化解析线程API与底层设计逻辑

线程 线程的概述 在之前&#xff0c;我们常把进程定义为 程序执行的实例&#xff0c;实际不然&#xff0c;进程实际上只是维护应用程序的各种资源&#xff0c;并不执行什么。真正执行具体任务的是线程。 那为什么之前直接执行a.out的时候&#xff0c;没有这种感受呢&#xf…...

VMware虚拟机Ubuntu磁盘扩容

VMware中操作&#xff1a; 选择要扩容的虚拟机&#xff0c;点击编辑虚拟机设置 打开后点击磁盘——>点击扩展&#xff08;注意&#xff1a;如果想要扩容的话需要删除快照&#xff09; 调整到你想要的容量 点击上图的扩展——>确定 然后我们进到虚拟机里面 首先&#…...

游戏引擎学习第217天

运行游戏并在 FreeVariableGroup 中遇到我们的断言 其实在美国&#xff0c;某些特定的小糖果&#xff08;例如小糖蛋&#xff09;只在圣诞节和复活节期间出售&#xff0c;导致有些人像我一样在这段时间吃得过多&#xff0c;进而增加体重。虽然这种情况每年都会发生&#xff0c…...