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

抽象类和抽象方法

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

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. RabbitMQ启动出现的问题与解决办法

    问题1 使用命令启动 service rabbitmq-server start 报错如下: Starting rabbitmq-server (via systemctl): Job for rab ...

  2. 字典排序MD5生成代码

    /* * Project: payment.framework * * File Created at 2017年12月23日 * * Copyright 2016 CMCC Corporation ...

  3. FastJson实现复杂对象序列化与反序列化

    原文:http://blog.csdn.net/xqhadoop/article/details/62217954 一.认识FastJson 1.优势 fastjson是目前java语言中最快的jso ...

  4. Solr新特性【4.x,5.x,6.x,7.x】

    一.Solr4.x新特性 1.近实时搜索 Solr的近实时搜索[Near Real-Time,NRT]功能实现了文档添加到搜索的快速进行,以应对搜索快速变化的数据. 2.原子更新与乐观并发 原子更新功 ...

  5. Springboot+Mybatis的逆向工程

    Mybatis逆向工程,自动生成 entity类和常用的增删改查方法. 1.pom.xml引入类 <!-- 通用mapper 用于mabatis封装的基础增删改查的功能--><dep ...

  6. SQL注入基础

    注入点的判断: 首先判断该注入点是怎么闭合的,常用的是','),')),",再利用and 1=2,and 1=1判断闭合是否正确 sql注入常用语句: 普通语句:schema_name——数 ...

  7. Jmeter中Switch Controller逻辑控制器用法

    当Switch Controller中Switch Value设置为0时,执行第0+1个子节点:Switch Value设置为1时,执行第1+1个子节点:Switch Value设置为2时,执行第2+ ...

  8. DateFormat与SimpleDateFormat区别和使用详解

    DateFormat类 此类是一个日期的格式化类,用来格式化日期.具体日期可以通过java.util.Date类来获取. DateFormat类的定义:此类是定义在java.test包中的. publ ...

  9. JS定时器实现函数节流和防抖 -简单实现对比 -适用地方

    如题 (总结要点) 防止重复点击! 最近项目中遇见这个"函数抖动"的问题!快速点击前端xx按钮,造成数据多次加载进页面里,正常只显示10条数据,结果显示了20条数据,异常! 出现原 ...

  10. 20180418模拟赛T1——Seq

    Seq (seq.cpp/c/pas) 题目描述 Description 木吉要去征讨VAN様,所以他现在需要从他身边的人中选出若干位陪同.现在有\(n\)个人站成一行,木吉要从其中选出\(2\)批在 ...