6) Java中如果子类和超类同时包含具有相同签名的公有域方法,那么在子类中将覆盖超类中的域方法。这其中的方法签名只是包括方法名和参数列表,既参数的个数和类型,函数的返回值不包含在方法签名中,但是在Java中针对该种方法覆盖的返回值还是存在一定的限制,既子类中的返回值的类型,或者与超类中该方法的返回值类型相同,或者为其返回类型的子类。C++中没有此类返回值类型的限制。但是Java的此类限制也会带来一些潜在的迷惑和危险,见如下代码:
1 class Employee {
2 public Employee[] getBuddies() { ... }
3 }
4
5 class Manager extends Employee {
6 public Manager[] getBuddies() { ... }
7 }
8
9 public static void main(String[] args) {
10 Employee[] m = new Manager().getBuddies();
11 //在Java中子类的数组在复制给超类的数组时不需要显式的转换,就像
12 //子类的实例赋值给超类的实例一样,也不需要任何显式的转换。
13 //赋值之后e和m指向相同的内存地址,同样e[0]和m[0]也指向相同的实例。
14 Employee[] e = m;
15 //本次赋值合法也不会引发任何异常,但是会导致一个潜在的问题,既
16 //m[0]的对象已经被悄悄的改变了,指向了Employee的另外一个子类。
17 e[0] = new OtherEmployee();
18 //此时再调用m[0]中Manager定义的域方法时将会引发Java的运行时异常。
19 m[0].setBonus(1000);
20 }
7) Java中的final类,如果某个自定义类型被加入final关键字,则表示该类将不能被继承,否则会直接产生编译错误。在C++中没有特殊的关键字类完成此类限制,然而在实际的应用中也同样存在一些潜在的技巧协助开发者来进行此类限制的甄别。如将父类中的析构函数不设置为虚函数,此方法则间接的暗示子类的实现者要留意,如果仍然继承该父类,那么在实现多态时,如BaseClass* c = new DeriveClass,如果之后需要释放c变量的内存资源时 delete c, 此时由于父类中的析构函数并不是虚函数,因此此次调用将只会执行父类的析构函数,而不会调用子类的析构函数,最终导致类分割所带来的一些潜在错误或资源泄漏。
8) 内联方法,在C++中有特殊的关键字inline用于帮助编译器来推断是否需要将该方法编译成内联方法,以提高运行时的效率。在Java中没有此类关键字,而是通过编译器的一连串推演,最终决定该域方法是否可以编译成内联方法,主要候选方法为简短、被频繁调用且没有真正被子类覆盖的域方法。
9) 超类到子类的强制类型转换。在Java中可以通过直接强转的方式来转换,如Manager m = (Manager)e。如果装换失败将会引发运行时异常ClassCastException,因此很多情况下为了避免此类异常的发生,需要在强转之前先进行判断,如if (e instanceof Manager) { ... }, 如果条件为真,装换将顺利完成。在C++中也可以采用这样的直接强转方法,但是即使类型不匹配程序也不会在强转是引发任何异常,而是在后面针对该变量的使用时才会导致错误的发生。在C++中存在dynamic_cast关键字,如dynamic_cast
10) 抽象类:在Java中如果class被定义为abstract class,该类将不能被实例化,如果子类未能完全实现超类中所有的抽象方法,那么子类也将会被视为抽象类。C++中没有特殊的关键字来表示抽象类,而且通过将类中的一个或多个方法定义为纯虚方法来间接实现的,见如下C++代码,其中的first和second均为纯虚方法,既在方法的尾部添加" = 0 "。
2 public:
3 virtual void first() = 0;
4 virtual void second() = 0;
5 virtual void third();
6 }
11) protected关键字在Java和C++中针对域方法和域字段的访问方式存在着不同的限制级别,相同之处是protected的方法和字段都可以被子类直接访问,不同之处是Java中相同包中的类也可以直接他们。C++自身并不存在包的概念,然而即便是相同名字空间内的对象也不能直接访问。
2. Object:
Java是单根结构的框架,所有的对象都是Object的子类,即使在对象声明时没有进行直接的指定,Java的编译器将会自行搞定这些。C++中没有适当的类作为所有对象的根类,然而在有些类库中可以自行定义,如MFC的CObject等。Java的Object中有3个非常重要的方法equals、hashCode和toString。如果子类中重载了他们中的任意一个方法,同时也建议重载另外两个域方法。
1) equals: 主要用于判定两个对象是否相等。类的实现者可以根据自己的真实逻辑来重新实现该方法,通用实现规则见下例:
1 public class Employee {
2 //1. 显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。
3 public boolean equals(Object otherObject) {
4 //2. 检测this与otherObject是否引用同一个对象(一种优化)
5 if (this == otherObject)
6 return true;
7 //3. 检测otherObject是否为null,如果null,则返回false。
8 if (otherObject == null)
9 return false;
10 //4. 比较this与otherObject是否属于同一个类。
11 //如果子类中的equals语义各不相同,使用下面的getClass方式,精确定义类类型。
12 if (getClass() != otherObject.getClass())
13 return false;
14 //如果子类中的equal语义和超类完全相同,可以使用instanceof检测即可。
15