一. 抽象类里面并非一定需要抽象方法,但是没有抽象方法,抽象类就没有存在的意义。
二. 在以下任一条件成立时,类必须定义成抽象类:
① 类中有至少一个抽象方法。
② 类继承了父类中的抽象方法,但是至少有一个抽象方法没有实现。
③ 类实现了某个接口,但没有全部实现接口中的方法。
一. 什么是接口
① 接口是方法和常量值的定义的集合。
② 接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
③ 接口和类类似,也可以从一个父接口中派生。接口的继承也是使用"extends"关键字来完成。
二. 实现接口
① 多个无关的类可实现同一个接口。
② 一个类可实现多个无关的接口。接口的实现是使用"implements"关键字来完成。
③ 在Java中,可以通过接口来模拟多继承。
① 在Java中,对象变量是多态的。一个类型为Aclass的变量既可以指向类型为Aclass的对象,又可
② 以多态的形式来传递参数,增强了参数类型的灵活性。
③ 一个对象只能有一种确切的数据类型。
④ 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
对于继承可能会引发某种争论:
继承应该只重载基类的方法(而并不添加在基类中没有的新方法)吗?如果这样做,就意味着导出类和基类是完全相同的类型,因为它们具有完全相同的接口。如果你可以用一个导出类对象来完全替代一个基类对象。这可以被视为“纯粹替代(pure_substitution)”,通常称之为“替代法(substitution_principle)”。在某种意义上,这是一种处理继承的理想方式。我们经常将这种情况下的基类与导出类之间的关系称为“is-a”关系,因为你可以说“一个圆形就是一个几何形状”。判断是否继承,就是要确定你是否可以用is-a来描述之间的关系,并使之具有实际意义。
有时你必须在导出类型中添加新的接口元素,这样也就扩展了接口并创建了新的类型。这个新的类型仍然可以替代基类,但是这种替代并不完美,因为基类无法访问你新添加的方法。这种情况我们可以描述为“is-like-a”关系。新类型具有旧类型的接口,但是它还包含其他方法,所以你不能说它们完全相同
1 抽象类:
有构造器
有变量/也有常量
有抽象方法/方法实现
修饰符需要定义(public abstract final)
可以有游离块
2 接口:
没有构造器
只有常量
只有抽象方法
修饰符默认为(public abstract final)
没有游离块
abstract class和interface在Java语言中都是用来进行抽象类定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?(这里的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法,请注意区分)
比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。
abstract class Demo{
abstract void method1();
abstract void method2();
…
}
使用interface的方式定义Demo抽象类的方式如下:
interface Demo{
void method1();
void method2();
…
}
同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了 "one rule,one place" 原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。
从设计理念层面看 abstract class 和 interface上 面主要从语法定义和编程的角度论述了abstract class和interface的区 别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二 者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。
考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:
abstract class Door{
abstract void open();
abstract void close();
}
使用interface方式定义Door:
interface Door{
void open();
void close();
}
如果 现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢?下面将罗列出可能的解 决方案,并从设计理念层面对这些不同的方案进行分析。(在本例中主要是为了展示 abstract class 和interface 反映在设计理念上的区别)
简单的在Door的定义中增加一个alarm方法,如下:
abstract class Door{
abstract void open();
abstract void close();
abstract void alarm();
}
或者
interface Door{
void open();
void close();
void alarm();
}
那么具有报警功能的AlarmDoor的定义方式如下:
class AlarmDoor extends Door{
void open(){…}
void close(){…}
void alarm(){…}
}
或者
class AlarmDoor implements Door{
void open(){…}
void close(){…}
void alarm(){…}
}
显然,由于Java语言不支持多重继承,①是不可行的。② ③都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。
如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用 interface方式定义)反映不出上述含义。
abstract class Door{
abstract void open();
abstract void close();
}
interface Alarm{
void alarm();
}
class Alarm Door extends Door implements Alarm{
void open(){…}
void close(){…}
void alarm(){…}
}
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。
2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。
3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"is-like-a"关系。
4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。
6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
7.接口中的方法默认都是 public,abstract 类型的。
abstract class 和 interface 是Java语言中的两种定义抽象类的方式,它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概 念本质的理解、对于设计意图的反映是否正确、合理,因为它们表现了概念间的不同的关系(虽然都能够实现需求的功能)。这其实也是语言的一种的惯用法。
public abstract class Bank {
private double interest;//利率
private double fund;//本金
//计算利率的方法
public double calc() {
interest = getFund() * getInterestRate();
return interest;
}
//抽象的方法,在具体的实例中根据需求定义
public abstract double getInterestRate();
//设置本金
public void setFund(double fund) {
this.fund = fund;
}
//获得本金
public double getFund() {
return this.fund;
}
}
---------------------------------------
//实例1
public class ICBC extends Bank {
//实现父类中的抽象方法
public double getInterestRate() {
return 0.022;
}
public void test (){
System.out.println("Test.............");
}
}
---------------------------------------
//实例2
public class CBC extends Bank {
//实现父类中的抽象方法
public double getInterestRate() {
return 0.033;
}
public void test (){
System.out.println("Test......");
}
}
---------------------------------------
public class TestBank {
public static void main(String[] args) {
//①声明子类类型,引用子类类型
ICBC i = new ICBC();
i.setFund(1000);
System.out.println(i.calc());
//变量"i"可以访问子类中添加的方法
i.test();
//②声明父类类型,引用子类类型
Bank c = new CBC();
c.setFund(1000);
System.out.println(c.calc());
//变量"c"不能访问子类中添加的方法
// c.test();
}
}

















