2.抽象类,普通的类与接口之间的一种中庸之道。尽管在构建具有某些未实现方法的类时,你的第一想法可能是创建接口,但是抽象类仍然是用于此目的的一种重要而必须的工具。因为你不可能总是使用纯接口。
1.通用接口,建立诸如Instrument(乐器)这个通用接口的唯一理由是,不同的子类可以用不同的方式表示此接口。通用接口建立起来一种基本形式,以此表示所有导出类的共同部分。
2.另一种说法是将Instrument类称作抽象基类或简称抽象类。如果我们只有一个像Instrument的抽象类,那么该类的对象几乎没有任何意义。我们创建抽象类是希望通过这个通用接口操纵一系列类。因此 Instrument只是表示了一个接口,没有具体的实现内容,因此创建一个Instrument对象没有什么意义,并且我们还可能想阻止使用者这样做。通过让Instrument中的所有方法都产生错误,就可以实现这个目的。但是这样做会将错误信息延迟到运行时才获得,并且需要在客户端进行可靠,详尽的测试。所以最好是在编译时捕获这些问题->Java提供了抽象方法的机制,不完整的,仅有声明而没有方法体,如 abstract void f();
3.包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的,否则编译器报错。如果一个抽象类不完整,那么当我们试图产生该类的对象时,编译器会怎么处理。由于为抽象类创建对象是不安全的,所以我们会从编译器那里得到一条出错信息。这样,编译器会确保抽象类的纯粹性,我们不必担心会误用它。
4.如果从一个抽象类继承,并想创建该类的对象,那么就必须为基类的所有抽象方法提供方法定义,如果不这样做,可以选择不做,那么导出类也是抽象类,且编译器会强制我们用abstract关键字来限制这个类。
5.我们也可能创建一个没有任何抽象方法的抽象类,考虑这种情况,如果有一个类,让其包含任何abstracat方法都显得没有任何实际意义,而且我们也想阻止产生这个类的任何对象,那么这样做就很有用了。
6.创建抽象类和抽象方法很有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎么样来使用他们。抽象类还是很有用的重构工具,因为他们使得我们可以很容易的将公共方法沿着继承层次向上移动。
3.interface关键字使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或多个没有任何定义的方法,提供了接口部分,而没有提供任何相应的具体实现。这些实现是由类的继承者创建的.interface这个关键字产生一个完全抽象的类,它根本就没有提供任何具体实现。接口只提供了形式,而未提供任何具体实现。
1.一个接口表示,所有实现了该特定接口的类看起来都像这样。因此任何使用某特定接口的代码都知道可以调用该接口的哪些方法,而且仅需要知道这些。因此接口被用来建立类与类之间的协议。protocol.
3.interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继承变种的特性。
4.接口也可以包含域,不过这些域隐式的是static和final的。可以选择在接口中显示的将方法声明为public的,但即使你不这么做,他们也是public的,因此,当要实现一个接口时,在接口中被定义的方法必须被定义为public的。否则他们只得到默认的包访问权限,这样在方法被继承的过程中 ,其可访问权限就被降低了。这是Java编译器所不允许的。
注:不仅仅是接口,对于继承覆盖的方法也不能降低可访问权限,即 Cannot reduce the visibility of the inherited method.但是我们可以增加可访问权限,比如基类方法是default,而导出类的覆盖方法则可以将访问权限提升至public.
4.只要一个方法操作的是类而不是接口,那么你就只能使用这个类及其子类,如果你想要将这个方法应用于不再此继承结构的某个类,那么你就会触霉头了。接口可以在很大程度上放宽这种限制,因此他们可以使我们可以编写可复用性更好的代码。
1.创建一个能够根据所传递的对象的参数不同而具有不同行为的方法,被称为策略设计模式。这类方法包含的所要执行的算法中固定不变的部分,而策略包含变化的部分,策略就是传递进去的参数对象 ,它包含要执行的代码。
2.将接口从具体实现中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具可复用性。
5.接口不仅仅是只是一种更纯粹形式的抽象类,它的目标比这要求更高。因为接口是没有任何具体实现的,也就是说没有任何与接口相关的存储;因此也就无法阻止多个接口的组合。这一点是很有价值的,因为你有时需要去表示“一个x是一个a和一个b以及一个c”。在c++中,组合多个类接口的行为被称作为多重继承(C++菱形问题,即B,C同时继承了接口A,D多重继承B,C,这样在调用A中的方法的时候,无法知道该方法究竟是B中的还是C中的)。它可能会使你背负很沉重的包袱,因为每一个类都有一个具体实现。
注:Java中接口不会有这样的问题,当你实现多个接口的时候。因为接口是没有实现的,这样菱形问题就不会对编译器造成困扰,因为都是没有实现的。即如接口B和接口C继承结合A,而实现类D实现了接口B和C,此时D的实现类中实现具体方法,因为所有的接口都是无实现的,所以编译器不会困扰,因为调用的肯定是实现的具体类的方法。因为具体类必须实现接口中未实现的方法。当然使用抽象类也是不行的,因为抽象类中也可以定义具体的方法。
1.当通过一个具体类和多个接口组合到一起的时候,这个具体类必须放在前面,后面跟着的才是接口,否则编译报错。
注:个人觉得这条规定可能是防止歧义的出现,比如正常的形式是A extends B implements C,D 如果换做:A implements C,D extends B的话,肯定会有歧义的,是c或D extends B 所以说编译器强制这样规定。
2.使用接口的核心原因:
1.为了能够向上转型为多个基类型以及由此而带来的灵活性。
2.然而使用接口的第二个原因却是与抽象基类相同,防止客户端程序员创建该类的对象,并确保这仅仅是创建一个接口。这就带了一个问题:我们应该使用接口还是抽象类?如果我们要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。事实上,如果知道某事物应该成为一个基类,那么第一选择应该是使它成为一个接口。
3.通过继承来扩展接口
4.一定要注意组合接口时的名字冲突问题->在打算组合的不同接口中使用相同的方法名通常会造成代码可读性的混乱,因为覆盖,实现,重载令人不愉快的搅在了一起,而且重载方法仅通过返回类型是区分不开的。请尽量避免这种情况。
6.适配接口:
1.接口最吸引人的原因就是允许同一个接口具有不同的具体实现。在简单的情况下,它的体现形式通常是一个接受接口类型的方法,而