【JavaSE】抽象类、接口

接口的诞生


接口其实就是一种标准一种规范。
先从生活中的例子讲起,理解含义和概念后,再去理解程序会更容易理解一些。
生活中接口无处不在,比如著名的USB接口,大家可以试想一下,如果没有像USB这种统一的标准我们会有多麻烦。
拿电脑端来举例:
image
这台电脑只有A 接口,另一台电脑只有B 接口,一万台电脑就可以有一万个接口,那你该怎么去买数据线?
就算买了数据线,也只能用在一台电脑上换一个电脑就完全没用了。
而这只是数据线的其中一头,另一头的接口也没统一呢。

比如手机接口也不统。一万个手机就有一万个接口,这该有多麻烦。现在安卓和苹果,不能互用充电线,我们都觉得麻烦了,真要一个手机一种接口,那只怕心态崩了。如果没有一个统一的标准,那无论对设备厂商,还是对我们用户来说,都非常痛苦。所以统一标准和制定规范一定是各行各业都需要做也都想做的事情,那这个标准和规范就可以理解为接口。生活中的例子讲完,我们来延申到程序。

每项技术的产生,肯定是有其原因的。理解了技术的诞生经过,一般也就理解了技术本身。

那接口是如何诞生的呢?
image
假设现在是一个没有对象,只有基本数据类型和函数的世界,当我们的数据和函数多了维护起来就越发困难

image

于是我将其中一些有关联性质的数据和函数封装了起来,类和对象就这么诞生了,我只需要创建一个对象就拥有了特定的属性和方法,这些属性和方法都聚合在了一个实例上,维护起来比较方便。可还有一个问题,现在大多数类的属性和方法都差不多,完全没必要每次重新定义

image

于是乎我将这些重复的东西封装到一个类中,其他子类只需要复用它即可,继承就这么诞生了,子类继承父类之后,便拥有了父类的属性和方法,同时可以扩展自己的特性。
image
我们经常指定一个父类然后接收多个子类,在程序执行的时候,能自行发挥各种子类自己的特性,这一机制就是之前讲过的多态,很多时候我们发现父类完全没必要实现所有逻辑,也没必要创建父类对象,因为我们就是想让各种各样的子类来完成不同的逻辑。
image
这时候我们就可以将,父类的方法抽象出来,抽象类就这么诞生了,这里的抽象类其实已经有了标准和规范的意思,抽象方法就可以理解为一个对外的标准,子类就是这些标准的实现方,然后我们会发现,抽象类还不算彻底的抽象,因为它除了抽象方法外,还有成员属性,可我们很多时候,就是想指定一个纯粹的标准,让子类只去实现抽象方法,不想让子类再去继承别的东西。
image

于是乎我们将抽象类更进一步的抽象,接口就这么诞生了,接口只有方法没有成员属性,子类继承接口后,唯一能做的就是重写方法,所以说接口就是一种标准一种规范,它规定号方法模板后,子类都得按照这个来实现。说到这大家应该就能体会到接口在程序中的作用,就是定义方法让子类实现,然后供调用方调用。

映射到生活中子类就是设备厂商,接口调用方就是我们用户,只管使用,而不用操心各个设备的差异,概念性和比喻的东西讲完了,再来讲一讲,接口在程序中的具体运用:当我们想操作多个拥有共性的对象时,就可以用到接口

比如:我想打印一个数据集

    public static void printConllection(Collection collection){
	if(collection == null){
	     return;
	}
	System.out.println("数据数量"+ collection.size())
	System.out.println("数据"+ collection.size())
    }

    public static void main(String[] args){
	printCollection(new ArrayList());
	PrintCollection(new HashSet());
    }

就可以用到Java 的Collection接口,我将方法参数定义成Collection 别人就可以传任何 Collection 的子类进来了,ArrayList 可以,HashSet也可以,根本不用关心,数据是用哪个集合来存储的,Collection 有上百个子类别人爱用哪个用哪个,都不会影响到我的打印逻辑,就好像USB接口定义好后,你插U盘也好,手机充电线也好,这就是我们常说的面向接口开发

抽象类和接口的异同


image

首先我们知道抽象类和接口都是为了将方法进行抽象,然后让子类去实现

    public abstract class Animal{
	public abstract void eat();
   }

    public interface Runnable{
	public abstract void run();
    }

所以可以定义抽象方法就是这者第一个相同点。

在接口诞生中说过,这种类是没有必要创建实例对象的,所以第二个相同点就是不能创建本类对象,只能由子类去实例化子类对象。

两者最为明显的一个差异点,就是子类要扩展它们时使用的关键字不同,称呼不同但本质一样

// 继承抽象类
public class Dog extends Animal{}

// 实现接口
public class Thread implements Runnable {}

然后时抽象类可以去实现接口,而接口只能继承接口,不能继承类

public abstract class Animal implements A{}

public interface Runnable extends A,B,C{}

同时一个类最多只能继承一个父类,但可以实现多个接口。

public abstract class pet extends Animal implements A,B,C {}

所以当我们发现既可以用抽象类也可以用接口时,尽量去选择接口,这样子类的灵活度会更高

image

在接口的诞生我们说过,抽象类更进一步地抽象后就诞生了接口,接口比抽象类更纯粹,因为它没有成员属性,只有方法,子类实现接口后,唯一能做的就是重写方法,不像抽象类,子类继承抽象类后,连带父类的成员属性一起继承了。

  public abstract class Animal {
	protocted String name;

	public abstract void eat();
  }

  public interface Runnable {
	public static final String CRAB = "螃蟹";

	public abstract void run();
  }

抽象类可以定义成员属性,而接口不能定义成员属性,只能定义静态属性,而且只能用final 关键字定义静态常量,不能定义静态变量,接口还没有构造器,可以说是非常的纯粹了。

说白了接口就是一个只有方法和静态常量的类

这里有人可能会疑惑,抽象类都不能被实例化,还要个构造器有啥用,它的用处是限定子类的构造行为。
比如:抽象类可以将构造器定义好几个参数,子类要想实例化则必须想办法传入这几个参数

    public abstract class Animal{
	protected String name;
	protected Animal(String name){
	    this.name=name;
	}

	public abstract void eat();
    }

    class Dog extends Animal{
	public Dog(String name) {
	   super(name);
	}

	@Override
	public void eat() {
	    System.out.println(name + "要开吃了~");
	}
    }

两者异同就说完了,额外说明一些版本之前的差异
其实接口在Java8 之前更加纯粹,那时接口只能定义抽象方法,不能自己实现方法,也不能定义静态方法,到了Java 8才可以定义静态方法以及可以用 default 关键字来实现方法,这里不要死记硬背,一定要去理解 Java 设计者背后的意图,为什么突然在Java 8就加了这个特性呢?因为Java 8 许多原有的接口,新增了很多方法,这些新增的方法会影响到之前的子类如果你继承了某个接口,突然接口新增了一个方法,而你没有去实现,你的子类就会编译失败,为了保证向下兼容性,Java 8就推出了default关键字,被default关键字修饰的方法就不是抽象方法了,也就不会强制要求已有的子类去实现方法,default方法出现后,大家发现还挺好用,就大量在接口中去实现一些默认逻辑,可是一个方法中实现复杂逻辑,就会导致代码难以维护,于是Java 9又推出了一个新特性,那就是能在接口中,定义private 方法,这样就可以将一些内部逻辑拆开了,可以发现越到后面抽象类和接口的差异也就越小。

总结

抽象类(abstract class) 接口(interface)
定义 包含抽象方法的类 主要是抽象方法和静态常量的类
组成 构造器、抽象方法、普通成员方法、成员变量、静态方法、静态常量、常量 静态常量、抽象方法、default 方法、静态方法(Java8)私有方法(Java9)
使用 子类继承抽象类(extends) 子类实现接口(implements)
关系 子类只能继承一个抽象类,抽象类可以实现多个接口 子类可以实现多个接口,接口不能继承类,但可以继承多个接口
选择 如果需要继承父类的成员变量,或需要控制子类的实例化,则选抽象类 优先选择接口,避免单继承的局限性
posted @   卡卡鸡  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示