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

2014-11-24 02:04:05 · 作者: · 浏览: 13

八、泛型程序设计:

1. 泛型类的定义,见如下代码:

1 publicclassPair {
2 publicPair() { first = null; second = null; }
3 publicPair(T first,U second) { this.first = first; this.second = second; }
4
5 publicT getFirst() { returnfirst; }
6 publicU getSecond() { returnsecond; }
7 publicvoidsetFirst(T first) { this.first = first; }
8 publicvoidsetSecond(U second) { this.second = second; }
9
10 privateT first;
11 privateU second;
12 }

以上代码中的T,U都是泛型类Pair的类型参数。以下为C++中模板类的定义方式:

1 template
2 classPair {
3 public:
4 Pair(T first,U second): _first(first),_second(second) {}
5 ~Pair() {}
6 public:
7 T getFirst() { return_first; }
8 U getSecond() { return_second; }
9 voidsetFirst(T frist) { _first = first; }
10 voidsetSecond(U second) { _second = second; }
11 private:
12 T _first;
13 U _second;
14 }

2. 泛型方法的定义,在Java中泛型方法不一定声明在泛型类中,可以声明在普通类中,见如下代码:

1 publicclassMyFirst {
2 publicstaticvoidmain(String[] args) throwsException {
3 String[] names = {"john","Q.","Public"};
4 String middle = ArrayAlgo.getMiddle(names);
5 System.out.println(middle);
6 }
7 }
8
9 classArrayAlgo {
10 publicstatic T getMiddle(T[] a) {
11 returna[a.length/2];
12 }
13 }

在以上代码中可以看出getMiddle方法为静态泛型方法,类型变量位于修饰符"public static" 的后面,返回值的前面。调用的时候在方法名的前面给出了参数类型。由于Java的编译器提供类型推演的功能,既类型参数可以通过函数参数的类型进行推演,因此也可以直接调用泛型函数,如String middle = ArrayAlgo.getMiddle(names)。如果编译器无法通过函数参数的类型推演出类型参数的实际类型,这样将会导致编译错误。在C++中同样存在模板函数,也同样存在模板函数的类型推演,在这一点上主要的差异来自于函数声明的语法,见如下C++代码:

1 classArrayAlgo {
2 public:
3 template
4 staticT getMiddle(T* a,size_t len) {
5 returna[len/2];
6 }
7 };
8
9 intmain()
10 {
11 intv[] = {1,2,3};
12 intret = ArrayAlgo::getMiddle(v,3);
13 printf("This value is %d.\n",ret);
14 return0;
15 }

3. 类型参数的限定:有些泛型函数在使用类型参数变量时,经常会用到该类型的特殊方法,如在进行数组元素比较时,要求数组中的元素必须是Comparable接口的实现类,见如下代码:

1 publicstatic T min(T[] a) {
2 if(a == null|| a.length == 0)
3 returnnull;
4 T smallest = a[0];
5 for(inti = 0; i < a.length; ++i) {
6 if(smallest.compareTo(a[i]) > 0)
7 smallest = a[i];
8 }
9 returnsmallest;
10 }

在以上代码中,数组元素的类型为T,如果该类型并未提供compareTo域方法,将会导致编译错误,如何确保类型参数确实提供了compareTo方法呢?如果T是Comparable接口的实现类,那么该方法一定会被提供,因此可以通过Java语法中提供的类型参数限定的方式来确保这一点。见如下修订代码:

1 publicstatic T min(T[] a) {
2 if(a == null|| a.length == 0)
3 returnnull;
4 T smallest = a[0];
5 for(inti = 0; i < a.length; ++i) {
6 if(smallest.compareTo(a[i]) > 0)
7 smallest = a[i];
8 }
9 returnsmallest;
10 }

其中的语法保证了类型参数必须是Comparable接口的实现类,否则将会导致编译错误。Java中可以支持多接口的限定,之间用&分隔,如和之前的例子一样,尽管同样都会导致编译错误,但是后者不仅会产生更为明确的编译错误信息,同样也使使用者能够更加清晰的看到该方法的使用规则。在标准C++中并未提供这样的限定,但是在C++中对该种方式有另外一种称谓,叫做"类型绑定",在Boost等开源库中通过更复杂的模板技巧模仿了该功能的实现。然而,就泛型的该功能而言,C#的支持也是相当不错的,可参考C#泛型中的which关键字。
在标准C++中,其模板的实现较Java而言更为灵活和强大。对于第一个例子中的代码,只是要求模参必须提供compareTo方法即可通过编译。

1 template
2 staticT min(T* a,size_t len)