抽象类
如果一个类不能描绘一个具体的对象,那么这个类就是抽象类。
先来看下面这个例子:
虽然 Animal 类中有 eat 方法,但是 Animal 的范围太广,不知道吃啥,所以不能具体实现 eat 的方法,所以可以将 Animal 类设计成抽象类,而 Dog 类,Cat 类和 Bird 类都可以具体实现 eat 方法(狗吃骨头、猫吃鱼、鸟吃虫子)。
像上面这个例子中,Animal 类中的 eat 方法没有具体实现什么功能,我们就可以把它设计成抽象方法,包含抽象方法的类称为抽象类。
语法说明:
如果一个类被 abstract 修饰,那么这个类就是抽象类,抽象类中的方法被 abstract 修饰,那么这个方法就是抽象方法,抽象方法不用给出具体的实现细节(包括大括号)。例如下面这个类:
注意:抽象类中也可以包含普通方法、属性、构造方法。
抽象类特点:
- 抽象类不能实例化
- 抽象方法不能是 private 的
- 抽象方法不能被 final 和 static 修饰。 抽象方法需要子类重写,而 final 修饰的方法不能被重写,所以 abstract 和 final 不能同时使用。static 修饰的方法属于该类本身的,而这个方法又没有方法体,通过类再调用这个方法就会报错,所以 abstract 和 static 也不能同时使用。
- 抽象类被继承后,子类需要重写父类中的抽象方法,除非子类也是抽象类。如果子类也是抽象类,那么抽象子类的子类就要重写父类的抽象方法。
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。换句话说,一个方法是抽象方法,那么这个方法所在的类必须设置成抽象类。
- 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量。
可能看到这里还不清楚抽象类有什么用,功能和普通类都差不多。
其实抽象类的作用就是,当一个类继承了抽象类,那么这个类就知道它需要重写父类中的抽象方法,如果不重写,就会报错。而继承了普通类,子类不重写父类的方法,并不会报错,所以使用抽象类就相当于多一道保障。
接口
接口,在生活中是很常见的,比如插座,不管是冰箱还是电视,只要能插就能用。还有电脑上的 USB 接口,不管是鼠标还是键盘,同样能插进去就能用。上面的插座和 USB 接口,都是有一定的规范,所以接口就是公共行为的规范标准,只要符合这个标准,就是通用的。而 Java 中的接口是多个类的公共规范,是一种引用数据类型。
接口定义:
接口的定义和类的定义很像,将 class 关键字换成 interface 关键字即可。下面是接口声明的一个简单例子。
public interface 接口名称 {
// 抽象方法
public abstract void func1();
// public abstract 是固定搭配,可以不写,也就是 func1和func2是一样的
void func2();
...
}
接口使用:
接口并不能直接使用,需要一个类来实现(使用 implements 关键字)该接口,实现接口中的所有抽象方法。注意:implements 关键字放在 class 声明后面。
public class 类名称 implements 接口名称[, 其他接口名称, 其他接口名称..., ...]{
}
下面来看一个简单的例子:
注意事项:
- 接口类型是一种引用类型,但是不能直接实例化接口的对象。
如上面的 Animal 接口,语句 Animal animal = new Animal(); 将会报错。 - 接口中的方法默认都是 public abstract,可以不用写。
- 接口中的方法不能在接口中实现的,只能由实现接口的类来实现。因为接口里的方法是抽象方法,抽象方法不能有方法体。
- 重写接口中的方法时,不能使用默认的访问权限。
- 接口中如果有变量,那么就默认被 public static final 修饰(被 final 修饰,那么就需要指定初始值)。
- 接口中不能有构造方法和代码块。
实现多个接口
在 Java 中,一个类只能继承一个类,但是可以实现多个接口。
我们先提供几个接口分别来表示 飞、跑、游泳。
再创建几个类来实现这些接口:让狗类实现跑和游泳的接口,让鸭子实现上面三个接口( 飞、跑、游泳)。
Dog类:
Duck类:
运行效果:
使用接口的好处就是我们不用关心类的具体类型,只注意这个类是否拥有接口里的功能。所以我们要想让狗具有飞的功能的话,就让狗实现飞的接口,这样狗就具有飞的功能了。
接口的多继承
在 Java 中,类的多继承是不合法,但接口允许多继承。例如:
interface Ifunc2 extends IRun,ISwim{
}
此时一个类实现 Ifunc2 接口的话,就需要重写 IRun 和 ISwim 里的方法。
public class Frog implements Ifunc2 {
@Override
public void run() {
}
@Override
public void swim() {
}
}
抽象类和接口的总结
- 抽象类可以包含普通方法,这些普通方法子类可以不用重写直接使用,而接口不能包含普通方法,子类需要重写接口里的方法。
- 抽象类里的普通方法可以提供方法的实现细节,而接口中只能存在public abstract 方法(JDK1.8以后允许有 default 和 static 修饰的方法)。
- 一个子类只能继承一个父类,但是可以实现多个接口,一个接口也能继承另一个接口。
- 抽象类表示的是一种 is-a 关系(Dog is an …),而接口表示一种 has-a 关系(Dog has a …)。
注意: 如果几个类都有共同的方法,并且这个方法有一定的功能,我们就可以使用抽象类(抽象类里的普通方法可以有具体的实现)。如果想实现多重继承,我们就要使用接口,抽象类和接口之间有很多相似的地方,需要不断积累,才能选择出合适的。