- 浏览: 122752 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (130)
- JUnit4学习 (0)
- Spring3.X学习 (2)
- 日记 (1)
- 文学类 (2)
- Java (15)
- Thingking In Java (11)
- org.apache.poi (4)
- XML (2)
- Log4j (1)
- Jar包收集 (2)
- ExtJs (1)
- 汇编语言 (11)
- 开发工具 (0)
- 电子书 (2)
- Oracle (6)
- Ajax (1)
- Jquery (2)
- myBatis (1)
- Spring2.5学习 (6)
- Tomcat (1)
- MyEclipse (1)
- JSP (1)
- Linux shell 脚本攻略 (7)
- Python3 (2)
- HTML5 (5)
- JavaScript (7)
- Hadoop-1.2.1 (2)
- Python2.7 (12)
- Django (3)
- 软件安装 (1)
- 高级Bash脚本编程指南 (7)
- Linux命令 (3)
- Ansible (2)
- MySQL (2)
- 病历 (1)
- 操作系统 (1)
- CSS (0)
- CSS3 (0)
- 面试题 (1)
最新评论
-
hw1287789687:
http://www.cnblogs.com/hccwu/p/ ...
Java获取真实的IP地址 -
liubey:
String ip = request.getHeader(& ...
Java获取真实的IP地址 -
bewithme:
我记得uploadify这破东西只能在chrome浏览器中才有 ...
Struts2结合Jquery.uploadify上传插件的应用 -
MrLee23:
http://mrlee23.iteye.com/admin/ ...
Struts2结合Jquery.uploadify上传插件的应用 -
crysik:
import com.eshore.ppm.model.com ...
Struts2结合Jquery.uploadify上传插件的应用
2013年6月20日 星期四 21时41分40秒
第九章 接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
9.1 抽象类和抽象方法
java提供了一种抽象方法的机制(相当于C++中的虚函数),这种方法是不完整的,仅有声明而没有方法体。
abstract void f();
包含抽象方法的类叫抽象类。如果一个类包含一个或多个抽象方法,该类必须被定义为抽象的。
如果从一个抽象类基础,并想创建该新类的对象,那么必须为基类中的所有抽象方法提供方法定义。如果不这么做,那么导出类便也是抽象类,且编译器会强制我们用abstract关键字来 限定这个类。
创建抽象类和抽象方法很有用,应该他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎么使用他们。抽象类还是很有用的重构工具。
9.2 接口
interface关键字使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或多个没有任何定义的方法----提供了接口部分。但是没有提供任何相应的具体实现,这些 实现是由此类的继承者创建的。
interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性。
一个接口,如果不添加public关键字,则它只具有包访问权限,这样它就只能在一个包内使用。接口也可以包含域,但是这些域隐式地是static和final的。
接口中的方法默认都是public类型。
9.3 完全解耦
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你可以选择使用接口。这样可以编写可复用性 更好的代码。
package chapter9.classprocessor;
import java.util.Arrays;
/*@name Bath.java
* @describe 9.3 完全解耦
* @since 2013-06-20 22:14
* @author 张彪
*/
class Processor{
public String name(){
return getClass().getName();
}
Object process(Object input){return input;}
}
class Upcase extends Processor{
String process(Object input){return ((String)input).toUpperCase();}
}
class Downcase extends Processor{
String process(Object input){return ((String)input).toLowerCase();}
}
class Splitter extends Processor{
String process(Object input){return Arrays.toString(((String)input).split(" "));}
}
public class Apply {
public static void process(Processor p,Object s){
System.out.println("Using Processor "+p.name());
System.out.println(p.process(s));
}
public static String s="Disagreement with be liefs is by definition incorrect";
public static void main(String[] args){
process(new Upcase(),s);
System.out.println("================");
process(new Downcase(),s);
System.out.println("================");
process(new Splitter(),s);
}
}
/*Using Processor chapter9.classprocessor.Upcase
DISAGREEMENT WITH BE LIEFS IS BY DEFINITION INCORRECT
================
Using Processor chapter9.classprocessor.Downcase
disagreement with be liefs is by definition incorrect
================
Using Processor chapter9.classprocessor.Splitter
[Disagreement, with, be, liefs, is, by, definition, incorrect]*/
如上例所示,创建一个能够根据所传参数对象的不用而具有不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而"策略"包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。这里Processor对象就是一个策略。
package chapter9.interfaces;
import chapter9.filters.*;
class FilterAdapter implements Processor{
Filter filter;
public FilterAdapter(Filter filter){
this.filter=filter;
}
public String name(){return filter.name();}
public Waveform process(Object input){
return filter.process((Waveform)input);
}
}
public class FilterProcessor {
public static void main(String[] args){
Waveform w=new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)), w);
Apply.process(new FilterAdapter(new HighPass(1.0)), w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)), w);
}
}
在上述这种使用适配器的方式中,FilterAdapter的构造器接收了你所拥有的接口Filter,然后生成具有你所需要的Processor接口对象。你可能还注意到了,在FilterAdapter类中用到了代理。
将接口从具体实现类中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具有复用性。
9.4 Java中的多重继承
接口不仅仅只是一种更纯粹的抽象类,它的目标比这要高。因为接口是根本没有任何具体实现的----也就是说,没有任何与接口相关的存储;因此也就无法阻止多个接口的组合。
Java中可以继承多个接口,并可以向上转型为每个接口,因为每个接口都是一个独立类型。
下面的例子展示了一个具体类组合数个接口之后产生了一个新类:
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.4 Java中的多重继承
* @since 2013-06-20 23:30
* @author 张彪
*/
interface CanFight{void fight();}
interface CanSwim{void swim();}
interface CanFly{void fly();}
class ActionCharacter{public void fight(){}}
//注意:當通過這種方式講一個具體類和多個接口組合到一起時,這個具體的類必須放在前面,後面跟著才是接口(負責編譯器會報錯)
class Hero extends ActionCharacter implements CanFight,CanSwim,CanFly {
public void swim(){}
public void fly(){}
}
public class Adventure {
public static void t(CanFight x){x.fight();}
public static void u(CanSwim x){x.swim();}
public static void v(CanFly x){x.fly();}
public static void w(ActionCharacter x){x.fight();}
public static void main(String[] args){
Hero h=new Hero();
t(h);
v(h);
u(h);
w(h);
}
}
注意:在Adventure类中,Hero对象可以被传递给四个方法中的任何一个,这意味着它依次被向上转型为每一个接口。
上述例子展示了使用接口的原因:为了能够向上转型为多个基类的类型(以及由此而带来的灵活性)。然而,使用接口的第二个原因却是与使用接口基本相同:我们应该使用接口还是抽象类??如果要创建不带任何方法定义和成员变量的基类,我们就应该选择接口而不是抽象类。事实上,如果知道某个事物应该成为一个基类,那么第一选择应该使他成为一个接口。
9.5 通过继承来扩展接口
通过继承,可以很容易在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。这两种情况都可以获得新的接口。
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.5 通過繼承來擴展接口
* @since 2013-06-20 23:55
* @author 张彪
*/
interface Monster{void menace();}
interface DangerousMonster extends Monster{void destory();}
interface Lethal{void kill();}
class DragonZilla implements DangerousMonster{
public void menace(){}
public void destory(){}
}
interface Vampire extends DangerousMonster{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
public void menace(){}
public void destory(){}
public void kill(){}
public void drinkBlood(){}
}
public class HorrorShow {
static void u(Monster b){b.menace();}
static void v(DangerousMonster d){
d.menace();
d.destory();
}
static void w(Vampire l){l.drinkBlood();}
public static void main(String[] args){
DangerousMonster h=new DragonZilla();
u(h);
v(h);
Vampire p=new VeryBadVampire();
u(p);
v(p);
}
}
9.5.1 组合接口时的名字冲突
在实现多重继承时,可能会碰到一个小陷阱,在前面的例子中,CanFight和ActionCharacter都一个一个相同的void fight()方法。这不是问题的所在,因为方法在二者中是相 同的。相同的方法不会有什么问题,但是如果签名或返回类型不同呢??? 举一个例子
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.5.1 組合接口時的名字衝突
* @since 2013-06-21 0:14
* @author 张彪
*/
interface I1 { void f(); }
interface I2 { int f(int i); }
interface I3 { int f(); }
class C { public int f() { return 1; } }
class C2 implements I1, I2 {
public void f() {}
public int f(int i) { return 1; } // overloaded
}
class C3 extends C implements I2 {
public int f(int i) { return 1; } // overloaded
}
class C4 extends C implements I3 {
// Identical, no problem:
public int f() { return 1; }
}
//class C5 extends C implements I1 {} //error: The return type is incompatible with I1.f(),C.f()
//interface I4 extends I1, I3 {} //error: The return type is incompatible with I3.f(),I1.f()
当撤销注释行时,就显示错误信息
所以在打算组合不同的接口中使用相同的方法名通常会造成代码的可读性的混乱,请尽量避免这种情况。
9.6 适配接口
接口最吸引人的原因之一就是允许同一个接口具有多个不同的具体实现。在简单的情况下,它的体现形式通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取 决于方法的使用者。
因此,接口的一种常见用法就是前面提到的策略设计模式,此时你编写一个执行某些操作的方法,而该方法将接受一个同样是你指定的接口。你主要就是声明:“你可以用任何你想要 的对象来调用我的方法,只要你的对象遵循我的接口。”这使得你的方法更灵活,通用,并更具有可复制性。
下面以Readable接口为例:
package chapter9.interfaces;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.*;
/*@name Bath.java
* @describe 9.6 適配接口
* @since 2013-06-21 0:47
* @author 张彪
*/
public class RandomWords implements Readable{
private static Random rand=new Random(47);
private static final char[] capitals="ABCDEFGHIGKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers="abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels="aeiou".toCharArray();
private int count;
public RandomWords(int count){
this.count=count;
}
public int read(CharBuffer cb) throws IOException {
if(--count==0){
return -1;
}
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i=0;i<4;i++){
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
return 6;
}
public static void main(String[] args){
Scanner s=new Scanner(new RandomWords(10));
while(s.hasNext()){
System.out.println(s.next());
}
}
}
假设你还有一个未实行Readable的类,怎样才能让Scanner组用于它呢? 下面这个例子,它可以随机产生浮点数。
package chapter9.interfaces;
import java.util.Random;
/*@name RandomDoubles.java
* @describe 产生随机浮点数
* @since 2013-06-21 9:45
* @author 张彪
*/
public class RandomDoubles {
private static Random rand=new Random(47);
public double next(){
return rand.nextDouble();
}
public static void main(String[] args){
RandomDoubles rd=new RandomDoubles();
for(int i=0;i<7;i++){
System.out.println(rd.next());
}
}
}
我们再次使用了适配器模式,但是在本例中,被适配的类可以通过继承和实现Readable接口来创建。因此通过使用interface关键字提供的伪多重继承机制,我们还可以生成既是RandomDoubles又是Readable的新类。
package chapter9.interfaces;
import java.nio.CharBuffer;
import java.util.Scanner;
public class AdapterRandomDoubles extends RandomDoubles implements Readable{
private int count;
public AdapterRandomDoubles(int count){
this.count=count;
}
public int read(CharBuffer cb){
if(count--==0){
return -1;
}
String result=Double.toString(next())+" ";
cb.append(result);
return result.length();
}
public static void main(String[] args){
Scanner s=new Scanner(new AdapterRandomDoubles(10));
while(s.hasNext()){
System.out.println(s.nextDouble()+" ");
}
}
}
9.7 接口中的域
因为你放入接口中的任何于都自动是static 和 final的,所以接口就成为了一种很便捷的用来创建常量组的工具。在Java SE5之前,这是产生与C或C++中enum(枚举类型)具有相同效 果的类型的唯一途径。 因此在Java SE5之前的代码中你会看到这样的代码:
package chapter9.interfaces;
public interface Months {
public interface Month{
int
JANUARY=1,FEBRUARY=2,MARCH=3;
}
}
注意:接口中的域自动是public。
有了Java SE5之后,你就可以使用更强强大而灵活的enum关键字。(详见19章)
9.7.1 初始化接口中的域
在接口中定义的域不能是“空final”,但是可以被非常量表达式初始化。例如:
package chapter9.interfaces;
import java.util.Random;
/*@name RandomDoubles.java
* @describe 9.7.1 初始化接口中的域
* @since 2013-06-21 9:45
* @author 张彪
*/
public interface RanVals {
Random RAND=new Random(47);
int RANDOM_INT =RAND.nextInt(10);
long RANDOM_LONG=RAND.nextLong()*10;
float RANDOM_FLOAT=RAND.nextFloat();
double RANDOM_DOUBLE=RAND.nextDouble();
}
//既然域是static的,他们就可以在类第一次被加载时初始化,这发生在任何域首次被访问时。当然这些域不是接口的一部分,他们的值被存储在该接口的静态存储区域内。
9.8 嵌套接口
接口可以嵌套在类或其他接口中。这揭示了许多非常有趣的特性。
package chapter9.interfaces;
/*@name RandomDoubles.java
* @describe 9.8 嵌套接口
* @since 2013-06-21 11:21
* @author 张彪
*/
//类嵌套
class A{
interface B{void f();}
public class BImp implements B{public void f(){}}
private class BImp2 implements B{public void f(){}}
public interface C{void f();}
private class CImp2 implements C{public void f(){}}
private interface D{void f();}
private class DImp implements D{public void f(){}}
public class DImp2 implements D{public void f(){}}
public D getD(){return new DImp2();}
private D dRef;
public void receieD(D d){
dRef=d;
dRef.f();
}
}
//接口嵌套
interface E{
interface G{void f();}
public interface H{void f();}
void g();
//The interface member type I can only be public
//private interface I{}
}
public class NestingInterfaces {
public class BImp implements A.B{
public void f(){}
}
class CImp implements A.C{
public void f(){}
}
//cannot implements a private interface
/*class DImp implements A.D{
public void f(){}
}*/
class EImp implements E{
public void g(){}
}
class EGImp implements E.G{
public void f(){}
}
class EImp2 implements E{
public void g(){}
class EG implements E.G{
public void f(){}
}
}
public static void main(String[] args){
A a=new A();
a.receieD(a.getD());
}
}
//NestingInterfaces展示了嵌套接口的各种实现方式。特别要注意的是,当实现某个接口时,并不需要实现嵌套在其内部的任何接口。而且,private接口不能在定义它的类之外被实现。
9.9 接口与工厂
接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方法就是工厂设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是的创建方法,而该工厂对象将生成接口 的某个实现的对象。 理论上通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以可以透明地将某个实现替换为另一个实现。
下面的实例展示了工厂方法的结构。
package chapter9.interfaces;
/*@name RandomDoubles.java
* @describe 9.9 接口与工厂___工厂方法设计模式
* @since 2013-06-23 16:21
* @author 张彪
*/
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
public void method1(){System.out.println("Implementation1.method1()");}
public void method2(){System.out.println("Implementation1.method2()");}
}
class Implementation2 implements Service{
public void method1(){System.out.println("Implementation2.method1()");}
public void method2(){System.out.println("Implementation2.method2()");}
}
class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implementation1();
}
}
class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s =fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(new Implementation2Factory());
}
}
为什么我们想要添加这种额外级别的间接性呢?一中常见的原因是想要创建框架。
9.10 总结
“确定接口是理想选择,因而应该总是选择接口而不是实现。”这其实是一种引诱。当然,对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂。
任何抽象性都应该是应真正的需求而产生的。当必要时,你应该重构接口而不是到处添加额外级别的间接性,并由此带来的额外复杂性。
恰当的原则应该是优先选择类而不是接口。从类开始,如果接口的必须性变得非常明确,那么就进行重构。接口是一种重要的工具,但是他们容易被滥用。
2013-06-23 16:42 记 @tangxiacun.tianhequ.guanzhou
第九章 接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
9.1 抽象类和抽象方法
java提供了一种抽象方法的机制(相当于C++中的虚函数),这种方法是不完整的,仅有声明而没有方法体。
abstract void f();
包含抽象方法的类叫抽象类。如果一个类包含一个或多个抽象方法,该类必须被定义为抽象的。
如果从一个抽象类基础,并想创建该新类的对象,那么必须为基类中的所有抽象方法提供方法定义。如果不这么做,那么导出类便也是抽象类,且编译器会强制我们用abstract关键字来 限定这个类。
创建抽象类和抽象方法很有用,应该他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎么使用他们。抽象类还是很有用的重构工具。
9.2 接口
interface关键字使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或多个没有任何定义的方法----提供了接口部分。但是没有提供任何相应的具体实现,这些 实现是由此类的继承者创建的。
interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性。
一个接口,如果不添加public关键字,则它只具有包访问权限,这样它就只能在一个包内使用。接口也可以包含域,但是这些域隐式地是static和final的。
接口中的方法默认都是public类型。
9.3 完全解耦
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。如果你想要将这个方法应用于不在此继承结构中的某个类,那么你可以选择使用接口。这样可以编写可复用性 更好的代码。
package chapter9.classprocessor;
import java.util.Arrays;
/*@name Bath.java
* @describe 9.3 完全解耦
* @since 2013-06-20 22:14
* @author 张彪
*/
class Processor{
public String name(){
return getClass().getName();
}
Object process(Object input){return input;}
}
class Upcase extends Processor{
String process(Object input){return ((String)input).toUpperCase();}
}
class Downcase extends Processor{
String process(Object input){return ((String)input).toLowerCase();}
}
class Splitter extends Processor{
String process(Object input){return Arrays.toString(((String)input).split(" "));}
}
public class Apply {
public static void process(Processor p,Object s){
System.out.println("Using Processor "+p.name());
System.out.println(p.process(s));
}
public static String s="Disagreement with be liefs is by definition incorrect";
public static void main(String[] args){
process(new Upcase(),s);
System.out.println("================");
process(new Downcase(),s);
System.out.println("================");
process(new Splitter(),s);
}
}
/*Using Processor chapter9.classprocessor.Upcase
DISAGREEMENT WITH BE LIEFS IS BY DEFINITION INCORRECT
================
Using Processor chapter9.classprocessor.Downcase
disagreement with be liefs is by definition incorrect
================
Using Processor chapter9.classprocessor.Splitter
[Disagreement, with, be, liefs, is, by, definition, incorrect]*/
如上例所示,创建一个能够根据所传参数对象的不用而具有不同行为的方法,被称为策略设计模式。这类方法包含所要执行的算法中固定不变的部分,而"策略"包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。这里Processor对象就是一个策略。
package chapter9.interfaces;
import chapter9.filters.*;
class FilterAdapter implements Processor{
Filter filter;
public FilterAdapter(Filter filter){
this.filter=filter;
}
public String name(){return filter.name();}
public Waveform process(Object input){
return filter.process((Waveform)input);
}
}
public class FilterProcessor {
public static void main(String[] args){
Waveform w=new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)), w);
Apply.process(new FilterAdapter(new HighPass(1.0)), w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)), w);
}
}
在上述这种使用适配器的方式中,FilterAdapter的构造器接收了你所拥有的接口Filter,然后生成具有你所需要的Processor接口对象。你可能还注意到了,在FilterAdapter类中用到了代理。
将接口从具体实现类中解耦使得接口可以应用于多种不同的具体实现,因此代码也就更具有复用性。
9.4 Java中的多重继承
接口不仅仅只是一种更纯粹的抽象类,它的目标比这要高。因为接口是根本没有任何具体实现的----也就是说,没有任何与接口相关的存储;因此也就无法阻止多个接口的组合。
Java中可以继承多个接口,并可以向上转型为每个接口,因为每个接口都是一个独立类型。
下面的例子展示了一个具体类组合数个接口之后产生了一个新类:
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.4 Java中的多重继承
* @since 2013-06-20 23:30
* @author 张彪
*/
interface CanFight{void fight();}
interface CanSwim{void swim();}
interface CanFly{void fly();}
class ActionCharacter{public void fight(){}}
//注意:當通過這種方式講一個具體類和多個接口組合到一起時,這個具體的類必須放在前面,後面跟著才是接口(負責編譯器會報錯)
class Hero extends ActionCharacter implements CanFight,CanSwim,CanFly {
public void swim(){}
public void fly(){}
}
public class Adventure {
public static void t(CanFight x){x.fight();}
public static void u(CanSwim x){x.swim();}
public static void v(CanFly x){x.fly();}
public static void w(ActionCharacter x){x.fight();}
public static void main(String[] args){
Hero h=new Hero();
t(h);
v(h);
u(h);
w(h);
}
}
注意:在Adventure类中,Hero对象可以被传递给四个方法中的任何一个,这意味着它依次被向上转型为每一个接口。
上述例子展示了使用接口的原因:为了能够向上转型为多个基类的类型(以及由此而带来的灵活性)。然而,使用接口的第二个原因却是与使用接口基本相同:我们应该使用接口还是抽象类??如果要创建不带任何方法定义和成员变量的基类,我们就应该选择接口而不是抽象类。事实上,如果知道某个事物应该成为一个基类,那么第一选择应该使他成为一个接口。
9.5 通过继承来扩展接口
通过继承,可以很容易在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。这两种情况都可以获得新的接口。
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.5 通過繼承來擴展接口
* @since 2013-06-20 23:55
* @author 张彪
*/
interface Monster{void menace();}
interface DangerousMonster extends Monster{void destory();}
interface Lethal{void kill();}
class DragonZilla implements DangerousMonster{
public void menace(){}
public void destory(){}
}
interface Vampire extends DangerousMonster{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
public void menace(){}
public void destory(){}
public void kill(){}
public void drinkBlood(){}
}
public class HorrorShow {
static void u(Monster b){b.menace();}
static void v(DangerousMonster d){
d.menace();
d.destory();
}
static void w(Vampire l){l.drinkBlood();}
public static void main(String[] args){
DangerousMonster h=new DragonZilla();
u(h);
v(h);
Vampire p=new VeryBadVampire();
u(p);
v(p);
}
}
9.5.1 组合接口时的名字冲突
在实现多重继承时,可能会碰到一个小陷阱,在前面的例子中,CanFight和ActionCharacter都一个一个相同的void fight()方法。这不是问题的所在,因为方法在二者中是相 同的。相同的方法不会有什么问题,但是如果签名或返回类型不同呢??? 举一个例子
package chapter9.interfaces;
/*@name Bath.java
* @describe 9.5.1 組合接口時的名字衝突
* @since 2013-06-21 0:14
* @author 张彪
*/
interface I1 { void f(); }
interface I2 { int f(int i); }
interface I3 { int f(); }
class C { public int f() { return 1; } }
class C2 implements I1, I2 {
public void f() {}
public int f(int i) { return 1; } // overloaded
}
class C3 extends C implements I2 {
public int f(int i) { return 1; } // overloaded
}
class C4 extends C implements I3 {
// Identical, no problem:
public int f() { return 1; }
}
//class C5 extends C implements I1 {} //error: The return type is incompatible with I1.f(),C.f()
//interface I4 extends I1, I3 {} //error: The return type is incompatible with I3.f(),I1.f()
当撤销注释行时,就显示错误信息
所以在打算组合不同的接口中使用相同的方法名通常会造成代码的可读性的混乱,请尽量避免这种情况。
9.6 适配接口
接口最吸引人的原因之一就是允许同一个接口具有多个不同的具体实现。在简单的情况下,它的体现形式通常是一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取 决于方法的使用者。
因此,接口的一种常见用法就是前面提到的策略设计模式,此时你编写一个执行某些操作的方法,而该方法将接受一个同样是你指定的接口。你主要就是声明:“你可以用任何你想要 的对象来调用我的方法,只要你的对象遵循我的接口。”这使得你的方法更灵活,通用,并更具有可复制性。
下面以Readable接口为例:
package chapter9.interfaces;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.*;
/*@name Bath.java
* @describe 9.6 適配接口
* @since 2013-06-21 0:47
* @author 张彪
*/
public class RandomWords implements Readable{
private static Random rand=new Random(47);
private static final char[] capitals="ABCDEFGHIGKLMNOPQRSTUVWXYZ".toCharArray();
private static final char[] lowers="abcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] vowels="aeiou".toCharArray();
private int count;
public RandomWords(int count){
this.count=count;
}
public int read(CharBuffer cb) throws IOException {
if(--count==0){
return -1;
}
cb.append(capitals[rand.nextInt(capitals.length)]);
for(int i=0;i<4;i++){
cb.append(vowels[rand.nextInt(vowels.length)]);
cb.append(lowers[rand.nextInt(lowers.length)]);
}
cb.append(" ");
return 6;
}
public static void main(String[] args){
Scanner s=new Scanner(new RandomWords(10));
while(s.hasNext()){
System.out.println(s.next());
}
}
}
假设你还有一个未实行Readable的类,怎样才能让Scanner组用于它呢? 下面这个例子,它可以随机产生浮点数。
package chapter9.interfaces;
import java.util.Random;
/*@name RandomDoubles.java
* @describe 产生随机浮点数
* @since 2013-06-21 9:45
* @author 张彪
*/
public class RandomDoubles {
private static Random rand=new Random(47);
public double next(){
return rand.nextDouble();
}
public static void main(String[] args){
RandomDoubles rd=new RandomDoubles();
for(int i=0;i<7;i++){
System.out.println(rd.next());
}
}
}
我们再次使用了适配器模式,但是在本例中,被适配的类可以通过继承和实现Readable接口来创建。因此通过使用interface关键字提供的伪多重继承机制,我们还可以生成既是RandomDoubles又是Readable的新类。
package chapter9.interfaces;
import java.nio.CharBuffer;
import java.util.Scanner;
public class AdapterRandomDoubles extends RandomDoubles implements Readable{
private int count;
public AdapterRandomDoubles(int count){
this.count=count;
}
public int read(CharBuffer cb){
if(count--==0){
return -1;
}
String result=Double.toString(next())+" ";
cb.append(result);
return result.length();
}
public static void main(String[] args){
Scanner s=new Scanner(new AdapterRandomDoubles(10));
while(s.hasNext()){
System.out.println(s.nextDouble()+" ");
}
}
}
9.7 接口中的域
因为你放入接口中的任何于都自动是static 和 final的,所以接口就成为了一种很便捷的用来创建常量组的工具。在Java SE5之前,这是产生与C或C++中enum(枚举类型)具有相同效 果的类型的唯一途径。 因此在Java SE5之前的代码中你会看到这样的代码:
package chapter9.interfaces;
public interface Months {
public interface Month{
int
JANUARY=1,FEBRUARY=2,MARCH=3;
}
}
注意:接口中的域自动是public。
有了Java SE5之后,你就可以使用更强强大而灵活的enum关键字。(详见19章)
9.7.1 初始化接口中的域
在接口中定义的域不能是“空final”,但是可以被非常量表达式初始化。例如:
package chapter9.interfaces;
import java.util.Random;
/*@name RandomDoubles.java
* @describe 9.7.1 初始化接口中的域
* @since 2013-06-21 9:45
* @author 张彪
*/
public interface RanVals {
Random RAND=new Random(47);
int RANDOM_INT =RAND.nextInt(10);
long RANDOM_LONG=RAND.nextLong()*10;
float RANDOM_FLOAT=RAND.nextFloat();
double RANDOM_DOUBLE=RAND.nextDouble();
}
//既然域是static的,他们就可以在类第一次被加载时初始化,这发生在任何域首次被访问时。当然这些域不是接口的一部分,他们的值被存储在该接口的静态存储区域内。
9.8 嵌套接口
接口可以嵌套在类或其他接口中。这揭示了许多非常有趣的特性。
package chapter9.interfaces;
/*@name RandomDoubles.java
* @describe 9.8 嵌套接口
* @since 2013-06-21 11:21
* @author 张彪
*/
//类嵌套
class A{
interface B{void f();}
public class BImp implements B{public void f(){}}
private class BImp2 implements B{public void f(){}}
public interface C{void f();}
private class CImp2 implements C{public void f(){}}
private interface D{void f();}
private class DImp implements D{public void f(){}}
public class DImp2 implements D{public void f(){}}
public D getD(){return new DImp2();}
private D dRef;
public void receieD(D d){
dRef=d;
dRef.f();
}
}
//接口嵌套
interface E{
interface G{void f();}
public interface H{void f();}
void g();
//The interface member type I can only be public
//private interface I{}
}
public class NestingInterfaces {
public class BImp implements A.B{
public void f(){}
}
class CImp implements A.C{
public void f(){}
}
//cannot implements a private interface
/*class DImp implements A.D{
public void f(){}
}*/
class EImp implements E{
public void g(){}
}
class EGImp implements E.G{
public void f(){}
}
class EImp2 implements E{
public void g(){}
class EG implements E.G{
public void f(){}
}
}
public static void main(String[] args){
A a=new A();
a.receieD(a.getD());
}
}
//NestingInterfaces展示了嵌套接口的各种实现方式。特别要注意的是,当实现某个接口时,并不需要实现嵌套在其内部的任何接口。而且,private接口不能在定义它的类之外被实现。
9.9 接口与工厂
接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方法就是工厂设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是的创建方法,而该工厂对象将生成接口 的某个实现的对象。 理论上通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以可以透明地将某个实现替换为另一个实现。
下面的实例展示了工厂方法的结构。
package chapter9.interfaces;
/*@name RandomDoubles.java
* @describe 9.9 接口与工厂___工厂方法设计模式
* @since 2013-06-23 16:21
* @author 张彪
*/
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
public void method1(){System.out.println("Implementation1.method1()");}
public void method2(){System.out.println("Implementation1.method2()");}
}
class Implementation2 implements Service{
public void method1(){System.out.println("Implementation2.method1()");}
public void method2(){System.out.println("Implementation2.method2()");}
}
class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implementation1();
}
}
class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s =fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(new Implementation2Factory());
}
}
为什么我们想要添加这种额外级别的间接性呢?一中常见的原因是想要创建框架。
9.10 总结
“确定接口是理想选择,因而应该总是选择接口而不是实现。”这其实是一种引诱。当然,对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂。
任何抽象性都应该是应真正的需求而产生的。当必要时,你应该重构接口而不是到处添加额外级别的间接性,并由此带来的额外复杂性。
恰当的原则应该是优先选择类而不是接口。从类开始,如果接口的必须性变得非常明确,那么就进行重构。接口是一种重要的工具,但是他们容易被滥用。
2013-06-23 16:42 记 @tangxiacun.tianhequ.guanzhou
- chapter9.rar (8.7 KB)
- 下载次数: 0
发表评论
-
第十三章 字符串
2013-08-06 00:50 9382013年8月1日 星期四 21时05分59秒 第十三章 字 ... -
第十二章 通过异常处理错误
2013-08-01 21:04 7612013年7月10日 星期三 00时04分21秒 第十二章 ... -
第十一章 持有对象
2013-07-09 00:49 9582013年6月24日 星期一 20时57分09秒 第十一章 ... -
第十四章 类型信息
2013-07-02 01:26 9572013年6月25日 星期二 23时12分42秒 第十四章 ... -
第十章 内部类
2013-06-24 20:47 10172013年6月23日 星期日 16时50分56秒 第十章 内 ... -
第八章 多态
2013-06-19 23:06 7072013年6月17日 星期一 23 ... -
Thinking in Java Fourth Edition Source Code
2013-06-17 23:10 527Thinking in Java F ... -
第七章 复用类
2013-06-17 22:36 5942013年6月16日 星期日 21时06分54秒 第七章 复 ... -
第六章 访问权限控制
2013-06-16 21:05 8892013年6月16日 星期日 11时10分46秒 第六章 访 ... -
第五章 初始化与清理
2013-06-16 10:58 6342013年6月15日 星期六 16 ...
相关推荐
9Java编程思想第九章接口.pptx
第9章 并行接口
【单片机原理与接口技术】的第9章主要探讨了串行通信及其相关的实验内容。串行通信作为单片机系统中与外部设备交互的一种重要方式,与并行通信相比,具有节省传输线的优势,尤其在数据量大和长距离传输时。然而,其...
微型计算机系统与接口第二版 李继灿 第九章答案
微型计算机原理与接口技术:第九章 中断系统与 8259A 中断控制器.ppt
第9章_显示器、键盘、打印机接口--打印机.pdf第9章_显示器、键盘、打印机接口--打印机.pdf第9章_显示器、键盘、打印机接口--打印机.pdf第9章_显示器、键盘、打印机接口--打印机.pdf第9章_显示器、键盘、打印机接口--...
### 第九章 MCS-51与键盘、显示器、拨盘、打印机的接口设计 #### 9.1 LED显示器接口原理 ##### 9.1.1 LED显示器的结构 LED显示器通常指的是发光二极管显示器,它是一种常见的数字或字母显示设备。在本章节中,...
9. **第九章 接口**:接口技术是连接不同设备的关键,本章可能涵盖了各种接口电路的设计与应用,如A/D和D/A转换器、显示器、键盘和打印机接口等。 10. **第十章 综合应用**:这部分可能提供了综合案例,将前面学习...
在Java程序设计与数据结构的学习过程中,第九章通常会涵盖数据结构的重要概念和应用,包括数组、链表、栈、队列、树等基础数据结构,以及如何利用这些数据结构来解决问题。本资源提供了第九章的习题答案,旨在帮助...
"单片机原理及接口技术课后习题第9章答案" 本资源摘要信息涵盖了单片机原理及接口技术的重要知识点,主要包括输入/输出接口电路的作用、数据传输控制方式、接口电路设计和检验控制程式的编制等内容。 第九章复习...
第9章 人机交互设备接口是计算机科学中关于如何使用户与计算机系统进行有效通信的重要部分。这一章涵盖了各种常见的交互设备,如键盘、显示器、打印机以及多媒体设备的接口技术和工作原理。以下是对各部分的详细解释...
微机原理与接口技术:20第9章 并行接口与串行接口.doc
微机原理与接口技术:21第9章 并行接口与串行接口.ppt
第9章-实现接口.ppt
第九章的微机接口技术是计算机科学中的一个重要领域,它主要研究如何使计算机与外部设备进行有效通信。在微机原理实验中,学生通常会深入理解这些概念,并通过实际操作来提升技能。微机原理是计算机硬件系统的基础,...
非常全面的课件,版权归制作老师所有,这里仅供分享 章节目录 计划学时 第1章 微型计算机系统概述 3.5 ...第9章 定时计数控制接口 4 第10章 DMA控制接口 6 第11章 并行接口 12 第12章 串行通信接口 6 第13章 模拟接口 6
第1章 模式的简史和形而上学 ...第9章 接口隔离原则 第10章 合成、聚合复用原则 第11章 迪米特法则 第12章 简单工厂模式 第13章 工厂方法模式 第14章 抽象工厂模式 第15章 单例模式 第16章 .......
在本资源中,我们关注的是"C++第九章的课后题源码",这通常涉及到谭浩强教授的《C++编程语言》一书中的学习材料。谭浩强教授是中国著名的计算机教育专家,他的教材深入浅出,适合初学者学习。第九章可能涵盖了C++中...
第9章 中断体系结构 第10章 系统时钟和定时器 第11章 通用异步收发器UART 第12章 I*IC接口 第13章 LCD控制器 第14章 ADC和触摸屏接口 第3篇 嵌入式Linux系统移植篇 第15章 移植U-Boot ...