C++和Java中的“泛型”类型之间有什么区别?

Java具有泛型和C++提供了一个非常强大的编程模型。那么,C++和Java泛型有什么区别呢?template


答案 1

它们之间有很大的区别。在C++您不必为泛型类型指定类或接口。这就是为什么你可以创建真正的泛型函数和类,但需要注意的是更宽松的类型。

template <typename T> T sum(T a, T b) { return a + b; }

上面的方法添加两个相同类型的对象,并且可以用于具有可用“+”运算符的任何类型 T。

在Java中,如果要对传递的对象调用方法,则必须指定一个类型,如下所示:

<T extends Something> T sum(T a, T b) { return a.add ( b ); }

在C++泛型函数/类只能在标头中定义,因为编译器为不同类型的(调用它)生成不同的函数。因此,编译速度较慢。在Java中,编译没有重大损失,但Java使用一种称为“擦除”的技术,其中泛型类型在运行时被擦除,因此在运行时Java实际上调用...

Something sum(Something a, Something b) { return a.add ( b ); }

尽管如此,Java的泛型有助于类型安全。


答案 2

Java泛型与C++模板有很大的不同。

基本上在C++模板基本上是一个美化的预处理器/宏集(注意:由于有些人似乎无法理解类比,我并不是说模板处理是一个宏)。在Java中,它们基本上是语法糖,以尽量减少对象的样板转换。这是一个关于C++模板与Java泛型的相当不错的介绍

为了详细说明这一点:当您使用C++模板时,您基本上是在创建代码的另一个副本,就像您使用宏一样。这允许您执行一些操作,例如在模板定义中具有确定数组大小的参数等。#defineint

Java不是那样工作的。在Java中,所有对象都来自java.lang.Object,所以,在泛型之前,你会这样编写代码:

public class PhoneNumbers {
    private Map phoneNumbers = new HashMap();
    
    public String getPhoneNumber(String name) {
      return (String) phoneNumbers.get(name);
    }
}

因为所有Java集合类型都使用Object作为其基类型,因此您可以在其中放入任何内容。Java 5 滚动并添加了泛型,因此您可以执行如下操作:

public class PhoneNumbers {
    private Map<String, String> phoneNumbers = new HashMap<String, String>();
    
    public String getPhoneNumber(String name) {
        return phoneNumbers.get(name);
    }
}

这就是所有Java泛型:用于转换对象的包装器。那是因为Java泛型没有被提炼。它们使用类型擦除。做出这个决定是因为Java泛型在这篇文章中出现得太晚了,以至于他们不想破坏向后兼容性(每当需要a时,a都是可用的)。将其与不使用类型擦除的 .Net/C# 进行比较,后者会导致各种差异(例如,您可以使用基元类型并且彼此之间没有任何关系)。Map<String, String>MapIEnumerableIEnumerable<T>

使用 Java 5+ 编译器编译的泛型的类在 JDK 1.4 上可用(假设它不使用任何其他需要 Java 5+ 的功能或类)。

这就是为什么Java泛型被称为句法糖

但是,关于如何做泛型的这个决定产生了深远的影响,以至于(极好的)Java泛型常见问题解答如雨后春笋般涌现,回答了人们对Java泛型的许多问题。

C++模板具有许多 Java 泛型所没有的功能:

  • 使用基元类型参数。

    例如:

    template<class T, int i>
    class Matrix {
        int T[i][i];
        ...
    }
    

    Java 不允许在泛型中使用基元类型参数。

  • 使用默认类型参数,这是我在Java中错过的一个功能,但是有向后兼容性的原因;

  • Java 允许参数的边界。

    例如:

    public class ObservableList<T extends List> {
        ...
    }
    

确实需要强调的是,具有不同参数的模板调用确实是不同的类型。他们甚至不共享静态成员。在Java中,情况并非如此。

除了与泛型的差异之外,为了完整起见,这里是C++和Java(以及另一个)的基本比较。

我也可以建议在Java中思考。作为一C++程序员,许多像对象这样的概念已经是第二天性,但存在细微的差异,因此即使您略读部分,也值得拥有介绍性文本。

在学习Java时,你学到的很多东西都是所有库(包括标准库--JDK中的内容--以及非标准库,包括像Spring这样常用的东西)。Java语法比C++语法更冗长,并且没有很多C++功能(例如运算符重载,多重继承,析构器机制等),但这也不能严格使其成为C++的子集。