Java编程思想之九 接口
接口和内部为我们提供了一种将接口与实现分离的更加结构化的方法。
抽象类和抽象方法
创建一个抽象类是希望通过这个通用接口操纵一系列类。
Java提供了一个叫做抽象方法的机制,这种方法是不完整的;仅声明而没有方法体。
abstract void f();
包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,那么该类必须限定为抽象的。
如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类的所有抽象方法提供方法定义。
9.2 接口
一个接口表示:所有实现该特定接口的类看起来都像这样。任何使用某特定接口的代码都指定可以调用该接口的哪些方法,而且仅需要知道这些。接口被用来建立类与类之间的协议。
interface不仅仅是一个极度抽象的类,它允许人们通过创建一个能够被向上转型的多种基类的类型,来实现某种类似多重继变种的特性。
创建一个接口,需要用到interface替换关键字class。
9.3 完全解耦
只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类。
创建一个能够根据所传递参数对象不同而具有不同行为的方法,这被称为策略模式。这类方法包含所有执行的算法中固定不变的部分,而策略包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。
class Process{
public String name(){
return getClass().getName();
}
Object process(Object input){
return input;
}
}
class Process1 extends Process{
Object process(Object input){
return ((String)input).toUpperCase();
}
}
class Process2 extends Process{
Object process(Object input){
return ((String)input).toLowerCase();
}
}
class Process3 extends Process{
Object process(Object input){
return ((String)input).toCharArray()[0];
}
}
class Process4 extends Process{
Object process(Object input){
return ((String)input).toCharArray()[1];
}
}
public class Apply {
public static void processint(Process p,Object s){
System.out.println("Process:"+p.name()+"+"+p.process(s));
}
public static void main(String[] args){
processint(new Process1(),"S1");
processint(new Process2(),"s2");
processint(new Process3(),"s3");
processint(new Process4(),"s4");
}
}
9.4 Java中的多重继承
接口不仅仅只是一种更纯粹形式的抽象。因为接口是根本没有任何具体实现的:没有任何与接口相关的存储,所有,多个接口可以组合。
在导出类中,不强制必须有一个是抽象的或具体的基类,如果从一个非接口类继承,就只能是一个,其余元素都必须是接口。
interface CanFight{
void fight();
}
interface CanFly{
void fly();
}
interface CanSwim{
void swim();
}
class Actions{
public void fight(){
}
}
class hero extends Actions implements CanFight,CanFly,CanSwim
{
//如果需要继承接口,则需要是public
@Override
public void fly() {
}
@Override
public void swim() {
}
}
当一个导出类中有基类和接口时,基类必须放在最前面。
使用接口的主要原因:能够向上转型为多个基类型。
第二个原因与使用抽象类相同:防止客户端程序员创建该类对象,并确保者仅仅是一个接口。
9.5 通过继承来扩展接口
public class HorrorShow {
static void u(Monster b){
b.manse();
}
static void v(DangerousMonster d){
d.manse();
d.destroy();
}
static void w(Lethal l){
l.kill();
}
public static void main(String[] args){
DangerousMonster barney =new DragonZilla();
u(barney);
v(barney);
Vampire vlad=new VeryBadVampire();
u(vlad);
v(vlad);
w(vlad);
}
}
interface Monster{
void manse();
}
interface DangerousMonster extends Monster{
void destroy();
}
interface Lethal{
void kill();
}
class DragonZilla implements DangerousMonster{
@Override
public void manse() {
}
@Override
public void destroy() {
}
}
interface Vampire extends DangerousMonster,Lethal{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
@Override
public void manse() {
}
@Override
public void destroy() {
}
@Override
public void kill() {
}
@Override
public void drinkBlood() {
}
}
只可以将extends用于单一类,但是可以引用多个基类接口。但需要用逗号隔开。
9.5.1 组合接口时名字冲突
interface I1{
void f();
}
interface I2{
int f(int i);
}
interface I3{
int f();
}
class C0{
public int f(){
System.out.println("C0.f");
return 0;
}
}
class C1 implements I1,I2{
@Override
public void f() {
System.out.println("C1.f()");
}
@Override
public int f(int i) {
System.out.println("C1.f(i)");
return 0;
}
}
class C2 extends C1 implements I2{
@Override
public int f(int i) {
System.out.println("C2.f(i)");
return 0;
}
}
class C3 extends C0 implements I3{
public int f(int i){
System.out.println("C3.f(i)");
return 0;
}
}
/*class C4 extends C0 implements I1{
}*///无法使用
9.6 适配接口
允许同一个接口具有多个不同的实现。它的形式通常是:一个接受接口类型的方法,而该接口的实现和向该方法传递的对象则取决于方法的使用者。
接口的一种常见用法就是策略模式。
使用接口,你主要声明:你可以用任何你想要的对象来调用我的方法,只要你的对象遵循了我的接口。
我们可以再任何有类之上添加新的接口,所有这意味着让方法接受接口类型,是一种让任何类都可以对该方法进行适配的方式。这就是使用接口而不是类的强大之处。
9.7 接口中的域
接口中任何域都自动是static和final的。
public class C11 {
public static void main(String[] args){
System.out.println(A1.i1+":"+A1.i2+":"+A1.i3);
}
}
interface A1{
int i1=1,i2=2,i3=3;
}
9.7.1 初始化接口中的域
再接口中定义的域不能是空final,但是可以被非常量表达式初始化。
public class C11 {
public static void main(String[] args){
System.out.println(A1.i);
System.out.println(A1.i);
System.out.println(A1.i);
}
}
interface A1{
int i=new Random(47).nextInt(58);
}
既然域是static的,它们就可以再类第一次被加载时初始化,这发生在任何域首次被访问。
但这些域不是接口的一部分,它们的值被存储在该接口的静态存储区域类。
9.8 嵌套接口
接口可以嵌套在类或其他接口中。
public class NestingInterfaces {
public static void main(String[] args){
A a=new A();
A.D ad=a.getD();
}
public class BImp implements A.B {
@Override
public void f() {
}
class CImp implements A.C{
@Override
public void f() {
}
}
class EImp implements E{
@Override
public void g() {
}
}
class EGImp implements E.G{
@Override
public void f() {
}
}
class EImp2 implements E{
@Override
public void g() {
}
}
class EG implements E.G{
@Override
public void f() {
}
}
}
}
class A{
interface B{
void f();
}
public class BImp implements B{
@Override
public void f() {
}
}
private class BImp2 implements B{
public void f(){
}
}
public interface C{
void f();
}
class CImp implements C{
@Override
public void f() {
}
}
private class CImp2 implements C{
@Override
public void f() {
}
}
public interface D{
void f();
}
class DImp implements D{
@Override
public void f() {
}
}
private class DImp2 implements D{
@Override
public void f() {
}
}
public D getD(){
return new DImp2();
}
private D dRef;
public void receiveD(D d){
dRef=d;
dRef.f();
}
}
interface E{
interface G{
void f();
}
public interface H{
void f();
}
void g();
}
在类中嵌套接口就像非嵌套接口一样,可以拥有public和包访问两种可视性。
9.9 接口与工厂
接口是实现多继承的途径,而生成遵循某个接口的对象的典型方式就是工厂模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,通过这种方法,我们的代码将完全与接口实现分离,这就使得我们可以透明的将某个实现替换为另一个实现。
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s=fact.getService();
s.menthod();
s.method2();
}
public static void main(String[] args){
serviceConsumer(new I1F());
serviceConsumer(new I2F());
}
}
interface Service{
void menthod();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Im1 implements Service{
Im1(){}
@Override
public void menthod() {
System.out.println("I1menthod");
}
@Override
public void method2() {
System.out.println("I1method2");
}
}
class I1F implements ServiceFactory{
@Override
public Service getService() {
return new Im1();
}
}
class Im2 implements Service{
Im2(){}
@Override
public void menthod() {
System.out.println("I2menthod");
}
@Override
public void method2() {
System.out.println("I2method2");
}
}
class I2F implements ServiceFactory{
@Override
public Service getService() {
return new Im2();
}
}
但我们为什么要使用这种额外的间接性呢?常见原因就是使用框架。
Java编程思想之九 接口的更多相关文章
- java编程思想第九章接口
9.1抽象类和抽象方法 为什么要有抽象类? 是希望通过通用接口操作一系列类. 那么抽象类的形式是什么样的呢? 声明类的使用使用abstract关键字,且在该类中应该具有抽象方法. 注:抽象方法被关键字 ...
- Java编程思想学习(九) 异常处理
java的异常处理机制可以使程序有极好的容错性,让程序更加的健壮.所谓的异常,就是指的阻止当前方法或作用域继续执行的问题,,当程序运行时出现异常时,系统就会自动生成一个Exception对象来通知程序 ...
- Java编程思想学习笔记——接口
1.抽象类和抽象方法 抽象方法:不完整的,仅有声明而没有方法体. abstract void f(); 抽象类:包含抽象方法的类.(若一个类包含一个或多个抽象方法,则该类必须限定为抽象的.) 1.用抽 ...
- Java编程思想 第九章 接口
第九章 接口 抽象类和抽象方法 抽象:从具体事物抽出.概括出它们共同的方面.本质属性与关系等,而将个别的.非本质的方面.属性与关系舍弃,这种思维过程,称为抽象. 这句话概括了抽象的概念,而在Java中 ...
- 《Java编程思想》阅读笔记二
Java编程思想 这是一个通过对<Java编程思想>(Think in java)进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会忽略或 ...
- Java编程思想——第17章 容器深入研究(two)
六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...
- JAVA编程思想——分析阅读
需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...
- 《Java编程思想》读书笔记(四)
前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...
- Java编程思想重点笔记(Java开发必看)
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
随机推荐
- 微信小程序必知相关知识
微信小程序必知相关知识 1 请谈谈微信小程序主要目录和文件的作用? project.config.json 项目配置文件,用得最多的就是配置是否开启https校验: App.js 设置一些全局的基础数 ...
- ES6 之 对象的简写方式
简写有两条基本原则: 同名的属性可以省略不写 对象中的方法中的 : function 可以省略不写 来看下下面这个例子,我分别用ES5 和 ES6 的语法分别定义并声明了一个简单的学生对象: ES5: ...
- Eclipse apk项目创建和项目构架
一.创建项目工程 设定名字 设定包名(每一台机器只有唯一的包名)下一步 根据设置进行选择 创建空项目 Finish即可创建 调节项目的字体 二.Eclipse 项目构架 Src 2. Gen R.ja ...
- 假设检验、T检验
假设检验初步: https://cosx.org/2010/11/hypotheses-testing t检验:https://mangowu97.github.io/%E5%82%BB%E7%93% ...
- Mycat配置项详解
schema.xml文件配置中的balance属性和writeType属性: . balance=", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上. . ba ...
- HTML那些标签已废弃,被代替
表单:cellpadding,cellspacing属性:已废弃, 替代者: table { border-collapse:collapse; } table, td, th { border:1p ...
- CodeForces - 348D:Turtles(LGV定理)
题意:给定N*M的矩阵,'*'表示可以通过,'#'表示不能通过,现在要找两条路径从[1,1]到[N,M]去,使得除了起点终点,没有交点. 思路:没有思路,就是裸题. Lindström–Gessel ...
- Java批量下载文件并zip打包
客户需求:列表勾选需要的信息,点击批量下载文件的功能.这里分享下我们系统的解决方案:先生成要下载的文件,然后将其进行压缩,生成zip压缩文件,然后使用浏览器的下载功能即可完成批量下载的需求.以下是zi ...
- Convert.ToByte((int)val)
static void Main(string[] args) { ; byte bit8 = Convert.ToByte((int)val); Console.WriteLine("[{ ...
- C++编译器与链接器工作原理
http://blog.csdn.net/success041000/article/details/6714195 1. 几个概念 1)编译:把源文件中的源代码翻译成机器语言,保存到目标文件中.如果 ...