抽象类和接口的详解(实例)

article/2025/10/13 23:26:17

这里写图片描述

抽象类和接口在我们的代码中,生活中息息相关,与上图所示,操纵复杂,密切相关,那么问题来了,何谓抽象类,何谓接口?

带着这层薄纱,慢慢揭开这层薄纱;也许在古代,新婚之夜,透过这层薄纱,你看到的或者是惊喜,或许是惊悚,不要怕,无论是惊悚还是惊喜,她都会伴你一生。

曾几何时?你还会在面试当中与面试官对答如流的解释抽象类和接口吗?
面试官:解释一下抽象类和接口的区别?
me:

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

2、抽象类要被子类继承,接口要被类实现。

3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

7、抽象类里可以没有抽象方法

8、如果一个类里有抽象方法,那么这个类只能是抽象类

9、抽象方法要被实现,所以不能是静态的,也不能是私有的。

10、接口可继承接口,并可多继承接口,但类只能单根继承。

好吧,对答如流,可能是背会了,而且很熟,我们不仅仅是为了会背,如果过一段时间不忘记,能够根深蒂固,那只有融入到我们的思维中,形成我们自己的语言,不仅仅是文字的阐述,更是以图的形式存在,记忆在右脑当中,那么下面让我们探讨一下,在现实与代码中他们的作用。

我看网上有个例子很好,特此举例(适配器的概念):

没有使用适配器的时候,实现接口的类要实现接口的所有方法,即便只是对其中一个方法进行了实现
这里写图片描述
建立一个抽象类实现接口(适配器概念),再用抽象类的子类重写想要实现的方法
这里写图片描述

tips:对于接口,你需要继承接口里边所有的实现,而建立一个抽象类实现接口,那么可以用一个普通类实现这个抽象类就可以实现你需要的方法,方便了许多。

下面就是一个抽象类和接口引发的血案:

涉及到

1)掌握抽象类和接口的实例化操作。

2)掌握模板设计的作用。

3)掌握工厂设计模式的作用。

4)掌握代理设计模式的作用。

5)掌握适配器模式的作用。

6)掌握抽象类与接口的使用区别。

具体内容呢?
1、 在java中,可以通过对象的多态性,为抽象类和接口实例化,这样再使用抽象类和接口的时候就可以调用本子类中所覆写过的方法。
  之所以抽象类和接口不能直接实例化,是因为其内部包含了抽象方法,抽象方法本身是未实现的方法,所以无法调用。
  通过对象多态性可以发现,子类发生了向上转型关系之后,所调用的全部方法,都是被覆写过的方法。如下:

abstract class A{    // 定义抽象类Apublic abstract void print() ;    // 定义抽象方法print()
};
class B extends A {    // 定义子类,继承抽象类public void print(){        // 覆写抽象方法System.out.println("Hello World!") ;}
};
public class AbstractCaseDemo01{public static void main(String args[]){A a = new B() ;        // 通过子类为抽象类实例化,向上转型。a.print() ;}
};
运行结果:
Hello World!

可以继续利用此概念,为接口实例化。

package com.zhijin;
interface A{    // 定义抽象类Apublic abstract void print() ;    // 定义抽象方法print()
};
class B implements A {    // 定义子类,继承抽象类public void print(){        // 覆写抽象方法System.out.println("Hello World!!!") ;}
};
public class ThisDemo06{public static void main(String args[]){A a = new B() ;        // 通过子类为抽象类实例化a.print() ;}
};

所以,如果想要使用抽象类和接口,则只能按照以上操作完成。
2、抽象类的实际使用场景–设计模式(模板设计)

super : 动物
子类:猫、狗

abstract class Animal{private String name ;        // 定义name属性private int age ;            // 定义age属性public Animal(String name,int age){this.name = name ;this.age = age ;}public String getName(){return this.name ;}public int getAge(){return this.age ;}public void say(){        // 人说话是一个具体的功能System.out.println(this.getContent()) ;    // 输出内容}public abstract String getContent() ;    // 说话的内容由子类决定
};
class Cat extends Animal{private String call;public Cat(String name,int age,String call){super(name,age) ;    // 调用父类中的构造方法this.call= call ;}public String getContent(){return    " 姓名:" + super.getName() + ";年龄:" + super.getAge() + ";叫声:" + this.call;}
};
class Dog extends Animal{private String call ;public Dog (String name,int age,String call){super(name,age) ;    // 调用父类中的构造方法this.call= call;}public String getContent(){return    "姓名:" + super.getName() + ";年龄:" + super.getAge() + ";叫声:" + this.call ;}
};
public class AbstractCaseDemo02{public static void main(String args[]){Animal per1 = null ;    // 声明Animal 对象Animal per2 = null ;    // 声明Animal 对象per1 = new Cat("猫儿",2,"喵儿") ;    per2 = new Dog("小狗",10,"wangwang") ;    per1.call() ;    per2.call() ;  }
};
运行结果:
姓名:张三;年龄:2;喵儿
姓名:李四;年龄:10;wangwang

tips:抽象类就相当于一个模板,现实的模板:
这里写图片描述

3、接口的实际应用–制定标准

比如说“U盘和打印机都可以插在电脑上使用,因为他们都实现了USB标准的接口”

interface USB{        // 定义了USB接口public void start() ;    // USB设备开始工作public void stop() ;    // USB设备结束工作
}
class Computer{public static void plugin(USB usb){    // 电脑上可以插入USB设备,向上转型,这里就相当于一个接口,只有符合这个接口的标准的类的对象(即只有继承这个接口的类的对象),才能被这个方法调用。usb.start() ;System.out.println("=========== USB 设备工作 ========") ;usb.stop() ;}
};
class Flash implements USB{public void start(){    // 覆写方法System.out.println("U盘开始工作。") ;}public void stop(){        // 覆写方法System.out.println("U盘停止工作。") ;}
};
class Print implements USB{public void start(){    // 覆写方法System.out.println("打印机开始工作。") ;}public void stop(){        // 覆写方法System.out.println("打印机停止工作。") ;}
};
public class InterfaceCaseDemo02{public static void main(String args[]){Computer.plugin(new Flash()) ;Computer.plugin(new Print()) ;}
};
运行结果:
U盘开始工作。
=========== USB 设备工作 ========
U盘停止工作。
打印机开始工作。
=========== USB 设备工作 ========
打印机停止工作。

4、工厂设计模式–接口应用

interface Fruit{    // 定义一个水果接口public void eat() ;    // 吃水果
}
class Apple implements Fruit{public void eat(){System.out.println("** 吃苹果。") ;}
};
class Orange implements Fruit{public void eat(){System.out.println("** 吃橘子。") ;}
};
public class InterfaceCaseDemo03{public static void main(String args[]){Fruit f = new Apple() ;    // 实例化接口f.eat() ;}
};
运行结果:
吃苹果。

看起来上边的代码没有什么大问题,但是扩展性呢?
JVM工作原理:程序-》JVM(相当于客户端)-》操作系统。

问题的解决:客户端通过过渡端,得到特定子类的接口实例,返回接口实例给客户端,接口实例调用接口中的方法。
此时就涉及到了工厂模式

interface Fruit{    // 定义一个水果接口public void eat() ;    // 吃水果
}
class Apple implements Fruit{public void eat(){System.out.println("** 吃苹果。") ;}
};
class Orange implements Fruit{public void eat(){System.out.println("** 吃橘子。") ;}
};
class Factory{    // 定义工厂类public static Fruit getInstance(String className){ //注意这里的方法是static修饰的,因为在主方法中是Factory调用Fruit f = null ;if("apple".equals(className)){    // 判断是否要的是苹果的子类f = new Apple() ;}if("orange".equals(className)){    // 判断是否要的是橘子的子类f = new Orange() ;}return f ;}
};
public class InterfaceCaseDemo04{public static void main(String args[]){Fruit f = Factory.getInstance(”apple“) ;    // 实例化接口f.eat() ;}
};
运行结果:
**吃苹果

5、代理模式–接口应用
这里说的代理模式有很多种,讨债公司代理要讨债的人,江歌案中(日本律师代理江母),下面我们讲一下我们经常使用的代理服务器;

interface Network{  public void browse() ;    // 浏览
}
class Real implements Network{  //真实上网操作类public void browse(){System.out.println("上网浏览信息") ;}
};
class Proxy implements Network{  //代理类。private Network network ;    // 代理对象public Proxy(Network network){  //初始化,把真实对象传给代理对象,向上转型操作。this.network = network ;}public void check(){System.out.println("检查用户是否合法。") ;}public void browse(){this.check() ;this.network.browse() ;    // 调用真实的主题操作,这里调用的是真实类里的对象。}
};
public class ProxyDemo{public static void main(String args[]){Network net = null ;net  = new Proxy(new Real()) ;//  指定代理操作,这里两次向上转型操作,第一次向上是实例化代理类,
第二次向上转型是括号中,把真实类对象传入,以便在代理类中调用真实类中的方法。net.browse() ;    // 客户只关心上网浏览一个操作}
};
运行结果:
检查用户是否合法
上网浏览信息

5、适配器模式–上边刚开始的案例
在Java中,一个子类实现一个接口,则肯定在子类中复写此接口中全部抽象方法,那么这就造成提供的抽象方法过多,而实际不需要,那么我们会选择一个中间过渡(也就是适配器模式)
这里写图片描述

interface Window{        // 定义Window接口,表示窗口操作public void open() ;    // 打开public void close() ;    // 关闭public void activated() ;    // 窗口活动public void iconified() ;    // 窗口最小化public void deiconified();// 窗口恢复大小
}
abstract class WindowAdapter implements Window{public void open(){} ;    // 打开public void close(){} ;    // 关闭public void activated(){} ;    // 窗口活动public void iconified(){} ;    // 窗口最小化public void deiconified(){};// 窗口恢复大小
};
class WindowImpl extends WindowAdapter{public void open(){System.out.println("窗口打开。") ;}public void close(){System.out.println("窗口关闭。") ;}
};
public class AdapterDemo{public static void main(String args[]){Window win = new WindowImpl() ;win.open() ;win.close() ;}
};
运行结果:窗口打开。
窗口关闭。

6、内部类的扩展

abstract class A{    // 定义抽象类public abstract void printA() ;    // 抽象方法interface B{    // 定义内部接口public void printB() ;    // 定义抽象方法}
};
class X extends A{    // 继承抽象类public void printA(){System.out.println("HELLO --> A") ;}class Y implements B{    // 定义内部类实现内部接口public void printB(){System.out.println("HELLO --> B") ;}};
};
public class InnerExtDemo01{public static void main(String args[]){A.B b = new X().new Y() ;  //参考前面内部类的知识,实现内部类实例的方法:外部类.内部类  内部类对象= 外部类对象.new  内部类b.printB() ;}
};
运行结果:
HELLO-->B

 含有内部接口的抽象类的子类,必须也要定义内部类继承该接口。

interface A{    // 定义接口public void printA() ;    // 抽象方法abstract class B{    // 定义内部抽象类public abstract void printB() ;    // 定义抽象方法}
};
class X implements A{    // 实现接口public void printA(){System.out.println("HELLO --> A") ;}class Y extends B{    // 继承抽象类public void printB(){System.out.println("HELLO --> B") ;}};
};
public class InnerExtDemo02{public static void main(String args[]){A.B b = new X().new Y() ;b.printB() ;}
};

 含有内部抽象类的接口,对于继承他的子类来说,除了要覆写接口中的抽象方法,还要专门定义一个内部类继承抽象类,并覆写全部抽象类。
 从开发中,一般不推荐,看起来这些代码有点混乱。

总结:
这里写图片描述


Tips:在开发中,一个类永远不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口,如果两个类同时可以使用的话,优先使用接口,避免单继承的局限性。

1)抽象类和接口类的实例化,通过多态性(向上转型,向下转型)。

2)抽象类表示一个模板,接口表示一个标准。

3)常见的设计模式:模板设计,工厂设计,代理设计,适配器设计。


http://chatgpt.dhexx.cn/article/ghT5x2of.shtml

相关文章

接口和抽象类的区别

转自:https://www.cnblogs.com/yongjiapei/p/5494894.html 接口和抽象类有什么区别 你选择使用接口和抽象类的依据是什么? 接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。 抽象类表示的是,这个对象是什…

接口与抽象类的区别

c# 一、抽象类: 抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现&…

Java抽象类与接口(学习笔记)

抽象类 什么是抽象类: 类和类之间具有共同特征,讲这些共同特征抽取出来,就形成了抽象类。因为类本身是不存在的,所以抽象类无法创建对象(无法实例化)。 以下借用视频中总结的思维层次图: 抽象类…

接口与抽象类的区别 详细总结

------------------------- 在这里我总结了五点区别 ----------------------- 区别一: 抽象类中可以存在非抽象的方法 VS 接口中的方法被默认的变成抽象方法,只要是定义了接口,接口中的方法 就全部变成了抽象类即使你不写 abstract 它也是抽…

Java-抽象类与接口

前言 温故而知新 最近从头来看当初学过的语法知识点, 温故而知新, 发现当初还有许多未掌握的知识, 所以我建议大家也要多温故, 可能当初有好多知识点是没掌握到的. 这篇博客的重点就是介绍抽象类与接口, 并阐述他们的区别. 一. 抽象类 1. 概念 在面向对象的概念中, 所有的…

一文带你了解【抽象类和接口】

1. 抽象类概念 在面向对象的概念中,所有的对象都是通过类来描绘的,但是并不是所有类都是用来描绘对象的。如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。 举个简单的例子 上图中,三角形&#xff0…

抽象类和接口

目录 抽象类 抽象类使用abstract修饰类 抽象类当中可以包含普通类所能包含的成员 抽象类和普通类不一样的是,抽象类当中可以包含抽象方法。 抽象类方法是使用abstract修饰的,这个方法没有具体的实现 不能实例化抽象类 抽象类存在的意义是为了被继承…

Java抽象类和接口 -- 深度剖析

💖欢迎来阅读子豪的博客(Java语法篇🧔) 👉有什么宝贵的意见或建议可以在留言区留言 💻欢迎 素质三连 点赞 关注 收藏 🧑‍🚀码云仓库:补集王子的代码仓库 Java抽象类和接…

Java学习系列之抽象类和接口的区别和联系

导读 本文首先分别介绍抽象类和接口的基础概念、特征和应用场景,然后介绍其区别和联系。 1 抽象类 1.1 定义抽象类 在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称为抽象方法,抽象方法只有方法的声明&#xff…

从抽象类到接口—手把手教你写抽象类(一)—还在Ctrl C的伙伴们看过来了

目录 一、抽象类概述 二、抽象类的特点 三、抽象类的案例 四、抽象类的细节 五、抽象类的思想 抽象类概述 抽象定义 –抽象是从多个事物中将共性的,本质的内容抽取出来。 –例:狼和狗共性都是犬科,犬科就是抽象出来的概念。 抽象类 –…

Java基础学习:抽象类和接口

目录,更新ing,学习Java的点滴记录 目录放在这里太长了,附目录链接大家可以自由选择查看--------Java学习目录 抽象类和接口_抽象类和抽象方法 抽象类是普通的类与接口之间的一种中庸之道,尽管你可能在构建某些未实现方法的类是,第一想法可能是创建接口,但是抽象类仍旧是用于此…

SVD奇异值分解(理论与C++实现)

SVD奇异值分解 前言理论推导部分代码实现 前言 奇异值分解(singular value decomposition,以下简称SVD)是线性代数中一种重要的矩阵分解。SVD将矩阵分解为奇异向量(singular vector)和奇异值(singular value)。SVD将矩阵 A A A分解成三个矩阵的乘积 A U D V T A …

matlab实现奇异值分解

一、原理 二、实现 %% 两种方法计算矩阵 A 的 SVD A [0,1; 1,1; 1,0];%% 方法一:利用特征分解eig % 计算右奇异矩阵V [V,D1] eig(A*A); n size(D1,1); index n:-1:1; D1 diag(D1); D1 D1(index); D1 diag(D1, 0); V V(:,index); % 计算左奇异矩阵U [U,D2…

特征值分解和奇异值分解

特征值分解 特征值分解是将一个方阵A分解为如下形式: A Q Σ Q − 1 AQ\Sigma Q^{-1} AQΣQ−1 其中,Q是方阵A的特征向量组成的矩阵, Σ \Sigma Σ是一个对角矩阵,对角线元素是特征值。 通过特征值分解得到的前N个特征向量&am…

奇异值分解的揭秘(一):矩阵的奇异值分解过程

转载来源: 作者:Xinyu Chen 链接:https://zhuanlan.zhihu.com/p/26306568 来源:知乎 矩阵的奇异值分解(singular value decomposition,简称SVD)是线性代数中很重要的内容,并且奇…

奇异值分解(Singular Values Decomposition,SVD)

奇异值分解 1.奇异值分解1.1 变换(Transformations)1.2 线性变换(Linear Transformations)1.3 降维(Dimensionality Reduction)1.4 奇异值分解(SVD)1.4.1 如果矩阵 A A A是方阵&…

奇异值分解(SVD)的原理详解及推导

1. 写在前面 最近整理推荐系统模型的时候, 第二个模型打算整理一下隐语义模型, 这里面绕不开一种思想就是矩阵分解, 而作为矩阵分解的经典方法SVD感觉这次有必要学学了, SVD不仅是一个数学问题,在工程应用中的很多地方…

机器学习(29)之奇异值分解SVD原理与应用详解

微信公众号 关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 前言 奇异值分解(Singular Value Decomposition,简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于…

【机器学习】这次终于彻底理解了奇异值分解(SVD)原理及应用

奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,有相当多的应用与奇异值都可以扯上关系,它不光可以用于降维算法中的特征分解,比如做feature reduction的PCA,做数据压缩&#x…

联邦学习——用data-free知识蒸馏处理Non-IID

《Data-Free Knowledge Distillation for Heterogeneous Federated Learning》ICML 2021 最近出现了利用知识蒸馏来解决FL中的用户异构性问题的想法,具体是通过使用来自异构用户的聚合知识来优化全局模型,而不是直接聚合用户的模型参数。然而&#xff0c…