您的位置:首页 > 编程语言 > Java开发

Java编程思想(9)接口

2018-01-20 23:34 267 查看

抽象类和抽象方法(abstract)

1、有些基类的方法往往是哑方法。实际上是无实际意义的。这些类的目的是为它所有导出类创建一个通用接口。
2、创建一个这样的类对象没有意义,甚至还要阻挡使用者这样做。
3、Java提供一个叫做抽象方法的机制。这种方法不完整,仅声明而没有方法体,如下格式:
  abstract void f();
  用abstract关键字,且不包含f()的具体实现。
4、包含抽象方法的类叫做抽象类(只要有一个就是,虽然可能有其他方法不一定是抽象方法),该类被定义为抽象的。
5、编译器会阻止构建抽象类的对象。
6、从一个抽象类继承,并想创建新类的对象的话,必须为基类中所有的抽象方法提供方法定义。如果不这样做,那导出类也必须是abstract的。编译器这一关就过不了。
7、也可以创建一个没有任何抽象方法的抽象类,其目的是阻止创建这个类的任何对象。

接口(interface)

1、abstract关键字允许在类中创建一个或多个没有定义的方法,只有接口。这些方法实现由类的继承者创建。
2、interface则产生一个完全抽象的类,没有实现任何一个方法。这样,任何使用某特定接口的代码都知道可以调用接口的那些方法。因此,接口可以用来建立类与类之间的协议。
3、把class替换成interface,就可完成定义。
    interface Instrument{
        void play(Note n);
void adjust();
}

4、要让一个类遵循某个特定接口(或一组接口),需要使用implements关键字。它表示本类将实现接口具体如何工作,且遵循这些接口的定义要求。
5、接口中方法缺省是public的,也必须是public的。

6、一个小例子。定义了Instrument接口,实现了Wind和Brass两个类,遵循这个接口。

package C_09;
//这里定义了一个简单的枚举,用于其他地方引用。
public enum Note01 {
C,D,E,F,G,A,B
}
package C_09;

import java.util.*;
import C_09.Note01;

interface Instrument{
void play(Note01 n);
void adjust();
}

class Wind implements Instrument{
public void play(Note01 n) {
System.out.println(this +".play()"+n);
}

public void adjust() {
System.out.println(this+".adjust()");
}
}

class Brass implements Instrument{
public void play(Note01 n) {
System.out.println(this +".play()"+n);
}

public void adjust() {
System.out.println(this+".adjust()");
}
public String toString() {return "Brass"; }
}

public class Music5Interface01 {

public static void main(String[] args) {
Instrument[] orchestra = {new Wind(),new Brass()};
orchestra[0].play(Note01.B);
orchestra[1].play(Note01.E);
// TODO Auto-generated method stub

}
}
结果为:

C_09.Wind@122bbb7.play()B

Brass.play()E

因为Brass实现了toSting()方法,打印好看点。

完全解耦

1、

多重继承

1、接口没有任何具体实现,也就是说没有任何与接口相关的存储。因此,无法阻止多个接口的组合。
2、如果从一个非接口类型继承,只能从一个类继承,其余的都是接口。将所有接口名都置于implements之后,用逗号隔开。可以继承任意多个接口,并可以向上转型成为每个接口,因为每个接口都是一个独立类型。
3、看以下例子:

package C_09;

//第一个接口
interface CanFight{
void fight();
}

//第二个接口
interface CanSwim{
void swim();
}

//第三个接口
interface CanFly{
void fly();
}

class ActionCharacter{
//这里的flight与上面CanFlight()没什么关系,同名
public void fight() {System.out.println("fight01");};
}

class Hero extends ActionCharacter implements  CanFight,CanSwim,CanFly{
//因为Hero继承自ActionCharacter,所以继承了它的flight()方法,所以天然完成了CanFlight接口的flight()方法。
//此处只需要实现另外两个接口要求的方法。

public void swim() {System.out.println("swim01");}
public void fly() {System.out.println("fly01");}

}
public class Adventure {

//这里定义4个函数,实际是用来体现子类向上转型时,可以作为不同基类的参数输入。
public static void t(CanFight x) {x.fight();}
public static void u(CanSwim x) {x.swim();}
public static void v(CanFly x) {x.fly();}
public static void w(ActionCharacter x) {x.fight();}

public static void main(String[] args) {
// TODO Auto-generated method stub
//子类对象
Hero hero = new Hero();
//同一个参数,调用时,方法参数类型不同,实现向上转型
t(hero); //这里看做是一个CanFight
u(hero);
v(hero);
w(hero);//这里看做是一个ActionCharacter

}

}


输出结果为:
fight01
swim01
fly01
fight01
Adventure类中,四个方法把不同接口和具体类作为参数。当Hero对象创建后,可以传给这些方法,它会被向上转型称为每一个接口。采用这种机制,防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口。
好处仅仅如此?那为什么需要多重继承?--看了一些实践的代码,有感觉了。就是,你实现一个类,它可以遵循多个定义好的接口标准。这就是好处。
4、建议,如果知道某事物应该成为一个基类,第一选择应该是使它成为一个接口。
5、这里有强调:使用接口的核心原因:为了能够向上转型为多个基类型。(实际这里不是要求转型,因为上级也没定义实现,而是说实现的代码同时遵循多种接口标准,具有多重能力,且对外表现是可预期的(因为有基类方法约束))。

通过继承来扩展接口

1、如继承类一样,接口也可以继承,并可以添加新的方法声明。如:
package C_09;
//继承关系
//A---B------|----D
//    C------+

interface A{
void f1();
}

interface B extends A{
void f2();
}

interface C{
void f3();
}

interface D extends B,C{
void f4();
}

A是接口,B继承自A,C是独立接口,D继承自B,C。
在定义实现接口的类时,后面继承的可以重载前面的。
如:实现接口B

//针对B接口,需要实现f1,f2两个方法
class ClassB implements B{
public void f1() {System.out.println("ClassB--f1()");}
public void f2() {System.out.println("ClassB--f2()");}


实现接口D的时候,就得把前面的都实现了。
//定义实现接口的类
class ClassD implements D{
public void f1(){System.out.println("ClassD--f1()");}
public void f2(){System.out.println("ClassD--f2()");}
public void f3(){System.out.println("ClassD--f3()");}
public void f4(){System.out.println("ClassD--f4()");}
}
注意,虽然ClassB实现了B的接口,但与ClassD没有什么关系,在D里面都得实现。

然后再一个类里面创建相应对象,体现对这些接口的使用。
public class HorrorShow {
//方法定义输入参数为基类接口
static void u(A a) {a.f1();}

static void v(B b) {
b.f1();
b.f2();
//注意,这里因为参数为基类接口,所以,即使实际传入的参数是子类对象,已经实现了子接口的方法。

}
public static void main(String[] args) {
// TODO Auto-generated method stub
//用上一级的基类来声明变量,具体对象还得用实现类来创建。
D varClassD = new ClassD();
varClassD.f1();
varClassD.f2();
varClassD.f3();
varClassD.f4();
//
System.out.println("-------------");
B varClassB = new ClassB();
varClassB.f1();
varClassB.f2();
System.out.println("-------------");
u(varClassB);
v(varClassB);
System.out.println("-------------");
u(varClassD);
v(varClassD);

//	A varInterfaceA = new

}

}
输出如下:
ClassD--f1()

ClassD--f2()

ClassD--f3()

ClassD--f4()

-------------

ClassB--f1()

ClassB--f2()

-------------

ClassB--f1()

ClassB--f1()

ClassB--f2()

-------------

ClassD--f1()

ClassD--f1()

ClassD--f2()

注意:尽量避免在不同接口中使用相同的方法名,通常会造成混乱。

适配接口

1、从接口的使用上来看,很明显,同一个接口可以具有多个不同的实现。
2、其效果就是,不管你怎么实现你的类方法,只要你遵循一个接口,其他人就知道怎么调用了。
3、可以在任何现有类上添加新的接口。
4、这里特别介绍一下Sanner类。
   1)java.util.Scanner是Java5的新特征,主要功能是简化文本扫描。
   2)Scanner的构造器支持多种方式,可以从字符串(Readable)、输入流、文件等等来直接构建Scanner对象,有了Scanner了,就可以逐段(根据正则分隔式)来扫描整个文本,并对扫描后的结果做想要的处理。
  3)它可以接受一个Readable接口(专为Scanner设计的)的构造器。
  4)如果想让Scanner作用于一个类,就可以通过让它实现Readabl接口。只要实现其read()方法,就可以用Scanner作用到新定义的类了。实现read(CharBuff cb),把要被扫描的数据添加到cb中去,就可以用Scanner访问了。具体参见书上代码吧。

接口中的域--用接口实现枚举

1、放入接口中的任何域都自动是static和final的。所以接口也可以用来创建常量。在Java SE5之前,这是产生于C的枚举类型具有相同效果的唯一途径。
2、可以用常量直接赋值,也可以用表达式初始化。
package C_09;

import java.util.Random;

public interface EnumTest {
int  ONE =1, TWO =2;  //直接赋值
Random RAND = new Random(40);
int RANDOM_INT = RAND.nextInt(10);  //用表达式初始化
long RANDOM_LONG = RAND.nextLong()*10;
double RANDOM_DOUBLE=RAND.nextDouble()*10;

}

3、然后就可以直接用了,如下:
package C_09;

import C_09.EnumTest;
public class TestEnumInterface {

public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(EnumTest.ONE);
System.out.println(EnumTest.RANDOM_DOUBLE);
System.out.println(EnumTest.RANDOM_INT);
System.out.println(EnumTest.RANDOM_LONG);
}

}
输出如下:
1
6.501284755664213
2
-1341133541859225106


这一章断断续续10来天了,还余下工厂模式和嵌套没解读完。看了一下,工厂模式还比较复杂,后面专门做一次补充吧。这次先发出来,不然感觉没完没了。

------------2018.1.20  23:32 深圳

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: