技术开发 频道

Java和C++在细节上的差异(一)

  5. 对象的构造和构造函数:

  在Java中如果一个class没有定义任何构造函数,Java编译器将自动生成一个缺省的构造函数,没有任何参数,其行为只是按照Java默认的方式初始化该类的所有域变量,如数值型为0,布尔为false,对象则为null。但是如果该class定义了自己的构造函数,那么缺省构造函数将不会被自动生成,再试图调用自动生成的缺省构造函数将会导致编译错误。该行为和C++完全一致。但是Java提供了另外一种域变量初始化方式,如下:

1     public class Employee {
2         ...
3         private String name = "";    //直接赋值
4         private int id = assignId();//通过调用域方法完成初始化。
5     }

  在C++中不能直接在类的定义中以任何形式直接初始化成员变量。但是C++提供了在构造函数中以初始化列表的方式完成成员变量对象的初始化,特别是const成员,必须在这里赋值。

  通过一个构造器调用另一个构造器从而完成域变量的初始化和部分代码复用。通过this关键字(或称隐式参数)作为函数名,然后传入参数调用你期望的另一个构造函数,注:this被调用之前不能执行任何其他的code。

1     public Employee(double s) {
2         //calls Employee(String,double)
3         this("Employee #" + nextId,s);
4         ++nextId;
5     }

  在C++中如果打算完成此功能,必须将构造函数的部分逻辑抽取出来,以便让多个构造函数去调用,然后不同的构造函数之间不能直接调用。

  在Java定义的子类中,如果子类的构造函数不是调用父类的缺省构造函数,则需要在子类构造函数的第一行代码中指定欲调用的父类构造函数,该调用需要通过super关键字来完成。见如下代码:

1     public class MyFirst {
2         public static void main(String[] args) {
3             BaseClass bc1 = new SonClass();
4             BaseClass bc2 = new SonClass(5);
5         }
6     }
7      
8     class BaseClass {
9         public BaseClass() {
10             System.out.println("This is BaseClass");
11         }
12        
13         public BaseClass(int i) {
14             System.out.println("This is BaseClass with i.");
15         }
16     }
17    
18     class SonClass extends BaseClass {
19         public SonClass() {
20             System.out.println("This is SonClass");
21         }
22        
23         public SonClass(int i) {
24             super(5);
25             System.out.println("This is SonClass with i");
26         }
27     }
28     /*    结果如下:
29         This is BaseClass
30         This is SonClass
31         This is BaseClass with i.
32         This is SonClass with i */

       在C++中也可以完成该种类型的指定,但是必须在子类构造函数的初始化列表中完成对父类指定构造函数的调用。

1     class BaseClass {
2     public:
3         BaseClass() {
4             printf("This is BaseClass\n");
5         }
6      
7         BaseClass(int i) {
8             printf("This is BaseClass with i\n");
9         }
10     };
11    
12     class SonClass : public BaseClass {
13     public:
14         SonClass() {
15             printf("This is SonClass\n");
16         }
17    
18         SonClass(int i) : BaseClass(i) {
19             printf("This is SonClass with i\n");
20         }
21     };
22    
23     int main()
24     {
25         BaseClass* bc1 = new SonClass;
26         BaseClass* bc2 = new SonClass(5);
27         delete bc1;
28         delete bc2;
29         return 0;
30     }
31     /*    结果如下:
32         This is BaseClass
33         This is SonClass
34         This is BaseClass with i.
35         This is SonClass with i */

  在Java的域变量初始化方法中存在初始化块的方式,既除声明即初始化、构造函数初始化之外的第三种域变量初始化方式。在一个类的声明中可以存在多个代码块,只要构造类的对象,这些块就会被执行,然后再运行类的构造函数。静态域变量可以在静态初始化块中完成初始化的工作,但是该初始化块只是在类第一次加载时被执行一次,之后都将不再被执行。见如下代码:

1     class Employee {
2         public Employee(String n,double s) {
3             name = n;
4             salary = s;
5         }
6          
7         ...
8          
9         private static int nextId;
10         private int id;
11         private String name;
12         private double salary;
13        
14         //object initialization block.
15         {
16             id = nextId;
17             nextId++;
18         }
19        
20         //static initialization block.
21         static
22         {
23             Random generator = new Random();
24             nextId = generator.nextInt();
25         }
26     }

  6. C++的对象析构和Java对象的finalize方法:

  C++是有显式的析构方法,其中放置一些当对象不再使用时需要执行的清理代码。在析构函数中,最常见的操作时回收分配给对象的存储空间,系统资源等。有Java有自动的垃圾回收器,不需要人工回收内存,所以Java并不支持析构函数。如果打算在Java的代码中完成类似的工作,可以通过为该类添加finalize方法,该方法将会在垃圾收集器清除对象之前调用,在实际应用中,不要依赖于使用finalize方法回收任何短缺的资源,这是因为很难知道这个方法什么时候才能调用。如果某个资源确实需要在使用完毕后立刻关闭,那么就需要由人工来管理。可以应用一个类似dispose或close的方法完成相应的清理操作。特别需要说明,如果一个类使用了这样的方法,当对象不再被使用时一定要调用它。

  7. Java的包 vs C++的名字空间

  他们具有极为相同的只能,即防止名字污染。当一个应用程序中存在多个第三方组件,那么不同组件中命名了相同名称的类将是极为可能发生的,如Java中的Date类,在java.util和java.sql中均存在该名称的类的声明。为了有效的防止名字污染,C++中采用了namespace和using namespace的指令来明确定义某个类具体所位于的具体位置,Java中则采用了package和import语句。

  Java在Java SE5.0 开始,import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。如import static java.lang.System.*。在完成该静态导入之后,就可以在剩下的代码中直接使用System类的静态方法和静态域了,如out.println();exit(0)。该技巧主要用于带有较长名称的常量,如if (d.get(DAY_OF_WEEK) == MONDAY) ...,看起来比if (d.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) ...要容易的多。

0
相关文章