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

抽象类和抽象方法

创建一个抽象类是希望通过这个通用接口操纵一系列类。

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编程思想之九 接口的更多相关文章

  1. java编程思想第九章接口

    9.1抽象类和抽象方法 为什么要有抽象类? 是希望通过通用接口操作一系列类. 那么抽象类的形式是什么样的呢? 声明类的使用使用abstract关键字,且在该类中应该具有抽象方法. 注:抽象方法被关键字 ...

  2. Java编程思想学习(九) 异常处理

    java的异常处理机制可以使程序有极好的容错性,让程序更加的健壮.所谓的异常,就是指的阻止当前方法或作用域继续执行的问题,,当程序运行时出现异常时,系统就会自动生成一个Exception对象来通知程序 ...

  3. Java编程思想学习笔记——接口

    1.抽象类和抽象方法 抽象方法:不完整的,仅有声明而没有方法体. abstract void f(); 抽象类:包含抽象方法的类.(若一个类包含一个或多个抽象方法,则该类必须限定为抽象的.) 1.用抽 ...

  4. Java编程思想 第九章 接口

    第九章 接口 抽象类和抽象方法 抽象:从具体事物抽出.概括出它们共同的方面.本质属性与关系等,而将个别的.非本质的方面.属性与关系舍弃,这种思维过程,称为抽象. 这句话概括了抽象的概念,而在Java中 ...

  5. 《Java编程思想》阅读笔记二

    Java编程思想 这是一个通过对<Java编程思想>(Think in java)进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会忽略或 ...

  6. Java编程思想——第17章 容器深入研究(two)

    六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...

  7. JAVA编程思想——分析阅读

    需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...

  8. 《Java编程思想》读书笔记(四)

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  9. Java编程思想重点笔记(Java开发必看)

    Java编程思想重点笔记(Java开发必看)   Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...

随机推荐

  1. React Hooks --- useState 和 useEffect

    首先要说的一点是React Hooks 都是函数,使用React Hooks,就是调用函数,只不过不同的Hooks(函数)有不同的功能而已.其次,React Hooks只能在函数组件中使用,函数组件也 ...

  2. 《JavaScript高级程序设计》笔记:附录A ECMAScript Harmony

    一般性变化 常量 用const关键字声明常量,声明的变量在初始赋值后,就不能进行修改了,如下代码: const MAX_SIZE = 25; MAX_SIZE = 10; //报错 块级作用域及其他作 ...

  3. Android Handler类 发送消息-post()和postDelay(), Looper讲解

    https://blog.csdn.net/weixin_41101173/article/details/79701832 首先,post和postDelay都是Handler的方法,用以在子线程中 ...

  4. 数据结构与算法—simhash

    引入 随着信息爆炸时代的来临,互联网上充斥着着大量的近重复信息,有效地识别它们是一个很有意义的课题. 例如,对于搜索引擎的爬虫系统来说,收录重复的网页是毫无意义的,只会造成存储和计算资源的浪费: 同时 ...

  5. Prometheus学习笔记(4)什么是pushgateway???

    目录 一.pushgateway介绍 二.pushgateway的安装运行和配置 三.自定义脚本发送pushgateway 四.使用pushgateway的优缺点 一.pushgateway介绍 pu ...

  6. Vim 中进行文件目录操作

    Vim 中进行文件目录操作 当前文件名 我们知道Vim有48个寄存器,其中%只读寄存器中保存着当前文件路径. 例如在/home/harttle/下打开src/main.cpp,我们打印%的值: :ec ...

  7. 带你快速上手前端三剑客之css

    CSS介绍 ​ CSS(Cascading Style Sheet , 层叠样式表)定义如何显示HTML元素.当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染) 组成 ​ 每个CS ...

  8. (六)Kubernetes Pod控制器-ReplicaSet和Deployment和DaemonSet

    Pod控制器相关知识 控制器的必要性 自主式Pod对象由调度器调度到目标工作节点后即由相应节点上的kubelet负责监控其容器的存活状态,容器主进程崩溃后,kubelet能够自动重启相应的容器.但对出 ...

  9. django项目中使用KindEditor富文本编辑器。

    先从官网下载插件,放在static文件下 前端引入 <script type="text/javascript" src="/static/back/kindedi ...

  10. 洛谷 P3071 [USACO13JAN]座位Seating(线段树)

    P3071 [USACO13JAN]座位Seating 题目链接 思路: 一开始把题给读错了浪费了好多时间呜呜呜. 因为第二个撤离操作是区间修改,所以我们可以想到用线段树来做.对于第一个操作,我们只需 ...