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

抽象类和抽象方法

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

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();
}
}

但我们为什么要使用这种额外的间接性呢?常见原因就是使用框架。

05-28 21:46