六、接口与内部类:
1. 接口和抽象类:Java通过interface关键字来表示接口,接口中不能包含非静态域字段,所有的域成员均是公有的抽象方法,如Comparable接口,如果希望利用Arrays.sort方法,数组的成员必须实现该接口。抽象类中包含抽象方法,和接口一样抽象类也不能被实例化。
1) 接口不能被实例化,但是可以声明接口的变量指向其实现类的对象。
2) 每个类只能有一个超类,但是可以实现多个接口。
以下为Java的接口和抽象类的定义方式:
1 public interface Comparable {
2 int compareTo(Object other);
3 }
4
5 public interface Comparable
6 int compareTo(T other);
7 }
8
9 abstract class Employee implements Comparable {
10 public abstract int compareTo(Object other);
11 }
在C++中同样存在接口和抽象类的概念,也和Java一样不能被实例化,但是并没有相应的关键字存在,而是以一种潜在规则的方式存在,见如下代码:
1 //Comparable对象声明的方法中只有纯虚方法存在(析构函数除外),且没有任何成员变量。
2 class Comparable {
3 public:
4 virtual ~Comparable() {}
5 //compareTo为纯虚方法
6 virtual int compareTo(Comparable& other) = 0;
7 }
8
9 //Employee对象中存在部分纯虚方法,且可以有成员变量存在。
10 class Employee {
11 public:
12 virtual int compareTo(Comparable& other) { return 0; }
13 virtual int backgroud() = 0;
14
15 private:
16 int _age;
17 }
在C++的实现中,基于接口编程,同时导出C接口的工厂方法对于跨编译器极为重要,该方式比较类似于Windows中的COM技术。
C++支持多重继承,因此也存在虚基类(菱形结构)等问题带来的负面影响,既子类的两个父类中同时存在相同签名的虚方法。见如下代码:
1 class TcpServerTask {
2 public:
3 virtual void run() {}
4 }
6 class SentObjectTask {
7 public:
8 virtual void run() {}
9 }
10
11 class TcpServerSentTask : public TcpServerTask, public SentObjectTask { }
2. 对象克隆: Object对象中存在protected类型的clone方法,该方法将会完成子类对象clone的缺省操作,既对象域字段的浅拷贝,如果该对象的成员均为原始类型,如int、float等,或者为不可变类型,如String。这样的浅拷贝将能够达到对象clone的预期。换言之,如果对象内部存在可变对象的引用,浅拷贝将会带来原始对象和cloned对象引用相同对象引用的问题。如果希望避免该问题的发生,子类需要实现Cloneable接口。这里需要指出的是Cloneable接口并未提供clone方法,只是提供了一种契约签名。子类真正做的还是重载Object方法中的clone方法,由于Object中该方法为protected方法,所以caller不能直接调用它,只能将子类的clone方法声明为共有类型,caller才能调用。
1 //该实现类使用浅拷贝已经可以满足其需要了
2 public class implements Cloneable {
3 //这里已经提升了clone方法的级别为public。
4 public Employee clone() throws CloneNotSupportedException {
5 return (Employee)super.clone();
6 }
7 }
8 //深拷贝clone方法,必须clone对象内部所有可变的实例域,其中这些可变类
9 //必须全部都实现了自己的clone方法,否则将会跑出异常。
10 public class Employee implements Cloneable {
11 public Employee clone() throws CloneNotSupportedException {
12 //缺省clone完成了域字段的按位浅拷贝。
13 Employee cloned = (Employee)super.clone();
14 cloned.hireday = (Date)hireday.clone();
15 }
16 private Date hireday;
17 }
注:数组对象可以通过Array的clone(public)方法完成元素的拷贝。
在C++中由于并不存在Object这样的单根结构的框架,因此C++是以另外一种方式表现该问题的,既缺省拷贝构造和缺省等于操作符重载。和Java类似,这两个方法也是member bitwise拷贝的,但这是由编译器在生成对象模型时自动完成的缺省行为,如果该类重载了拷贝构造函数和等于操作符,在需要copy的时候则会调用重载后的方法,类的实现者应该在这两个方法中完成深拷贝。C++中还可以通过将这两个方法显示的声明为private类型的方法来禁用这种对象之间的copy行为,一旦出现,编译器将会在在编译器报错。在C++中还存在一个explicit的关键字,可以有效的防止编译器通过自行推演隐式的调用对象的拷贝构造函数和等于操作符函数,见如下代码:
1 //该类将会使用缺省的copy constructor,因此也会出现两个对象
2 //引用相同_name变量地址的问题。
3 class Employee {
4 private:
5 char* _name;
6 };
7 //该类由于将这两个方法私有化,一旦出现对象的隐式拷贝构造,
8 //将会导致编译错误。
9 class Employee {
10 private:
11 Employee(Employee& other);
12 const Employee& operator= (Employee& othe