Java编程思想4

第九章:接口
接口也可以包含域,但是这些域隐式地是static和final的(因此接口就成为了一种很便捷的用来创建常量组的工具)。你可以选择在接口中显示地将方法声明为public的,但即使你不这么做,它们也是public的。因此,当要实现一个接口时,在接口中被定义的方法必须被定位为是public的;否则,它们将只能得到默认的包访问权限,这样在方法被继承的过程中,其可访问权限就降低了,这是Java编译器所不允许的。

如果要从一个非接口的类继承,那么只能从一个类去继承。其余的基本元素都必须是都必须是接口。需要将所有的接口名都置于implements关键字之后,用逗号将它们一一隔开。可以继承任意多个接口,并可以向上转型为每个接口,因为每一个接口都是一个独立类型。下面这个例子展示了一个具体类组合数个接口之后产生了一个新类。

interface CanFight {
void fight();
}

interface CanSwim {
void swim();
}

interface CanFly {
void fly();
}

class ActionCharacter {
public void fight() {}
}

/**
* 当通过这种方式将一个具体类和多个接口组合在一起时,这个具体类必须放在前面,
* 后面跟着的才是接口(否则编译器会报错)
*/
class Hero extends ActionCharacter
implements CanFight, CanFly, CanSwim {

@Override
public void swim() { }

@Override
public void fly() { }
}

public class Adventure {
public static void t(CanFight x) { x.fight(); }
public static void f(CanFly x) { x.fly(); }
public static void s(CanSwim x) { x.swim(); }
public static void a(ActionCharacter x) { x.fight(); }

public static void main(String[] args) {
Hero h = new Hero();
t(h);
f(h);
s(h);
a(h);
}
}

该例也展示了使用接口的两个核心原因:

为了能够向上转型为多个基类型(以及由此而带来的灵活性)

防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口

我们也可以通过继承来扩展接口;通过继承,可以很容易地在接口中添加新的方法声明,还可以通过继承在新接口中组合数个接口。如下:

interface Monster {
void menace();
}

interface DangerousMonster extends Monster {
void destroy();
}

interface Lethal {
void kill();
}

class DragonZilla implements DangerousMonster {
@Override
public void menace() {}

@Override
public void destroy() {}
}

/**
* 改语法仅适用于接口继承
*/
interface Vampire extends DangerousMonster, Lethal {
void drinkBlood();
}

class VeryBadVampire implements Vampire {
@Override
public void menace() {}

@Override
public void destroy() {}

@Override
public void kill() {}

@Override
public void drinkBlood() {}
}

public class HorrorShow {
static void u(Monster b) { b.menace(); }
static void v(DangerousMonster d) {
d.menace();
d.destroy();
}
static void w (Lethal l) {
l.kill();
}

public static void main(String[] args) {
DangerousMonster barny = new DragonZilla();
u(barny);
v(barny);
Vampire vlad = new VeryBadVampire();
u(vlad);
v(vlad);
w(vlad);
}
}

由于接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的时创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,我们的代码将完全与接口的实现分离,这就使得我我们可以透明地将某个实现替换成另一个实现,下面的实例展示了工厂方法的结构:

interface Service {
void method1();
void method2();
}

interface ServiceFactory {
Service getService();
}

class Implementation1 implements Service {
Implementation1() { }

@Override
public void method1() {
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
System.out.println("Implementation1 method2");
}
}


class Implementation1Factory implements ServiceFactory {
@Override
public Service getService() {
return new Implementation1();
}
}

class Implementation2 implements Service {
Implementation2() { }

@Override
public void method1() {
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
System.out.println("Implementation2 method2");
}
}


class Implementation2Factory implements ServiceFactory {
@Override
public Service getService() {
return new Implementation2();
}
}

public class Factories {
public static void serviceConsumer(ServiceFactory factory) {
Service s = factory.getService();
s.method1();
s.method2();
}

public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}

}

 

posted @   就叫清风吧  阅读(34)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示