接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。这种机制在编程语言中并不通用,Java语言提供了关键字说明人们认为这些思想是重要的。还有另一个概念叫做抽象类,它是介于普通的类与接口之间的一个中庸之道。尽管在构造某些具有未实现方法的类时,你第一想到的可能是接口,但是抽象类仍旧是一种用于此目的的一种重要而必须的工具。因为你不可能总是使用纯接口。
一、抽象类和抽象方法
abstract void f();
包含上述抽象方法的类叫做抽象类,如果一个类中包含一个或多个抽象方法,那么这个类就必须被定义为抽象的,也就是抽象类。抽象类的关键字也是abstract。抽象类是不安全的,因为它不完整,所以当它试图创建对象的时候,编译器会报错。如果一个类继承自抽象类,并想创建新类的对象,那么这个类必须为基类中的所有抽象方法提供具体的方法体,否则的话这个类也要被声明为抽象类。我们也可能会创建一个没有任何抽象方法的抽象类,比如当我们一个类中的任何方法都没有存在的意义时,或者也没有被声明为abstract的意义时,恰好我们又需要让这个类不能够创建对象,那么这时一个没有任何抽象方法的抽象类就产生了它的作用。
package com.chenxyt.java.test;
abstract class Instrument{
private int i;
public String what(){
return "Instrumet";
}
public abstract void play(String s);
public void adjust(){};
}
class Wind extends Instrument{
public String what(){
return "Wind";
}
public void play(String s){
System.out.println("Wind.play" + s);
}
public void adjust(){};
}
class Percussion extends Instrument{
public String what(){
return "Percussion";
}
public void play(String s){
System.out.println("Percussion.play" + s);
}
public void adjust(){};
}
class Stringed extends Instrument{
public String what(){
return "Stringed";
}
public void play(String s){
System.out.println("Stringed.play" + s);
}
public void adjust(){};
}
class Brass extends Instrument{
public String what(){
return "Brass";
}
public void play(String s){
System.out.println("Brass.play" + s);
}
public void adjust(){};
}
class WoodWind extends Instrument{
public String what(){
return "WoodWind";
}
public void play(String s){
System.out.println("WoodWind.play" + s);
}
public void adjust(){};
}
public class Music{
static void tune(Instrument i ){
i.play("finish");
}
static void tuneAll(Instrument[] e){
for(Instrument i:e){
tune(i);
}
}
public static void main(String[] args) {
Instrument[] iArray = {
new Wind(),new Percussion(),new Brass(),new Stringed(),new WoodWind()
};
tuneAll(iArray);
}
}
运行结果:

二、接口
package com.chenxyt.java.test;
interface Instrument{
public void play(String s);
}
class Wind implements Instrument{
public String what(){
return "Wind";
}
public void play(String s){
System.out.println("Wind.play" + s);
}
public void adjust(){};
}
class Percussion implements Instrument{
public String what(){
return "Percussion";
}
public void play(String s){
System.out.println("Percussion.play" + s);
}
public void adjust(){};
}
class Stringed implements Instrument{
public String what(){
return "Stringed";
}
public void play(String s){
System.out.println("Stringed.play" + s);
}
public void adjust(){};
}
class Brass implements Instrument{
public String what(){
return "Brass";
}
public void play(String s){
System.out.println("Brass.play" + s);
}
public void adjust(){};
}
class WoodWind implements Instrument{
public String what(){
return "WoodWind";
}
public void play(String s){
System.out.println("WoodWind.play" + s);
}
public void adjust(){};
}
public class Music{
static void tune(Instrument i ){
i.play("finish");
}
static void tuneAll(Instrument[] e){
for(Instrument i:e){
tune(i);
}
}
public static void main(String[] args) {
Instrument[] iArray = {
new Wind(),new Percussion(),new Brass(),new Stringed(),new WoodWind()
};
tuneAll(iArray);
}
}
结果如下:

三、完全解耦
package com.chenxyt.java.test;
import java.util.Arrays;
class Processor{
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class UpCase extends Processor{
String process(Object input){
return input.toString().toUpperCase();
}
}
class DownCase extends Processor{
String process(Object input){
return input.toString().toLowerCase();
}
}
class Splitter extends Processor{
String process(Object input){
return Arrays.toString(input.toString().split(" "));
}
}
public class Apply{
public static void process(Processor p,Object s){
System.out.println("Using Processor:" + p.name());
System.out.println(p.process(s));
}
public static final String S = "Disagreement with beliefs is by definition incorrect";
public static void main(String[] args) {
process(new UpCase(), S);
process(new DownCase(), S);
process(new Splitter(), S);
}
}
运行结果:

package com.chenxyt.java.practice;
public class Filter{
public String name(){
return getClass().getSimpleName();
}
public WaveForm process(WaveForm input){
return input;
}
}
Filter类,看上去与Processor类似,都有name()方法和process()方法,区别在于方法的参数类型和返回类型不同。
package com.chenxyt.java.practice;
public class HighPass extends Filter{
double cutoff;
public HighPass(double cutoff){
this.cutoff = cutoff;
}
public WaveForm prcess(WaveForm input){
return input;
}
}
HighPass类,继承自Filter类
package com.chenxyt.java.practice;
public class BandPass extends Filter {
double lowCutoff,highCutoff;
public BandPass(double lowCutoff,double highCutoff){
this.lowCutoff = lowCutoff;
this.highCutoff = highCutoff;
}
public WaveForm process(WaveForm input){
return input;
}
}
BandPass类,继承自Filter类
package com.chenxyt.java.practice;
public class WaveForm{
private static long counter;
private final long id = counter++;
public String toString(){
return "Wave Form" + id;
}
}
WaveForm类,前边方法的参数类型和返回类型。
package com.chenxyt.java.practice;
public interface Processor{
String name();
Object process (Object input);
}
此时Processor类变成了一个接口,复用代码的形式就是之前继承它的类,可以改为实现它的接口,并且Filter类,也可以编程实现Processor类的接口,这样Apply.process()方法的耦合度就降低了,并且支持了其它的类型。还有一种情况,假如一个类是被发现的,而不是被我们自己创建的,那么这个类就无法实现Processor接口,比如说,如果Filter类是在类库中的类,那么这个类就无法主动实现Processor接口,这时候可以使用适配器模式,在这个类的外部封装一层,作为适配器来实现要实现的接口。如下:
package com.chenxyt.java.practice;
class FilterAdapter implements Processor{
Filter filter;
public FilterAdapter(Filter filter){
this.filter = filter;
}
public String name(){
return filter.name();
}
public WaveForm process(Object input){
return filter.process((WaveForm)input)
}
}
public class FilterProcessor{
public static void main(String[] args) {
WaveForm w = new WaveForm();
Apply.process(new FilterAdapter(new LowPass(1.0)),w);
Apply.process(new FilterAdapter(new HighPass(2.0)),w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)),w);
}
}
在这种使用适配器的方式中,FilterAdapter的构造器接受了Filter参数,然后生成对应接口Processor的对象。
四、Java中的多重继承
C++中允许多重继承,并且每一个继承的类都可以有一个实现,Java中是不允许的,Java中可以实现多个接口,每个接口名字在implements后边用逗号隔开,并且,Java中只能继承一个类。下面的例子说明一个具体的类组合实现多个接口产生一个新类:
package com.chenxyt.java.practice;
interface CanFight{
void Fight();
}
interface CanSwim{
void Swim();
}
interface CanFly{
void Fly();
}
class ActionChracter{
public void Fight(){
//---
};
}
class Hero extends ActionChracter implements CanFight,CanSwim,CanFly{
public void Fly(){
//---
};
public void Swim(){
//--
};
}
public class Adventure{
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(ActionChracter x){
x.Fight();
}
public static void main(String[] args) {
Hero h = new Hero();
t(h);
u(h);
v(h);
w(h);
}
}
可以看到Hero类组合具体类ActionChracter和另外的三个接口,当通过这种方式将类和接口组合在一起时,这个类必须放在前边,接口放在后边,否则编译器会报错。同时我们注意到,CanFight接口与ActionChracter类中的Fight()方法相同,而且Hero中并没有提供Fight()的具体定义。可以扩展接口,当想要创建对象的时候,所有的定义必须都存在,即使Hero没有显示的定义Fight()方法,由于其继承了ActionChracter类,所以定义随之而来,这使创建对象变成了可能。这里的意思是说,一个类实现了某些接口,这些接口中所有的定义在这个类中必须要有相关的实现(编译器会主动提示),然后因为这个类继承了一个类(ActionChracter),所以如果基类有实现了接口中的方法,那么子类就可以不显示的实现这个方法。(区别在于基类不是实现了这个方法,只是方法签名相同)
这个例子中,给出的四个方法分别使用接口作为了参数,所以在Hero作为参数传递的时候,它被依次进行了向上转型,Java中的接口设计,使得这项功能并不复杂。这个例子所展示的是使用接口的核心原因:为了能够向上转型为多个基本类型,提升程序的灵活性。使用接口的第二个原因与抽象类相同,防止程序员在使用的过程中创建该类的对象。当然关于这一点是使用抽象类还是接口,当要创建的类中没有任何方法定义和成员变量的定义是,选择接口是合适的,并且当知道某事物应当成为一个基类的时候,那么第一选择是应当使它成为接口。
五、通过继承扩展接口
package com.chenxyt.java.practice;
interface Monster{
void menace();
}
//新接口继承原来的接口
interface DangerousMonster extends Monster{
void destroy();
}
interface Lethal{
void kill();
}
//实现接口 要依次定义这个接口的方法以及它继承接口的方法 编译器自动补充
class DragonZill implements DangerousMonster{
@Override
public void menace() {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
//接口可以多重继承
interface Vampire extends DangerousMonster ,Lethal{
void drinkblood();
}
//继承多个接口 都要把定义实现
class VeryBadVampire implements Vampire{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void menace() {
// TODO Auto-generated method stub
}
@Override
public void kill() {
// TODO Auto-generated method stub
}
@Override
public void drinkblood() {
// TODO Auto-generated method stub
}
}
代码中标注了,接口可以使用extends继承多个,但是这一形式不适用于普通的类。
六、适配接口
package com.chenxyt.java.practice;
public interface Processor{
String name();
Object process(Object input);
}
package com.chenxyt.java.practice;
public class Apply {
public static void process(Processor p,Object s){
System.out.println("Using Processor" + p.name());
System.out.println(p.process(s));
}
}
package com.chenxyt.java.practice;
public class Filter{
public String name(){
return getClass().getSimpleName();
}
public Waveform process(Waveform input){
return input;
}
}
package com.chenxyt.java.practice;
public class Waveform {
private static long counter;
private final long id = counter++;
public String toString(){
return "Waveform" + id;
}
}
package com.chenxyt.java.practice;
public class LowPass extends Filter{
double cutoff;
public LowPass(double cutoff) {
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
package com.chenxyt.java.practice;
public class HighPass extends Filter{
double cutoff;
public HighPass(double cutoff) {
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
package com.chenxyt.java.practice;
public class BandPass extends Filter {
double lowCutoff,highCutoff;
public BandPass(double lowCutoff,double highCutoff){
this.lowCutoff = lowCutoff;
this.highCutoff = highCutoff;
}
public Waveform process(Waveform input){
return input;
}
}
package com.chenxyt.java.practice;
class FilterAdapter implements Processor{
Filter filter = new Filter();
public FilterAdapter(Filter filter) {
this.filter = filter;
}
@Override
public String name() {
// TODO Auto-generated method stub
return filter.name();
}
public Waveform process(Object input) {
// TODO Auto-generated method stub
return filter.process((Waveform)input);
}
}
public class FilterProcessor{
public static void main(String[] args) {
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)),w);
Apply.process(new FilterAdapter(new HighPass(2.0)),w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)),w);
}
}
七、接口中的域
package com.chenxyt.java.practice;
public interface Months{
int JANUARY = 1,FEBRUARY=2,MARCH=3,APRIL=4,
MAY=5,JUNE=6,JULY=7,AUGUST=8,SEPTEMBER=9,OCTOBER=10,
NOVEMBER=11,DECEMBER=12;
}
八、嵌套接口
package com.chenxyt.java.practice;
class A{
interface B{
void f();
}
public class BImp implements B{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
public class BImp2 implements B{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
public interface C{
void f();
}
class CImp implements C{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
private class CImp2 implements C{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
private interface D{
void f();
}
private class DImp implements D{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
private class DImp2 implements D{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
public D getD(){
return new DImp();
}
private D dRef;
public void reveiveD(D d){
dRef = d;
dRef.f();
}
}
interface E{
interface G{
void f();
}
public interface H{
void f();
}
void g();
//强制必须为public
//private interface I{};
}
public class NestingInterfaces{
public class BImp implements A.B{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
class CImp implements A.C{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
//因为接口D是私有的 所以不能被实现
//class DImp implements A.D{);
class EImp implements E{
@Override
public void g() {
// TODO Auto-generated method stub
}
}
class EGImp implements E.G{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
class EImp2 implements E{
@Override
public void g() {
// TODO Auto-generated method stub
}
class EG implements E.G{
@Override
public void f() {
// TODO Auto-generated method stub
}
}
}
public static void main(String[] args) {
A a = new A();
//D是private 不能实例化
//A.D ad = new A.D();
//getD()方法只能返回D
//A.DImp2 di2 = a.getD();
//private接口的域不能被访问
//a.getD().f();
//可以通过内部返回域的方法获取
A a2 = new A();
a2.reveiveD(a.getD());
}
}
九、接口与工厂
package com.chenxyt.java.practice;
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
Implementation1() {
// TODO Auto-generated constructor stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
// TODO Auto-generated method stub
System.out.println("Implementation1 method2");
}
}
class Implementation1Factory implements ServiceFactory{
@Override
public Service getService() {
// TODO Auto-generated method stub
return new Implementation1();
}
}
class Implementation2 implements Service{
Implementation2() {
// TODO Auto-generated constructor stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
// TODO Auto-generated method stub
System.out.println("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory{
@Override
public Service getService() {
// TODO Auto-generated method stub
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
serviceConsumer(new Implementation2Factory());
}
}
package com.chenxyt.java.practice;
interface Game{
boolean move();
}
interface GameFactory{
Game getGame();
}
class Checkers implements Game{
private int moves = 0;
private static final int MOVES = 3;
@Override
public boolean move() {
// TODO Auto-generated method stub
System.out.println("Checkers moves" + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory{
@Override
public Game getGame() {
// TODO Auto-generated method stub
return new Checkers();
}
}
class Chess implements Game{
private int moves = 0;
private static final int MOVES = 4;
@Override
public boolean move() {
// TODO Auto-generated method stub
System.out.println("Chess move" + moves);
return ++moves != MOVES;
}
}
class ChessFactory implements GameFactory{
@Override
public Game getGame() {
// TODO Auto-generated method stub
return new Chess();
}
}
public class Games {
public static void PlayGame(GameFactory fact){
Game s = fact.getGame();
while(s.move()){
//--
}
}
public static void main(String[] args) {
PlayGame(new CheckersFactory());
PlayGame(new ChessFactory());
}
}
十、总结
抽象类跟接口是将具体方法更加抽象的一种形式,这一章节主要讲了抽象类、抽象方法的形式以及使用场景,比较重要的一点是关于接口的使用,如何解耦,接口可以多重继承,接口可以嵌套等应用场景。关于这一章节中的设计模式,还要继续深入研究下去。