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

时间:2020-03-05 18:45:32  来源:igfitidea点击:

Java具有泛型,而C ++通过templates提供了非常强大的编程模型。
那么,C ++和Java泛型之间有什么区别?

解决方案

回答

C ++具有模板。 Java具有泛型,看上去有点像C ++模板,但是它们非常非常不同。

顾名思义,模板通过为编译器提供一个(正在等待...)模板来工作,模板可以通过填充模板参数来生成类型安全的代码。

据我了解,泛型的工作方式相反:编译器使用类型参数来验证使用它们的代码是否是类型安全的,但生成的代码完全没有类型。

将C ++模板视为一个非常好的宏系统,并将Java泛型视为自动生成类型转换的工具。

回答

它们之间有很大的区别。在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中的通用编程并不是真正有用的,它只是语法上的一点帮助新的foreach构造。

编辑:以上关于有用性的观点是由一个年轻的自我写成的。 Java的泛型当然有助于类型安全。

回答

Java(和C#)泛型似乎是一种简单的运行时类型替换机制。

回答

C ++模板是一种编译时结构,可让我们根据自己的需要修改语言。它们实际上是编译器在编译期间执行的纯功能语言。

<typename T> T sum(T a, T b) { return a + b; }
<typename T> T sum(T* a, T* b) { return (*a) + (*b); }
Special sum(const Special& a, const Special& b) { return a.plus(b); }

C ++模板的另一个优点是规范化。

回答

现在,如果使用指针调用sum,则将调用第二个方法;如果使用非指针对象调用sum,则将调用第一个方法;如果使用Special对象调用sum(),则将调用第三个方法。我认为Java无法做到这一点。

@基思:

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

回答

该代码实际上是错误的,除了较小的毛刺(省略了" template",专门化语法看起来有所不同)之外,部分专门化不适用于功能模板,仅适用于类模板。但是,该代码无需部分模板专门化即可工作,而应使用普通的旧重载:

基本上,AFAIK,C ++模板为每种类型创建代码的副本,而Java泛型使用完全相同的代码。

If you are familiar with C++'s template mechanism, you might think that generics are similar, but the similarity is superficial. Generics do not generate a new class for each specialization, nor do they permit “template metaprogramming.”

是的,我们可以说C ++模板等效于Java泛型概念(尽管更恰当的说法是Java泛型在概念上等效于C ++)

回答

来自:Java泛型

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

基本上,在C ++中,模板基本上是经过修饰的预处理器/宏集(注意:由于某些人似乎无法理解类推,因此我并不是说模板处理是宏)。在Java中,它们基本上是语法糖,可最大程度地减少对象的样板转换。这是C ++模板与Java泛型的相当不错的介绍。

详细说明这一点:使用C ++模板时,基本上是在创建代码的另一个副本,就像使用了#define宏一样。这使我们可以执行诸如在模板定义中使用" int"参数来确定数组大小等操作。

public class PhoneNumbers {
  private Map phoneNumbers = new HashMap();

  public String getPhoneNumber(String name) {
    return (String)phoneNumbers.get(name);
  }

  ...
}

Java不能那样工作。在Java中,所有对象都来自java.lang.Object,因此,泛型之前,我们需要编写如下代码:

public class PhoneNumbers {
  private Map<String, String> phoneNumbers = new HashMap<String, String>();

  public String getPhoneNumber(String name) {
    return phoneNumbers.get(name);
  }

  ...
}

因为所有Java集合类型都使用Object作为其基本类型,所以我们可以在其中放置任何内容。 Java 5全面推出并添加了泛型,因此我们可以执行以下操作:

这就是Java泛型的全部内容:封装对象的包装器。那是因为Java泛型没有改进。他们使用类型擦除。之所以做出此决定,是因为Java泛型出现的太晚了,以至于他们不想破坏向后兼容性(只要需要使用Map,就可以使用Map <String,String>)。将此与未使用.Net / Cwhere的类型擦除进行比较,这会导致各种差异(例如,我们可以使用原始类型,而IEnumerable和IEnumerable <T>彼此无关)。

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

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

但是,关于如何执行泛型的决定产生了深远的影响,以至于(一流的)Java Generics FAQ迅速出现,回答了人们对Java Generics的许多问题。

  • 使用原始类型参数。例如:
template<class T, int i>
class Matrix {
  int T[i][i];
  ...
}

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

  • 使用默认类型参数,这是我在Java中缺少的功能之一,但是有向后兼容的原因;
  • Java允许参数的边界。

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

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

例如:

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

除了与泛型的区别之外,为了完整性,这里是C ++和Java(和另一个)的基本比较。

我也可以建议使用Java思考。作为C ++程序员,对象之类的许多概念已经是天生的,但是存在细微的差别,因此即使我们略过部分内容,也应该有介绍性的文本。

回答

学习Java时,我们将学到的很多东西都是库(标准库(JDK中附带的库)和非标准库(包括诸如Spring之类的常用东西)。 Java语法比C ++语法更冗长,并且没有很多C ++功能(例如运算符重载,多重继承,析构函数等),但严格来说也不能使其成为C ++的子集。

Generics in Java resemble templates in
  C++. ... The syntax is deliberately
  similar and the semantics are
  deliberately different. ...
  Semantically, Java generics are
  defined by erasure, where as C++
  templates are defined by expansion.

Java泛型和集合中对该主题有很好的解释
莫里斯·纳夫塔林(Maurice Naftalin),菲利普·沃德勒(Philip Wadler)。我强烈推荐这本书。去引用:

请在此处阅读完整说明。

回答

替代文字http://oreilly.com/catalog/covers/0596527756_cat.gif

段落数量不匹配