1.写在前面的话
最近一些刚入门JAVA的读者朋友让我来写一篇有关于抽象类和接口的文章,我当即就答应了,因为抽象类和接口确实是两个很重要但是一时半会又无法完全理解的东西,这篇文章我主要先介绍抽象类、抽象方法、接口以及它两者的应用。所以废话不多说!Let's go !
2. 抽象类和抽象方法
抽象类,它是普通类和接口之间的一种中庸之道。可能大家看了这句话也有点懵,其实简单点说就是抽象类既有普通类的特征又有接口的特征。
我首先给大家上一段代码,然后咱们来细细地谈一谈:
Animal.java
public abstract class Animal { public abstract void say(); public abstract void eat();}
Dog.java
public class Dog extends Animal{ @Override public void say() { System.out.println("汪汪汪!"); } @Override public void eat() { System.out.println("骨头真好吃!"); } }
Cat.java
public class Cat extends Animal{ @Override public void say() { System.out.println("喵喵喵!"); } @Override public void eat() { System.out.println("鱼真好吃!"); }}
上面就是一个很简单的抽象类的实例了,抽象类Animal,我们可以看到它里面的内容,第一感觉是---这有啥用?感觉并没有什么用。那么为什么JAVA要引用抽象类这个概念呢?其实我们观察下面两块代码,这两个类都继承自Animal抽象类,并且我们都去重写了抽象类里面的方法,这个时候我们也许知道它的一丝用意,其实简单粗俗一点讲就是提供给了我们一个模板,我们直接按照那个模板来做就行了,官方一点讲呢,就是不同的子类可以用不同方式表示这个接口,这个就是所谓的抽象类。
我们来思考一下,如果我们只有Animal这一个抽象类那可咋办(没有子类),还能咋办,就是这个类的对象没有什么意义了,我们也无需去管它了,因为没有人想去用它的模板。
抽象类也被大家称作不能被初始化的类,编译器是不会允许你有这种操作的,也就是说你创建了抽象类,你就只能通过子类去继承它的这种方式来利用这个抽象类,而不能是我们通常的new初始化。总的来说抽象类除了被继承过之外,是没有用途、没有值、没有目的的。
public abstract class Animal { public abstract void say(); public abstract void eat();}
我把上面的代码搬了下来,目的是为了介绍一下抽象方法,简单点说,抽象方法仅仅只有声明而没有方法体。包含有抽象方法的类一定是抽象类。当我们的子类继承了抽象类之后,编译器会强制我们实现所有抽象类中的抽象方法的方法体。
3. 接口这个东东
interface这个关键字让抽象类的概念更向前迈进了一步,粗俗的讲接口就是比抽象类还要抽象的东西。interface这个关键字产生的是一个完全抽象的类,它根本就没有提供任何的具体实现。它允许创建者去确定它的方法名、参数列表、返回类型,但是没有任何的方法体。接口它仅仅只是提供一个形式,而未提供任何具体实现。
当我们去使用接口时,我们会发现实现该接口的类看起来都是一个样,所以接口可以当做类和类之间的一个协议。创建一个接口只需要把class关键字换成interface关键字就行了。实现接口就通过implements关键字。
咱们还是来看看代码:
AnimalImpl.java:
public interface AnimalImpl { void say(); void eat();}
CatImpl.java:
public class CatImpl implements AnimalImpl{ @Override public void say() { System.out.println("喵喵喵!"); } @Override public void eat() { System.out.println("鱼真好吃!"); }}
DogImpl.java:
public class DogImpl implements AnimalImpl{ @Override public void say() { System.out.println("汪汪汪!"); } @Override public void eat() { System.out.println("骨头真好吃!"); }}
看起来这个和上面的抽象类差不多,但是这里面还是有很多的知识点。我们可以在接口中显式地将方法声明为public的,但是即使你不这么做,它们也是public的。因此,我们要实现一个接口时,在接口中被定义的方法必须被定义为是public的;否则,它们将只是得到默认的包访问权限,这样在方法被继承的过程中,其可访问权限就被降低了,这样就会报错。
4. 两者的区别有哪些?
- 接口是抽象类的变体,接口比抽象类更加抽象,接口中所有的方
法都是抽象的。
- 每个类只能继承一个抽象类,但是可以实现多个接口
- 抽象类中不一定都是抽象方法,抽象的而抽象类可以实现部分方法。但是接口中方法必须为public修饰的、抽象的不能实现具体的法。
- 接口中基本数据类型为static 而抽象类不是的。
- 抽象类中不一定都是抽象的方法,也可以有具体实现的方法,这样就可以把大家公用的方法提升到抽象类中,然后具体的方法可以留给子类自己实现(此处经典的应用,模板方法设计模式)。所以抽象类可以更好的实现代码的复用
JAVA中,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口、走路接口)。
当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。