首先还是先重温一下抽象类和接口的区别:
接口
接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。
我们以JDK中提供了另一个序列化接口--Externalizable为例。
public interface Externalizable extends Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
public class Employee implements Externalizable {
//注意这种序列化必须自己实现构造方法
public Employee () {
System.out.println("none-arg constructor");
}
int employeeId;
String employeeName;
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
employeeId = in.readInt();
employeeName = (String) in.readObject();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(employeeId);
out.writeObject(employeeName);
}
}
抽象类
抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
// abstract method
abstract void service(ServletRequest req, ServletResponse res);
void init() {
// Its implementation
}
// other method related to Servlet
}
public class HttpServlet extends GenericServlet {
void service(ServletRequest req, ServletResponse res) {
// implementation
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// Implementation
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
// Implementation
}
// some other methods related to HttpServlet
}
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | jdk1.8之前没有,现在可以使用default关键字创在interface中创建一个default方法,该方法包含了具体的实现代码,一个接口中可以有多个default方法 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有抽象的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的非default方法的实现 |
构造器 | 抽象类可以有构造器 | 接口没有构造器 |
实例化 | 不能 | 不能 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。在java9以后可以用private定义私有方法,私有方法必须包含方法体。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
继承 | 单一继承 | 多继承 |
访问速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | jdk1.8以后可以添加了,也就是说有一些在接口设计上的顽疾现在有了完美解决的方法 |
通过以上对比抽象类的使用场景被削减,那么什么时候还需要使用抽象类
1、需要构造方法。
2、独立运行。
3、定义final方法防止子类篡改。
在使用抽象类时需要注意几点:
1、抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可。
2、抽象方法必须由子类来进行重写。
3、只要包含一个抽象方法的抽象类,该类必须要定义成抽象类。
4、抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
5、子类中的抽象方法不能与父类的抽象方法同名。
6、abstract不能与final并列修饰同一个类。
7、abstract 不能与private、static、final或native并列修饰同一个方法。
在使用接口过程中需要注意如下几个问题:
1、Interface的所有方法访问权限自动被声明为public。在java9以后可以定义私有方法,但是必须有方法体不能是抽象方法。
2、接口中可以定义“成员变量”,或者说是不可变的常量,因为接口中的“成员变量”会自动变为为public static final。可以通过类命名直接访问:ImplementClass.name。
3、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof Comparable){}。
4、在实现多接口的时候一定要避免方法名的重复,尤其是default方法。
5、接口里的方法不能用final修饰
public interface SimpleInterface {
public void doSomeWork();
//A default method in the interface created using "default" keyword
//使用default关键字创在interface中直接创建一个default方法,该方法包含了具体的实现代码
default public void doSomeOtherWork(){
getStu();
System.out.println("DoSomeOtherWork implementation in the interface");
}
static void getStatic() {
System.out.println("static method");
}
default public void doSomeOtherWork2(){
getStu();
//私有静态方法用于为接口中的默认方法服务
getStatic1();
System.out.println("DoSomeOtherWork2 implementation in the interface");
}
//java9中可以创建私有方法了
private void getStu() {
System.out.println( "private method!");
}
//java9中可以创建私有静态方法了
private static void getStatic1() {
System.out.println("private static method");
}
}
class SimpleInterfaceImpl implements SimpleInterface{
@Override
public void doSomeWork() {
System.out.println("Do Some Work implementation in the class");
}
@Override
public void doSomeOtherWork() {
System.out.println("Do doSomeOtherWork implementation in the class");
}
/*
* Not required to override to provide an implementation
* for doSomeOtherWork.
* 在SimpleInterfaceImpl里,不需要再去实现接口中定义的doSomeOtherWork方法
*/
public static void main(String[] args) {
SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
simpObj.doSomeWork();
simpObj.doSomeOtherWork();
simpObj.doSomeOtherWork2();
SimpleInterface.getStatic();
}
}
···