抽象(Abstraction)
抽象意味着只需要开发类的接口和功能声明,而不需要实现具体的实施细节。抽象类呈现的是接口,而不需要具体实现,将对象的实施与行为或实现分离开来,进而通过隐藏无关的细节来减少复杂度。
优点
- 通过使用抽象,我们可以将不同类别的东西分离开来;
- 经常需要修改的属性和方法可以被分离出来形成一个单独的类别,而那些主要留下的部分就不需要进行修改了,进而增强面向对象的分析与设计(OOAD)原则,即“代码应该易于扩展,而不应该经常修改”;
- 简化领域模型的表征。
抽象和封装的区别:
封装作为一种策略,被用作广义抽象的一部分。封装是与对象状态相关的——对象将自己的状态封装起来并对外界不可见,类外部的用户只能通过该类的方法来与其进行交互,但不能直接改变其状态。因此,类可以将与状态相关的实施细节通过抽象隔离开来。
抽象是一个更泛化的概念,可以通过子类来实现具体的功能。例如:在Java标准库中,List是“一串事物”的抽象,ArrayList和LinkedList是List的两个具体的类型,作用于抽象List的代码同样抽象地不指明具体所使用的List类型。
如果没有通过封装隐藏底层状态,也就不可能进行抽象处理。也就是说,如果一个类的内部状态全部都是公开的,内部功能无法被更改,该类也就无法进行抽象。
什么是抽象类和抽象方法?
抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。
在程序设计过程中,你希望基类只是其派生类的一个接口,也就是说,你不希望任何人能实例化该基类。你只是想隐式(可以实现多态性)地提出它,以便可以使用它的接口。那么你可以使用abstract关键字来定义一个抽象类。
为该抽象类设定一些限制,所有使用该抽象类的子类都必须实现其中的抽象方法,并提供多态性。
抽象类中可以既包括抽象方法和具体方法,如果一个方法是抽象方法,其所在的类必须被声明成抽象类。反之不然,如果一个类是抽象类,其中不一定包括抽象方法。
如果一个方法只提供了方法签名,但没有被具体实现,则这个方法是一个抽象方法,该方法的具体实现是在扩展该抽象类的子类中进行的。
抽象方法不能被实例化,其他类只能扩展它。
什么时候使用抽象类?
抽象类定义了一些默认的行为,而将具体的功能留给子类来实现。
例如:List是一个接口,而抽象类AbstractList提供了List的默认方法,这些默认方法可以被子类ArrayList继承或重新定义。
例如:Spring的依赖注入就使得代码实现了集合框架中的接口原则和抽象实现。
接口
接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。接口只是一种形式,接口自身不能做任何事情。
什么时候使用抽象类和接口
- 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
- 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
- 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
Java8中的默认方法和静态方法
Oracle已经开始尝试向接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。现在,我们可以为接口提供默认实现的方法了并且不用强制子类来实现它。这类内容我将在下篇博客进行阐述。
使用接口的优点
- 多重继承;
- 能对操作进行松耦合的抽象,可以分离实现任何功能, JDBC, JPA, JTA等等;
- 开发接口而不需要具体实现;
- 使用动态绑定的多态——揭示一个对象的编程接口,而无需展现其具体的实现细节;
- 抽象层:分离问题。
接口和抽象类之间的区别
- 接口是一种协议,要实现接口的类需要根据接口中定义地来实现接口,它只是一个提供了方法声明的空壳;
- 抽象类定义了一些通用方法,其子类可以定义新的具体或特殊的方法;
- 抽象类中的方法和参数可以被定义成任何可见性的,而接口中的所有方法必须由public可见性修饰符定义;
- 继承一个抽象类,子类需要实现其中的抽象方法,然而接口可以扩展另一个接口而无需实现其中的方法;
- 子类只能继承单个抽象类,而一个接口或类可以实现多个接口;
- 继承抽象类的子类可以以相同或更低的可见性实现父类中的抽象方法,而实现接口的类只能以与原抽象方法相同的可见性实现接口中的方法;
- 接口没有构造函数,抽象类有;
- 接口中的变量都是final型的,而抽象类中可以包含非final型变量;
- 接口中的成员默认是public类型的,但抽象类中的成员的访问类型可以是public,protected和默认类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final (这里需要说一点,既然一个变量被final修饰了,那么这个变量就是一个常量!!!!!变量必须初始化成常量!!!!!)
下面比较一下两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量!!!!!!!(注意重点在 普通 即 非静态 和 变量!!!!)
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5.抽象类中可以包含静态方法(static),接口中不能包含静态方法.
6.抽象类和接口中都可以包含静态成员变量(static),抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
接口可以继承接口,抽象类可以实现接口,抽象类可以继承具体类,但是和实体类的继承一样,也要求父类可继承,并且拥有子类可访问到的构造器。抽象类也可以继承抽象类,接口不可以继承抽象类。