一、抽象类
抽象类不可以用于创建对象。抽象类可以包含抽象方法,这些方法将在具体的子类中实现。
在继承的层次结构中,每个新子类都使类变得越来越明确和具体。如果一个子类追溯到父类,类就会变得更通用、更加的不明确。类的设计应该确保父类包含它的子类的共同特征。
有时候,一个父类设计得非常抽象,以至于它都没有任何具体的实例。这样的类称为抽象类。
父类中包含的实现取决于具体的类型的方法,叫抽象方法,在方法头中使用abstract修饰符表示。
在类头中使用abstract修饰符表示该类为抽象类。
在UML图形记号中,抽象类和抽象方法的名字用斜体表示。
抽象类和常规类很像,但是不能使用new操作符创建它的实例。抽象方法只有定义而没有实现。它的实现由子类提供。一个包含抽象方法的类必须声明为抽象类。
抽象类的构造方法定义为protected,因为它只是被子类使用。创建一个具体子类的实例时,它的父类的构造方法被调用以初始化父类中定义的数据域。
1、为什么要使用抽象方法
eg:equal(Object1,Object2)可以比较两个不同方法下的结果
2、抽象类的几点说明
①、抽象方法不能包含在非抽象类中。
②、抽象类是不能使用new操作符来初始化的。
③、包含抽象方法的类必须是抽象的。
④、子类可以覆盖父类的方法并将它定义为abstract。
⑤、即使子类的父类是具体的,这个子类也可以抽象的。
⑥、不能使用new操作符从一个抽象类创建一个实例,但是抽象类可以用作一种数据类型。
二、接口
接口是一种与类相似的结构,只包含常量和抽象方法。
接口在许多方面都与抽象类很相似,但是它的目的是指明相关或者不相关类的多个对象的共同行为。
为了区分接口和类,Java采用下面的语法来定义接口:
修饰符 interface 接口名{
/** 常量声明 **/
/** 方法签名 **/
}
在Java中,接口被看作是一种特殊的类。就像常规类一样,每个接口都被编译为独立的字节码文件。与抽象类相似,不能使用new操作符创建接口的实例。
可以使用Edible接口来明确一个对象是否可食用。需要使用implements关键字让对象的类实现这个接口来完成。eg:class Chicken extends Animal implements Edible
类和接口之间的关系称为接口继承。因为接口继承和类继承本质上是相同的,都简称为继承。
三、Comparable接口
Comparable接口定义了compareTo,用于比较对象。
Comparable接口的定义:
//Interface for comparing objects,defined in java.lang
package java.lang;
public interface Comparable<E>{
public int compareTO(E o);
}
compareTo方法判断这个对象相对于相对于给定对象o的顺序,并且当这个对象小于、等于或大于给定对象o时,分别返回负整数、0或正整数。
Comparable接口是一个泛型接口。在实现该接口时,泛型类型E被替换成一种具体的类型。
如果对象是Comparable接口类型的实例,Java API中的java.util.Arrays.sort(Object[])方法就可以使用compareTo方法来对数组中的对象进行比较和排序。
四、Cloneable接口
Cloneable接口给出了一个可克隆的对象。定义:
package java.lang
public interfacen Cloneable{
}
这个接口是空的。一个带空体的接口称为标记接口。一个标记接口既不包括常量也不包括方法。它用来表示一个类拥有某些特征的属性。实现Cloneable接口的类标记为可克隆的,而且它的对象可以使用在Object类中定义clone()方法克隆。
五、接口和抽象类
一个类可以实现多个接口,但是只能继承一个父类。
变量 | 构造方法 | 方法 | |
抽象类 | 无限制 | 子类通过构造方法调用构造方法,抽象类不能用new操作符实例化 | 无限制 |
接口 | 所有变量必须是public static final | 没有构造方法。接口不能用new操作符实例化 | 所有方法必须是公共的抽象实例的方法 |
Java只允许为类的扩展做单一继承,但是允许使用接口做多重扩展。
使用关键字extends,接口可以继承其他接口。这样的接口称为子接口。eg:
public interface NewInterface extends Interface1,...,InterfaceN{
//constans and abstract methods
}
抽象类和接口都是用来明确多个对象的共同特征的。一般来说,清晰描述父子关系的强的“是一种”的关系应该使用类建模。弱的“是一种”的关系也称为类属关系,它表明对象拥有某种属性,可以用接口来建模。
通常,推荐使用接口而非抽象类,因为接口可以定义非相关类共有的父类型。接口比类更加灵活。
六、类的设计原则
1、内聚性
类应该描述一个单一的实体,而所有的类操作应该在逻辑上相互配合,支持一个一致的目的。
2、一致性
遵循标准Java程序设计风格和命名习惯。为类、数据域和方法选取具有信息的名字。通常的风格是将数据声明置于构造方法之前,并且将构造方法置于方法之前。
选择名字要保持一致。给类似的操作选择不同的名字并非良好的实践。
一般来说,应该具有一致性地提供一个公共无参构造方法,用于构建默认实例。如果一个类不支持无参的构造方法,要用文档写出原因。如果没有显示定义构造方法,即假定有一个空方法体的公共无参构造方法。
如果不想让用户创建类的对象,可以在类中声明一个私有的构造方法,Math类就是如此。
3、封装性
一个类应该使用private修饰符隐藏其数据,以免用户直接访问它。这使得类更易于维护。
只在希望数据域可读的情况下,才提供get方法;也只在希望数据域可更新的情况下,才提供set方法。
4、清晰性
为使设计清晰,内聚性、一致性和封装性都是很好的设计原则。除此之外,类应该有一个很清晰的合约,从而易于解释和理解。
用户可以以各种不同的组合、顺序,以及在各种环境中结合使用多个类。
方法应在不产生混淆的情况下进行直观定义。
不应该声明一个来自其他数据域的数据域。
5、完整性
类是为许多不同用户的使用而设计的。为了能在一个广泛的应用中使用,一个类应该通过属性和方法提供多种方案以适应用户的不同需求。
6、实例和静态
依赖于类的具体实例的变量或方法必须是一个实例变量或方法。如果一个变量被类的所有实例所共享,那就应该将它声明为静态的。如果方法不依赖于某个具体的实例,那就应该将它声明为静态方法。
应该总是使用类名(而不是引用变量)引用静态变量和方法,以增强可读性并避免错误。
不要从构造方法传入参数来初始化静态数据域。最好使用set方法改变静态数据域。
实例和静态是面向对象程序设计不可或缺的部分。数据域或方法要么是实例的,要么是静态的。不要错误地忽视静态数据域或方法。
构造方法永远都是实例方法,因为它是用来创建具体实例的。一个静态变量或方法可以从实例方法中调用,但是不能从静态方法中调用实例变量或方法。
7、继承与聚合
继承和聚合之间的差异,就是is-a(是一种)和has-a(具有)之间的关系。