重温经典《Thinking in java》第四版之第九章 接口(四十六)

简介: 重温经典《Thinking in java》第四版之第九章 接口(四十六)

接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。

这种机制在编程语言中并不通用。例如,C++对这些概念只有间接的支持。Java中存在语言关键字这个事实表明人们认为这些思想是很重要的,以至于要提供对它们的直接支持。

首先我们将学习抽象类,它是普通类与接口之间的一种中庸之道。尽管构建具有某些未实现方法的类时,你的第一想法可能是创建接口,但是抽象类仍旧是用于此目的的一种重要而必须的工具,因为你不可能总是使用纯接口。

 

9.1 抽象类和抽象方法

Java提供一个叫做抽象方法的机制,这种方法是不完整的:仅有声明而没有方法体。下面是抽象方法声明所采用的语法:

abstract void f( );

包含抽象方法的类叫做抽象类。如果一个类包含一个或者多个抽象方法,该类必须被限定为抽象的。(否则,编译器就会报错。)

如果一个抽象类不完整,那么当我们试图产生该类的对象时,编译器会怎样处理呢?由于为抽象类创建对象时不安全的,所以我们会从编译器那里得到一条出错消息。这样,编译器会确保抽象类的纯粹性,我们不必担心误用它。

如果从一个抽象类继承,并想创建该新类的对象,那么必须为基类中的所有抽象方法提供方法定义。如果不这样做(可以选择不做),那么导出类便也是抽象类,且编译器将会强制我们用abstract关键字来限定这个类、

我们也可能会创建一个没有任何抽象方法的抽象类。考虑这种情况:如果有一个了,让其包含任何abstract方法方法都显得没有实际意义,而且我们也想要阻止产生这个类的任何对象,那么这时这样做就很有用了。

即使使某个非抽象类成为抽象类并不需要所有的方法都是抽象的,所以仅需将某些方法声明为抽象的即可。如下图所示:

image.png

下面是修改过的“管弦乐器”的例子,其中采用了抽象类和抽象方法:

//: interfaces/music4/Music4.java // Abstract classes and methods. packageinterfaces.music4; 
importpolymorphism.music.Note; 
importstaticnet.mindview.util.Print.*; 
abstractclassInstrument { 
privateinti; // Storage allocated for each publicabstractvoidplay(Noten); 
publicStringwhat() { return"Instrument"; } 
publicabstractvoidadjust(); 
} 
classWindextendsInstrument { 
publicvoidplay(Noten) { 
print("Wind.play() "+n); 
    } 
publicStringwhat() { return"Wind"; } 
publicvoidadjust() {} 
} 
classPercussionextendsInstrument { 
publicvoidplay(Noten) { 
print("Percussion.play() "+n); 
    } 
publicStringwhat() { return"Percussion"; } 
publicvoidadjust() {} 
} 
classStringedextendsInstrument { 
publicvoidplay(Noten) { 
print("Stringed.play() "+n); 
    } 
publicStringwhat() { return"Stringed"; } 
publicvoidadjust() {} 
} 
classBrassextendsWind { 
publicvoidplay(Noten) { 
print("Brass.play() "+n); 
    } 
publicvoidadjust() { print("Brass.adjust()"); } 
} 
classWoodwindextendsWind { 
publicvoidplay(Noten) { 
print("Woodwind.play() "+n); 
    } 
publicStringwhat() { return"Woodwind"; } 
} 
publicclassMusic4 { 
// Doesn’t care about type, so new types // added to the system still work right: staticvoidtune(Instrumenti) { 
// ... i.play(Note.MIDDLE_C); 
    } 
staticvoidtuneAll(Instrument[] e) { 
for(Instrumenti : e) 
tune(i); 
    } 
publicstaticvoidmain(String[] args) { 
// Upcasting during addition to the array: Instrument[] orchestra= { 
newWind(), 
newPercussion(), 
newStringed(), 
newBrass(), 
newWoodwind() 
        }; 
tuneAll(orchestra); 
    } 
}

/* Output:

Wind.play() MIDDLE_C

Percussion.play() MIDDLE_C

Stringed.play() MIDDLE_C

Brass.play() MIDDLE_C

Woodwind.play() MIDDLE_C

*///:~

我们看到除了基类,实际上并没有什么改变。

创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样来使用它们。抽象类还是很有用的重构工具,因为它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动。

 

9.2 接口

interface关键字使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或者多个没有任何定义的方法——提供了接口部分,但是没有提供任何相应的具体实现,这些实现是由此类的继承者创建的。interface这个关键字产生一个完全抽象的类,它根本就没有提供任何具体的实现(新版本的JDK允许接口拥有默认实现)。它允许创建者确定方法名、参数列表和返回类型,但是没有任何方法体。接口只提供形式,而为提供任何具体的实现。

一个接口表示:“所有实现了该特定接口的类看起来都像这样”。因此,任何使用某特定接口的代码都知道可以调用该接口的哪些方法,而且仅需知道这些。因此,接口被用来建立类与类之间的协议。(某些面向对象编程语言使用关键字protocol来完成这一功能。)

但是,interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被相送转型为多种基类的类型,来实现某种类似多重继承的特性。

要想创建一个接口,需要使用interface关键字来替代class关键字。就像一个类一样,可以在interface关键字前面添加public关键字(但仅限于该接口在与其同名的文件中被定义)。如果不添加public关键字,则它只具有包访问权限,这样它就只能在同一个包内可用。接口也可以包含域,但是这些域隐式地是static和final的。

要让一个类遵循某个特定接口或者一组接口,需要使用implements关键字,它表示:“interface只是它的外貌,但是现在我要声明它是如何工作的。”除此以外,它看起来还很像继承。“乐器”示例的图说明了这一点:

image.png

可以从WoodwindBrass类中看到,一旦实现了某个接口,其实现就变成了一个普通的类,就可以按常规方式扩展它。

可以选择在接口中显式地将方法声明为public的,但即使你不这么做,它们也是public的。因此,当要实现一个接口时,在接口中被定义的方法必须被定义为public的;否则它们将只能得到默认的包访问权限,这样在方法被继承的过程中,其可访问权限就被降低了,这是Java编译器所不允许的。

//: interfaces/music5/Music5.java // Interfaces. packageinterfaces.music5; 
importpolymorphism.music.Note; 
importstaticnet.mindview.util.Print.*; 
interfaceInstrument { 
// Compile-time constant: intVALUE=5; // static & final // Cannot have method definitions: voidplay(Noten); // Automatically public voidadjust(); 
} 
classWindimplementsInstrument { 
publicvoidplay(Noten) { 
print(this+".play() "+n); 
    } 
publicStringtoString() { return"Wind"; } 
publicvoidadjust() { print(this+".adjust()"); } 
} 
classPercussionimplementsInstrument { 
publicvoidplay(Noten) { 
print(this+".play() "+n); 
    } 
publicStringtoString() { return"Percussion"; } 
publicvoidadjust() { print(this+".adjust()"); } 
} 
classStringedimplementsInstrument { 
publicvoidplay(Noten) { 
print(this+".play() "+n); 
    } 
publicStringtoString() { return"Stringed"; } 
publicvoidadjust() { print(this+".adjust()"); } 
} 
classBrassextendsWind { 
publicStringtoString() { return"Brass"; } 
} 
classWoodwindextendsWind { 
publicStringtoString() { return"Woodwind"; } 
} 
publicclassMusic5 { 
// Doesn’t care about type, so new types // added to the system still work right: staticvoidtune(Instrumenti) { 
// ... i.play(Note.MIDDLE_C); 
    } 
staticvoidtuneAll(Instrument[] e) { 
for(Instrumenti : e) 
tune(i); 
    } 
publicstaticvoidmain(String[] args) { 
// Upcasting during addition to the array: Instrument[] orchestra= { 
newWind(), 
newPercussion(), 
newStringed(), 
newBrass(), 
newWoodwind() 
        }; 
tuneAll(orchestra); 
    } 
}

/* Output:

Wind.play() MIDDLE_C

Percussion.play() MIDDLE_C

Stringed.play() MIDDLE_C

Brass.play() MIDDLE_C

Woodwind.play() MIDDLE_C

*///:~

目录
打赏
0
0
0
0
97
分享
相关文章
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
随着大模型的越来越盛行,现在很多企业开始接入大模型的接口,今天我从java开发角度来写一个demo的示例,用于接入DeepSeek大模型,国内的大模型有很多的接入渠道,今天主要介绍下阿里云的百炼模型,因为这个模型是免费的,只要注册一个账户,就会免费送百万的token进行学习,今天就从一个简单的可以执行的示例开始进行介绍,希望可以分享给各位正在学习的同学们。
124 3
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
243 5
|
4月前
|
在Java中如何实现接口?
实现接口是 Java 编程中的一个重要环节,它有助于提高代码的规范性、可扩展性和复用性。通过正确地实现接口,可以使代码更加灵活、易于维护和扩展。
284 64
|
4月前
|
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
407 60
|
4月前
|
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
233 58
|
4月前
|
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
145 38
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
3月前
|
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
73 6
|
4月前
|
Java中内置的函数式接口
Java中内置的函数式接口
60 2
|
4月前
|
Eclipse 创建 Java 接口
Eclipse 创建 Java 接口
58 1