文章目录
- 一、抽象类
- 二、接口类
- 三、接口与抽象类的区别
- 1.相同点
- 2.不同点
- 3.设计目的的差别
- 四、抽象类和接口的应用场景
- 1. 抽象类的应用场景
- 2. 接口的应用场景:
- 3. 什么时候使用抽象类和接口:
一、抽象类
在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称为抽象方法,抽象方法只有方法的声明,没有方法体。抽象类的特点:
- 抽象类不能被实例化只能被继承;
抽象类是一种特殊的类,与类的区别只是抽象类不能被实例化,既然不能被实例化( Person p = new Person (); ),所以抽象类必须被继承,才能被使用。 抽象类也可以和类一样,实现接口、多接口等,但抽象类区别于类,不需要实现接口下的所有方法。 用途: 例如需要一个类,但是不需要有具体执行的代码,那么就可以把这个类写成抽象类。 抽象类(Persion)被子类(Man)继承后,就会强迫子类重写抽象类中定义的抽象方法,除非子类也是抽象类。 接口不是类,它由关键字interface声明,既然不是类,那接口就需要有自己的书写规范,也可以说“接口就是个规范”。 深层次的问题:为啥要用接口,除了多态的理论,其它的我这里暂时无法解释,因为我还接触不到
- 包含抽象方法的一定是抽象类,但是抽象类不一定含有抽象方法;
public abstract class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Student extends Person {
// Person person = new Person();//抽象类不能new实例化
public Student() { //通过子类继承,调用抽象父类的无参构造函数
// super();
}
public Student(String name, int age) {//通过子类继承,调用抽象父类的有参构造函数
super(name, age);
}
}
public class AbstractDemo {
public static void main(String[] args) {
Student student = new Student("张三", 24);
System.out.println(student.getName());
student.setAge(20);
System.out.println(student.getAge());
}
}
- 抽象类中的抽象方法的修饰符只能为public或者protected,默认为default;
- 一个子类继承一个抽象类,则子类必须实现父类抽象方法,否则子类也必须定义为抽象类;
public abstract class Parent {
void eat() {
}
abstract void run() ;
}
public class Son extends Parent{
}
- 抽象类可以包含属性、方法、构造方法,但是构造方法不能用于实例化,主要用途是被子类调用。
public abstract class Parent {
public String color = "黑色";
public Parent() {
System.out.println(color);
}
void eat() {
System.out.println("父亲在吃饭");
}
abstract void run() ;
}
public class Son extends Parent{
public static void main(String[] args) {
Son s1 = new Son();
s1.eat();
}
@Override
protected void run() {
// TODO Auto-generated method stub
}
}
Java代码行执行顺序: 1.静态块:用static声明,JVM加载类时执行,仅执行一次 2.构造块:类中直接用 {}定义,每次创建对象时执行 3.执行顺序优先级:静态块>main ()>构造块>构造方法 4.静态块和静态属性优先执行,谁在前先执行谁。
父类静态代码块》子类静态代码块》父类构造代码块》父类构造器》子类构造代码块》子类构造器
二、接口类
Java中接口使用interface关键字修饰,特点为:
-
接口可以包含变量、方法;变量被隐士指定为public static final,方法被隐士指定为public abstract(JDK1.8之前);
-
接口支持多继承,即一个接口可以extends多个接口,间接的解决了Java中类的单继承问题;
-
一个类可以实现多个接口;
-
JDK1.8中对接口增加了新的特性:
(1)、默认方法(default method):JDK 1.8允许给接口添加非抽象的方法实现,但必须使用default关键字修饰;定义了default的方法可以不被实现子类所实现,但只能被实现子类的对象调用;如果子类实现了多个接口,并且这些接口包含一样的默认方法,则子类必须重写默认方法;
(2)、静态方法(static method):JDK 1.8中允许使用static关键字修饰一个方法,并提供实现,称为接口静态方法。接口静态方法只能通过接口调用(接口名.静态方法名)。
抽象类可以有默认的方法实现完全是抽象的。 接口根本不存在方法的实现。 抽象类中可以有已经实现了的方法,也可以有被abstract修饰的方法(抽象方法),因为存在抽象方法,所以该类必须是抽象类。 但是接口要求只能包含抽象方法,抽象方法是指没有实现的方法。
三、接口与抽象类的区别
1.相同点
- 接口和抽象类都不能被实例化,主要用于被其他类实现和继承。
- 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。
2.不同点
-
接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
-
实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
-
接口强调特定功能的实现,而抽象类强调所属关系。
-
接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。
3.设计目的的差别
但接口和抽象类之间的差别非常大,这种差别主要体现在二者设计目的上。下面具体分析二者的差别。
-
接口作为系统与外界交互的窗口,接口体现的是一种规范。对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务(以方法的形式来提供);对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务(就是如何来调用方法)。当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。
从某种程度上来看,接口类似于整个系统的“总纲”,它制定了系统各模块应该遵循的标准,因此一个系统中的接口不应该经常改变。一旦接口被改变,对整个系统甚至其他系统的影响将是辐射式的,会导致系统中大部分类都需要改写。
-
抽象类则不一样,抽象类作为系统中多个子类的共同父类,它所体现的是一种模板式设计。抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能(那些已经提供实现的方法),但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同方式。
参数 | 抽象类 | 接口 |
---|---|---|
实现 | 子类使用 extends 关键字来继承抽象类,如果子类不是抽象类,则需要提供抽象类中所有声明的方法的实现。 | 子类使用 implements 关键字来实现接口,需要提供接口中所有声明的方法的实现。 |
访问修饰符 | 可以用 public、protected 和 default 修饰 | 默认修饰符是 public,不能使用其它修饰符 |
方法 | 完全可以包含普通方法 | 只能包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现 |
变量 | 既可以定义普通成员变量,也可以定义静态常量 | 只能定义静态常量,不能定义普通成员变量 |
构造方法 | 抽象类里的构造方法并不是用于创建对象,而是让其子类调用这些构造方法来完成属于抽象类的初始化操作 | 没有构造方法 |
初始化块 | 可以包含初始化块 | 不能包含初始化块 |
main 方法 | 可以有 main 方法,并且能运行 | 没有 main 方法 |
与普通Java类的区别 | 抽象类不能实例化,除此之外和普通 Java 类没有任何区别 | 是完全不同的类型 |
运行速度 | 比接口运行速度要快 | 需要时间去寻找在类种实现的方法,所以运行速度稍微有点慢 |
一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补 Java 单继承的不足。
四、抽象类和接口的应用场景
1. 抽象类的应用场景
- 父类只知道其子类应该包含怎样的方法,不能准确知道这些子类如何实现这些方法的情况下,使用抽象类。
- 从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,从而避免了子类设计的随意性。
2. 接口的应用场景:
- 一般情况下,实现类和它的抽象类之前具有 “is-a” 的关系,但是如果我们想达到同样的目的,但是又不存在这种关系时,使用接口。
- 由于 Java 中单继承的特性,导致一个类只能继承一个类,但是可以实现一个或多个接口,此时可以使用接口。
3. 什么时候使用抽象类和接口:
- 如果拥有一些方法并且想让它们有默认实现,则使用抽象类。
- 如果想实现多重继承,那么必须使用接口。因为 Java 不支持多继承,子类不能继承多个类,但可以实现多个接口,因此可以使用接口。
- 如果基本功能在不断改变,那么就需要使用抽象类。如果使用接口并不断需要改变基本功能,那么就需要改变所有实现了该接口的类。