Java有泛型,而C++则提供了一个非常强大的编程模型,使用template
。
Java有泛型,而C++则提供了一个非常强大的编程模型,使用template
。
它们之间有很大的区别。在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 ); }
Something sum(Something a, Something b) { return a.add ( b ); }
然而,Java的泛型有助于类型安全。
Java泛型与C ++模板非常不同。
基本上,在C ++中,模板基本上是一个较旧的预处理器/宏集合(注意:因为有些人似乎无法理解类比,我并不是说模板处理是宏)。在Java中,它们基本上是一种语法糖,用于最小化对象的样板铸造。这里有一个相当不错的介绍C++模板与Java泛型。
为了阐述这一点:当您使用C ++模板时,您基本上正在创建代码的另一个副本,就像使用#define
宏一样。这使您能够执行诸如在模板定义中具有int
参数以确定数组大小等操作。
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);
}
}
Use of primitive type arguments.
For example:
template<class T, int i>
class Matrix {
int T[i][i];
...
}
Java does not allow the use of primitive type arguments in generics.
Use of default type arguments, which is one feature I miss in Java but there are backwards compatibility reasons for this;
Java allows bounding of arguments.
For example:
public class ObservableList<T extends List> {
...
}
需要强调的是,使用不同参数的模板调用确实是不同的类型。它们甚至没有共享静态成员。在Java中不是这样。
除了泛型的差异外,为了完整起见,这里有一个C++和Java的基本比较(以及另一个比较)。
我还可以建议一下《Java编程思想》。作为C++程序员,很多概念像对象这样都是很自然的,但是也存在一些微妙的差异,因此即使您只是浏览一些部分,拥有一本入门文本也是值得的。
当学习Java时,您将学到的很多都是库(包括标准库 - JDK中的内容 - 和非标准库,其中包括常用的东西如Spring)。Java语法比C++语法更冗长,而且没有许多C++特性(例如运算符重载、多继承、析构函数机制等),但这并不严格意味着它是C++的子集。
Map map = new HashMap<String, String>
的向后兼容性。由于字节码的相似性,这意味着您可以在旧的 JVM 上部署新代码,并且它将能够运行。 - Yuval AdamC++有模板,Java有泛型,看起来有点像C++的模板,但它们非常不同。
正如其名称所示,模板通过提供可以用于填充模板参数以生成类型安全代码的(等待它……)模板来工作。
据我所知,泛型是相反的:编译器使用类型参数来验证使用它们的代码是否类型安全,但生成的代码根本没有类型。
把C++的模板想象成一个非常好的宏系统,而将Java的泛型视为自动生成类型转换的工具。
const
有关。在C++中,除非将const
强制转换掉,否则对象不会通过const
指针被修改。同样,在Java中由泛型类型创建的隐式转换保证是“安全”的,除非在代码中手动转换类型参数。 - Laurence GonsalvesC++模板有而Java泛型没有的另一个特性是专门化。这允许您针对特定类型拥有不同的实现。因此,您可以例如为int拥有高度优化的版本,同时仍为其余类型拥有通用版本。或者对于指针和非指针类型可以有不同的版本。如果您想在传递指针时操作取消引用的对象,则这非常方便。
Java中的泛型类似于C++中的模板,语法故意相似但语义不同。在语义上,Java泛型是通过擦除来定义的,而C++模板则是通过展开来定义的。
这个主题有一个很好的解释,可以在Maurice Naftalin和Philip Wadler所著的Java Generics and Collections一书中找到。我强烈推荐这本书。
请在此处阅读全文解释。
(来源: oreilly.com)
Java(以及C#)的泛型似乎是一个简单的运行时类型替换机制。
C++模板是编译时构造,它给你一种修改语言来适应你需求的方式。它们实际上是一种在编译期间由编译器执行的纯函数式语言。
Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);
编译时,该代码会被重写为:
Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);
Java泛型的使用并没有真正改变我们的能力;它只是让事情变得更加美观。因此,有时将Java泛型称为“语法糖”。
这与C ++完全不同。在C++中,模板本质上是一个被吹嘘的宏集,编译器为每种类型创建模板代码的新副本。这一点的证据在于MyClass的实例不会与MyClass共享静态变量。但是,两个MyClass的实例将共享静态变量。
/*** MyClass.h ***/
template<class T> class MyClass {
public:
static int val;
MyClass(int v) { val v;}
};
/*** MyClass.cpp ***/
template<typename T>
int MyClass<T>::bar;
template class MyClass<Foo>;
template class MyClass<Bar>;
/*** main.cpp ***/
MyClass<Foo> * fool
MyClass<Foo> * foo2
MyClass<Bar> * barl
MyClass<Bar> * bar2
new MyClass<Foo>(10);
new MyClass<Foo>(15);
new MyClass<Bar>(20);
new MyClass<Bar>(35);
int fl fool->val; // will equal 15
int f2 foo2->val; // will equal 15
int bl barl->val; // will equal 35
int b2 bar2->val; // will equal 35
在Java中,静态变量是在MyClass的所有实例之间共享的,无论不同类型参数如何。
Java泛型和C++模板有许多其他的区别,包括:
template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
Special sum(const Special& a, const Special& b) { return a.plus(b); }
现在,如果您使用指针调用sum函数,将调用第二个方法;如果您使用非指针对象调用sum函数,则将调用第一个方法;如果您使用Special对象调用sum
函数,则将调用第三个方法。我认为这在Java中是不可能的。