这个部分对应Thinking in JAVA 3rd P264-P312。这个部分当中的接口还算好理解,但是内部类书上写了好多特殊用法,很繁杂,没有仔细研究,准备以后用到的时候再去研究他。
这个部分对于C++而言可以说是全新的,当然有些概念是C++当中用过的,但是JAVA用了一种更加简洁的方式来实现。接口和内部类说到底是为了解决CPP当中多继承所带来的一些问题,这些问题主要是名字冲突以及同名内存块等等。
一、接口
接口可以认为是一种特殊的abstract类,这种类所有的方法都隐含认为是public的(可以省略这个关键字),他不存在成员数据和任何非public的东西。接口的意义是未所有实现他的类制定一个协议,即所有实现接口的类必须至少按照接口定义的签名来实现这些方法,因此所有从接口实现的类群都能够向上转型到接口。
接口大多被用在多继承上(由于实现接口在JAVA上用的是implement关键字而非继承所用的extended关键字,因此这种所谓的多继承停留在理解层次上)。由于JAVA接口规定他只能是public方法的定义而不含成员数据,因此他不会造成CPP当中多继承的那种内存名字冲突的问题。
JAVA的接口之间可以用extended关键字进行继承,因此,一个实现某个接口的类可以向上转型到其实现接口的更上级接口。另外需要注意的是JAVA规定只能从一个类(无论是abstract类或者普通类)继承但是可以从多个接口实现,在写这种类时,格式规定extended关键字在前implement关键字在后,然后几个接口用逗号隔开。接口当中的所有方法类中必须全部实现,但是从其基类继承而来的方法也可以用来实现接口当中的方法。
二、内部类
内部类是指在一个类内部定义的类,这种类可以控制其访问权限,public的内部类允许外部创建,而private的内部类只允许在外部类的内部创建和使用,protected内部类还允许包内使用(不要忘记protected权限包含包内权限,反之不然),这一点与CPP的内部类基本一致。不同点在两个方面:其一,JAVA的内部类允许访问包含他的外部类的所有成员,CPP不允许;其二,JAVA的内部类还允许创建在作用域内(如if语句或某个方法内),这样的内部类只允许作用域内访问创建,所以不需要访问权限控制符。
内部类的真正用途其实是要和接口配合使用。例如在外部有两个公开的接口IA和IB,那么在在类CA当中有两个private的内部类CIA和CIB,他们分别实现接口IA和IB,然后CA当中有两个方法分别返回一个创建好的CIA和CIB并向上转型为IA、IB。这样就实现了对客户端程序员完全的实现隐藏,客户端程序员得到接口后只要根据接口协议调用方法就能获取需要的数据,至于接口怎么实现则完全不可见。如果熟悉Windows下的COM组件原理的话,会发现这个部分的思想与COM完全一致(如果把上面那两个public 方法替换成一个,然后根据传入的参数返回不同的接口,那就完全一样了),不同的是JAVA相对优雅地用安全的内建机制实现,而COM则要依赖于CPP虚继承当中v-table的内存结构。
三、用JAVA来模拟COM组件的源代码
package MediaPlayer;
public interface BaseMediaType {
public int play();
public int stop();
}
package MediaPlayer;
public interface RealMedia extends BaseMediaType{
public int TranseUseRSTP();
}
package MediaPlayer;
public interface WindowsMedia extends BaseMediaType {
public int GetInfoFromInternet();
public int TranseUseMMS();
}
package MediaPlayer;
public class commonMediaPlayer {
public BaseMediaType QueryCommonMediaInterface(String mediaType){
if (mediaType == "RealMedia")
return new RealMediaPlayer();
else if (mediaType == "WindowsMedia")
return new WindowsMediaPlayer();
else
return null;
}
public WindowsMedia QueryWindowsMediaInterface(){
return new WindowsMediaPlayer();
}
public RealMedia QueryRealMediaInterface(){
return new RealMediaPlayer();
}
private String playerTitle = "Common Media Player";
private String curRender = "None";
private class RealMediaPlayer implements RealMedia{
public int play(){
curRender = "Real Media Render";
System.out.println("Real Player playing " + curRender);
return 0;
}
public int stop(){
curRender = "None";
return 0;
}
public int TranseUseRSTP(){
System.out.println("Real media can transe use protocol rstp");
return 0;
}
}
private class WindowsMediaPlayer implements WindowsMedia {
public int play(){
curRender = "Windows Media Render";
System.out.println("Windows Player playing " + curRender);
return 0;
}
public int stop(){
curRender = "None";
return 0;
}
public int TranseUseMMS(){
System.out.println("Windows media can transe use protocol mms");
return 0;
}
public int GetInfoFromInternet(){
System.out.println("Windows media can get information from internet");
return 0;
}
}
}
import MediaPlayer.*;
public class player {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
commonMediaPlayer common = new commonMediaPlayer();
BaseMediaType real = common.QueryCommonMediaInterface("RealMedia");
BaseMediaType wm = common.QueryCommonMediaInterface("WindowsMedia");
real.play();
real.stop();
wm.play();
wm.stop();
WindowsMedia wm1 = common.QueryWindowsMediaInterface();
wm1.GetInfoFromInternet();
wm1.TranseUseMMS();
RealMedia real1 = common.QueryRealMediaInterface();
real1.TranseUseRSTP();
}
}