抽象类:小样儿(接口),我一眼看出你就不是人(抽象类)(二)

简介: 抽象类:小样儿(接口),我一眼看出你就不是人(抽象类)

接口的特点:


接口一般是通过interface关键字来定义的,一个简单的接口定义就如下面的代码一样:


public interface advice {
}


上面的接口是一个最简单的接口.往往我们的接口里面会包含很多的函数,就比方下面这个例子:


20210223145135470.png


并且在这个接口里面我们不仅能够看到有多个函数,同时该接口里面还有自定义的变量.


这里还要提醒大家一点的就是:因为这里面不管是方法还是变量都是只通过public来进行修饰的,所以大家可能本能的就认为这些方法以及变量就是公开的,其实并不是这样的,接口里的所有方法其实都是抽象方法,接口里的所有变量也其实都是通过static final关键字来修饰的.这里我们可以通过查看类的结构就可以看到,就如下图所示:


20210223160758755.png


大家其实仔细看变量名以及方法名的上面都是有字母的,其实大家现在想想应该能知道那些字母分表代表什么意思了.


SF就代表static final

A就代表abstract


所以并不是我们所想象的那样,知道了方法都是抽象方法了之后,大家这时候结合我们上面所讲的抽象方法的概念,大家应该也能基本了解接口中方法的特点了.方法我们理解完了,那现在我们再来讲讲接口中的变量吧.大家知道的,既然接口中的变量已经通过static final修饰了那么就以为着这个变量是无法重新进行赋值的,相当于是一个值已经恒定的变量了.

就如同我下面图里面所演示的一样:


20210224092324425.png


这里可以给大家看一下错误的提示信息:


The final field advice.length cannot be assigned


意思就是我们上面讲的意思.所以一般在开发中是不在接口中定义变量的,如果需要在接口中定义变量并且来使用的话,那么很明显这个变量在项目中就是担当一个常量的作用.


其次我们在来看看我们在类中都是如何使用接口的:


我们都是通过implements关键字来实现我们的接口的.从上面的图中我们也可以看到如果一个类要使用接口的,那么就和一个类要继承抽象类一样,那么都是必须要实现该接口或者是抽象类中抽象方法的,否则也是会报错的.并且我们允许一个类可以实现多个接口,就如下图所示:


20210225185529154.png


最后我们总结一下接口的特点有哪些:


接口必须通过interface关键字来修饰


接口中的方法都是抽象的,并且即使是变量也是无法更改的.


使用接口的类必须实现接口中的所有方法


一个类可以实现多个接口,并且需要实现这些接口中的所有方法.


到这里我们基本上就已经了解了抽象类以及接口的基本特点了.那么接下来就是我们的重点了:他们两者之间到底什么样的关系呢?让我们接着往下看.


抽象类与接口的区别


如果上面的内容你都已经认真看过之后,不知道大家是否会有这样的疑问:抽象类和接口真的好像啊,都有抽象方法,一般的类继承抽象类或者是实现接口的时候,同样都需要实现他们两者的抽象方法.


当初我看网上的文章基本都没有说到他们的内核问题上面,所以当时自己一直都有这样的疑惑.所以不知道大家有没有这样的疑惑.如果有的话,就请继续看我下面的内容,相信一定可以给你一个很好的解答.


首先我们的确需要承认的就是其实接口的确就是从抽象类中分离出来的,所以接口很有很多抽象类的特征.所以大家才会觉得接口与抽象类非常的相似.但是他们两者适用的的范围其实是不一样的.接口从抽象类中分离出来,肯定不是为了实现和抽象类同样的功能的.接下来我们详细的来讲解.


上面我们说过了抽象类是所有具体的个体类所共有的特征,所以我们是不是可以用下面的图来描述个体类与抽象类的关系呢,看下图:


20210226105644828.png


从上面的图我们基本能得出这样的结论:抽象类与个体类是从属的关系.而且我们之前说过个体类实现抽象类的时候说的是继承,通过继承这个关键词大家也能够理解为什么是从属关系了.看完抽象类与个体类的关系之后我们再来看看接口与我们类的关系.


上面我们讲解接口的时候曾经说过,接口时用来扩展我们的系统或者是程序的.所以接口和我们的类的关系是不是可以用下面的图来描述呢,如下图:


20210226115947250.png


从上图中我们就既可以看出来接口和我们的个体类的关系是需不需要的关系.如果一个个体类本身就应该有这个功能,那么很显然我们就需要为这个类实现相应的接口并且上面我们也说过一个类是可以实现多个接口的,正就刚好表现了需不需要的概念.只要我想,我就可以全都需要.


20210226113346488.gif


这就是抽象类与接口的第一个区别.为了方便大家更好的理解这个概念.我们还是举上面我们关于狗的例子.


现在我们我们现在有两个抽象类分别为Dog:


public abstract class Dog {
  public abstract void eat();
  public abstract void wang();
  public abstract void sleep();
}

Cat:

public abstract class Cat {
  public abstract void eat();
  public abstract void miao();
  public abstract void sleep();
}


假设我们需要创建一个Husky(哈士奇)的类,那么首先我们就需要先选择我们该将这个类继承上面我们定义的那个抽象类呢?很明显Husky是属于Dog的而并不是属于Cat的范畴.所以这一步不仅解释了抽象类与个体类是从属的关系,并且还解释了类只能继承一个抽象类.


接下来我们继承完相应的抽象类之后,我们首先就需要先实现抽象类中的抽象方法,代码如下:


public class Husky extends Dog{
  @Override
  public void eat() {
    // TODO Auto-generated method stub
    System.out.println("邋里邋遢哈士奇,到处拆家惹人厌");
    System.out.println("吃饭?没空吃饭,拆家呢!");
  }
  @Override
  public void sleep() {
    // TODO Auto-generated method stub
    System.out.println("睡觉?家还没拆完,睡什么觉!");
  }
  @Override
  public void wang() {
    // TODO Auto-generated method stub
    System.out.println("呜呜呜....呜呜呜呜呜呜.....");
  }
}


这些就是我们哈士奇的基本特征吗,很显然哈士奇和其他的狗有一个基本的区别就是哈士奇会:


20210226140102829.gif


所以很显然这是哈士奇的一个最明显的特征同时也是哈士奇一定会的一项技能,所以我们需要为哈士奇这个类扩展这个功能,所以这时候我们就创建一个叫做DestroyHome的接口:


public interface DestroyHome {
  void destroyhome();
}

这时候我们重新让Husky实现这个接口:

public class Husky extends Dog implements DestroyHome{
  @Override
  public void eat() {
    // TODO Auto-generated method stub
    System.out.println("邋里邋遢哈士奇,到处拆家惹人厌");
    System.out.println("吃饭?没空吃饭,拆家呢!");
  }
  @Override
  public void sleep() {
    // TODO Auto-generated method stub
    System.out.println("睡觉?家还没拆完,睡什么觉!");
  }
  @Override
  public void wang() {
    // TODO Auto-generated method stub
    System.out.println("呜呜呜....呜呜呜呜呜呜.....");
  }
  @Override
  public void destroyhome() {
    // TODO Auto-generated method stub
    System.out.println("你还想有家?我给你全拆光");
  }
}


到这里我们关于Husky 就基本上编写完毕了.在这个过程中大家可以更加的理解抽象类是一个属不属于的问题,接口是一个需不需要的问题.


其次就是在代码的编写上面,虽然两者本质上都是抽象的,但是抽象类属于是显式抽象,接口属于是隐式抽象.这个很好理解.抽象类的一个硬性条件就是必须要有abstract关键字的修饰,而接口则不需要我们将abstract这个关键字显示的编写在我们的类以及方法名的前面.


接着就是在设计模式的层面上,还是像我们上面说的那样,抽象类是所有具体个例都抽象出来的所有具体个例所拥有的统一的类.意思就是具体个例的一般性行为,抽象类中都会有.还是拿我们的狗来举例:


世界上有很多种类的狗,有金毛,边牧,拉布拉多,哈士奇等,他们的行为一定会因为品种的问题存在着很大的差异,就比如说哈士奇,他的拆家属性肯定是点满了的.但是呢这些不同种类的狗都会有狗的一些共性,就比如说吃,喝,睡觉.这些行为都是狗的一些共性,所以我们就可以直接在Dog这个抽象类里面直接定义这些方法,然后这些个例只需要继承抽象类实现这些方法即可.不用在单独在每个类里面再创建这些行为,再实现.就好比下图所示:


20210226144203917.png


所以说抽象类就像是一个模板,他是所有具体个例的母版.所有的具体个例都会模仿抽象类的行为.并且假设所有的个例的某个行为都发生了变化,那么我们就只需要通过修改模版即抽象类即可解决问题.


但是接口和抽象类却有所不同.就像我们上面说的一样,接口是用来扩展我们的系统或者程序的,说以很显然接口属于是一种个性化定制服务,所接口一旦发生了改变的话,那么很显然只要是实现了该接口的类就全部需要进行修改.就比方下图演示的过程:


image.png


假设现在我们把接口中的play方法删掉了,改成了amuse方法,那么很显然所有只要实现了这个该接口的类都需要删掉play方法,并且实现amuse方法,入下图所示:


20210226160114248.png


所以很显然接口属于是一种辐射状的设计,属于是一点向多点的扩散.这和我们的抽象类恰恰相反.但是不知道大家有没有想过是什么原因造成了这样的状况呢?


其实这个问题是很简单的.大家还记不记得我们上面讲过的.抽象类中即可以包含抽象方法,同时也可以包含一般方法.相反的接口中的方法默认都是抽象方法.正因为抽象类中可以存在一般方法,所以抽象类可以直接修改本身的方法而不需要在修改其他继承该抽象类中的方法.接口就不行了,因为全是抽象方法,所以一旦需要修改就只能修改每一个类中的方法.


最后我们总结一下抽象类与接口的区别:


抽象类是显式抽象,接口是隐式抽象

抽象类中既可以有抽象方法,也可以有一般方法,但是接口中的方法默认都是抽象的

抽象类解决的是"是不是"的问题,接口解决的是"有没有"的问题

一个类只能继承一个抽象类,但是能实现多个接口

最后的最后我们还是通过一个例子来帮助我们收官.网上经常讲的例子就是防盗门,但是我们本片文章一直再举狗的例子,所以最后一个例子我们还是来举狗的例子


20210226160953798.jpg


好了话不多少,正式开始我们最后一个例子:

假设我们需要定义一个叫做Husky(哈士奇)的类,这个类现在需要实现这么几个功能:吃饭,睡觉,喝水,拆家,发疯.如何通过抽象类Dog或者接口Behavior来实现呢?


这里假设我们将所有的方法都定义在了抽象类Dog中.代码如下:

public abstract class Dog {
  public abstract void eat();
  public abstract void sleep();
  public abstract void drink();
  public abstract void destoryhome();
  public abstract void crazy();
}


很明显我们值需要通过让我们的Husky继承该抽象类并且实现里面的抽象方法就行了.代码如下:

public class Husky  extends Dog{
  @Override
  public void eat() {
    // TODO Auto-generated method stub
  }
  @Override
  public void sleep() {
    // TODO Auto-generated method stub
  }
  @Override
  public void drink() {
    // TODO Auto-generated method stub
  }
  @Override
  public void destoryhome() {
    // TODO Auto-generated method stub
  }
  @Override
  public void crazy() {
    // TODO Auto-generated method stub
  }
}


这样很显然也能够直接完成我们的目标,但是这里会有一个问题那就是当我们创建其他的狗的品种类时,就比如金毛,边牧的时候,很明显我们也是需要去继承Dog这个抽象类的,但是这时候我们会发现,这个抽象类中的两个方法是多余的,因为金毛和边牧基本上不会拆家,发疯,所以很明显这两个函数就是多余的.只要继承了这个抽象类,那么就必须要是实现这两个方法.所以虽然这种方案可以完成我们的任务,但是很明显不利于我们之后项目的扩展.


这时候有小伙伴可能会说,那我们直接在接口中定义这些方法不就行了.大家想一想就会发现,其实会出想我们上面遇到的同样的问题.


不知道大家这时候是不是已经有思路了呢.这时候结合我们上面所说的.抽象类是所有个例的共性,接口属于是个性化定制的范畴.看到这两句话,相信大家已经有了答案. 最好的方案应该是这样设计:

Dog抽象类:

public abstract class Dog {
  public abstract void eat();
  public abstract void sleep();
  public abstract void drink();
}


Behavior接口:


public interface Behavior{
     void destoryhome();
   void crazy();
}


最后我们的Husky只需要这样继承Dog抽象类以及实现Behavior接口即可,代码如下:

public class Husky  extends Dog implements Behavior{
  @Override
  public void eat() {
    // TODO Auto-generated method stub
  }
  @Override
  public void sleep() {
    // TODO Auto-generated method stub
  }
  @Override
  public void drink() {
    // TODO Auto-generated method stub
  }
  @Override
  public void destoryhome() {
    // TODO Auto-generated method stub
  }
  @Override
  public void crazy() {
    // TODO Auto-generated method stub
  }
}


这样当我们创建其他类继承Dog的时候吧就不用再去是此案那两个多余的方法了.并且接口也是定制化,适用于所有包含拆家以及发疯的动物.这样就能醉倒更好的扩展我们的程序了.


到这里我们关于抽象类以及接口的讲解就已经全部讲解完毕了,如果觉得文章不错或者觉得UP写的还可以的话,可以关注我的公众号:萌萌哒的瓤瓤.


相关文章
|
23天前
抽象类和接口在实现多态时的区别
【10月更文挑战第19天】抽象类和接口在实现多态时都有其独特的作用。抽象类更适合用于定义一些具有共同特征和部分实现的类,而接口则更强调定义一组行为规范,以便不同的类可以实现并组合这些行为。
52 10
|
2月前
|
Java
接口和抽象类【Java面向对象知识回顾②】
本文讨论了Java中抽象类和接口的概念与区别。抽象类是不能被实例化的类,可以包含抽象和非抽象方法,常用作其他类的基类。接口是一种纯抽象类型,只包含抽象方法和常量,不能被实例化,且实现接口的类必须实现接口中定义的所有方法。文章还比较了抽象类和接口在实现方式、方法类型、成员变量、构造方法和访问修饰符等方面的不同,并探讨了它们的使用场景。
接口和抽象类【Java面向对象知识回顾②】
|
4月前
|
Java 编译器
Java面向对象(三)详解: 封装 | 继承 | 方法重写 | 抽象类
Java面向对象(三)详解: 封装 | 继承 | 方法重写 | 抽象类
|
6月前
|
存储 Java
【面试问题】接口和抽象类有什么区别?
【1月更文挑战第27天】【面试问题】接口和抽象类有什么区别?
|
编译器
抽象类的学习与总结
抽象类的学习与总结
|
Java
Java面向对象—抽象类和接口
Java面向对象—抽象类和接口
105 0
|
Java
Java面向对象之抽象类与接口
抽象类的使用原则如下: (1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),默认为public; (2)抽象类也有构造器 (3)抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理; (4)外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称 (5)有时候由于抽象类中只需要一个特定的系统子类操作,所以可以忽略掉外部子类。这样的设计在系统类库中会比较常见,目的是对用户隐藏不需要知道的子类
93 0
|
传感器 Java
抽象类:小样儿(接口),我一眼看出你就不是人(抽象类)(一)
抽象类:小样儿(接口),我一眼看出你就不是人(抽象类)
抽象类:小样儿(接口),我一眼看出你就不是人(抽象类)(一)
抽象类代码
抽象类代码
73 0
笔记12-多态&抽象类&接口
笔记12-多态&抽象类&接口