1. c++ 约等于 c + 静态检查的面向对象 + 异常处理 + RAII + 泛型
java 约等于 网络计算 + 虚拟机 + 一个强大的跨平台的库
2. c++允许直接调用原生的系统库java要通过JNI调用, 或者 JNA
3. c++ const 关键字用来定义不可改变的常量和成员函式 java final 提供了一个限制版本的 const,等价于 type* const 的物件指标或者 const的基本类型数据。没有 const 成员函式,也没有const type* 指标的等价物
4 C++允许名字空间级别的常量,变量和函数. 而所有这样的 Java 声明必须在一个类或者接口当中.
5. 在 C++ 的声明中,一个类名可以用来声明一个此类对象的值. Java 里没办法做到这点. 在Java里对象不是值. 在 Java 的声明中,一个类名声明的是对此类的一个对象的引用. 而在
C++ 里与之等价的做法是用 '*' 来声明一个指针.
6. 在 C++ 里,'.'操作符将一个对象作为一个左操作参数来访问这个对象的成员. 因为对象在 Java 里不是值,所有的对象都通过引用来访问,刚才的做法在 Java 里是无法实现的. 在 Java 里,'.' 操作符是将一个对象的引用作为左操作参数来访问这个对象的成员.在C++中和这种做法等价的是 '->'.
C++ Java class Foo {
// 声明 Foo 类
public: int x;
// 成員變量
Foo(): x(0) { // Foo 的构造函数Constructor for Foo, }
// 初始化 x
int bar(int i) {
// 成员函数
bar()
return 3*i + x;
}
};
class Foo {
// 定义类
Foo public int x = 0;
// 成员变量,
// 以及其值的初始化
public Foo() {
// Foo的 构造函数
}
public int bar(int i) {
// 成员方法
bar()
return 3*i + x;
}
}
Foo a; // 声明 a 为一个Foo 类的对象值, // 使用其缺省的构造函数// 如果你想要用其他的构造函数, // 你可以用 'Foo a(args);'
Foo a; // 声明 a 为一个Foo 类的对象的引用 a = new Foo(); // 使用缺省的构造函数初始
化 // 如果你想要用其他的构造函数, // 你可以用 'Foo a = new Foo(args);'
Foo b = a; // 拷贝a 的内容到一个新的 Foo 类的变量 b 当中; // 另一种可以选择的语法是 'Foo b(a)'
Foo b = a.clone(); // 拷贝所有a这个实例的成员到b,当且仅当, // Foo 实现了一个public 的 clone() 方法, // 并且 clone() 返回一个新的这个对象的拷贝
Foo *c; // 声明 c 为指向一个Foo 类对象的指针(初始值是 // 未定义的;可能指向任何地方) Foo c; // 声明
c 为一个指向 Foo 对象的指针// (如果 c 是一个类的成员,那么初始值为空; // 如果 c 是一个局部变量那么你在使用之前必须// 对它进行初始化)
c = new Foo(); // 将c 绑定为一个新的 Foo 对象的引用
c = new Foo(); // 将c 绑定为一个新的 Foo 对象的引用
Foo *d = c; // 将d 绑定为和 c 同一个对象的引用
Foo d = c; // 将d 绑定为和 c 同一个对象的引用
c->x = 5; // 修改 c 指向的对象
c.x = 5; // 修改 c 指向的对象
a.bar(5); // 对a 调用 Foo::bar() c->bar(5); // 对*c 调用 Foo::bar()
a.bar(5); // 对a 调用 Foo.bar() c.bar(5); // 对c 调用 Foo.bar()
在 C++ 里,声明一个指向常量的指针是可能的, 也就是说, 你不能修改这个指针指向的对象的内容. 函数和方法也都保证不会修改用 'const' 关键字的指针指向的对象的内容,是强制常量正确性的. 在 Java 里
这是不可能做到的. 你可以声明一个引用为'final'(就像在 C++ 里声明一个'const' 指针), 但这只是阻止你重新绑定这个引用; 你还是可以修改这个'final' 引用指向的对象的.
C++ Java const Foo *a; // 你不能通过a 修改 a 指向的对象
final Foo a; // 你可以通过a 修改 a 指向的对象
a = new Foo();
a = new Foo(); // 只能在构造函数里
a->x = 5; // 非法
a.x = 5; // 合法, 你仍然可以修改这个对象
Foo *const b = new Foo(); // 你可以声明一个'const' 指针
final Foo b = new Foo(); // 你可以声明一个'final' 引用
b = new Foo(); // 非法, 你不能对它再次绑定
b = new Foo(); // 非法, 你不能对它再次绑定
b->x = 5; // 合法,你还是可以修改这个对象
b.x = 5; // 合法,你还是可以修改这个对象
C++ 允许给函数/方法的参数设置缺省值, Java 不提供这个特性. 但是方法重载可以达到同样的效果.\
C++ 允许基本类型之间的一些隐式的转换, 也允许程序员对于用户自定义类型相关的隐式转换规则. 在 Java 里, 只有基本类型之间变宽类型的转换可以是隐式的; 其余的转换需要显式的类型转换语法. 这造成的一个后果是,虽然在 Java 和 C++ 里循环的条件(if, while 和 for 里的退出条件)预期的都是一个布尔表达式, 但 if(a = 5) 这样的代码在 Java 里会导致编译错误,因为没有从整型到布尔的隐式变窄转换. 如果代码是 if(a == 5) 的输错的情况那么是很方便发现这个错误的. 而目前的 C++ 编译器一般来说只会针对这种情况产生一个警告. 对于传参数给函数的情况, C++ 支持引用传递和值传递. 在 Java 里, 参数总是值传递的.[4]但在 Java 里,所有的非基本类型的值都只是对于对象的引用 (用 C++ 的术语来说, 它们是智能指针). 对象在 Java 里不是作为值直接被使用的,只有对象的引用可以被直接操作; 习惯于将对象当做值直接使用的 C++ 开发者经常会把这个跟引用传递搞混.
Java 内建的类型在字节宽度和取值范围上是被虚拟机定义好的; 在 C++ 里, 内建的类型有定义一个最小取值范围, 但是其他的部分(字节宽度)可以被映射成具体平台上支持的原生类型. 举个例子, Java 字符是16位的Unicode字符, 字符串是由这样的字符组成的序列. C++ 提供窄和宽两种字符,但实际的字符宽度
是和平台相关的, 视所用的字符集而定. 字符串可以由这两种字符中的一种组成. 浮点数及其操作的精度和舍入方式在 C++ 里是平台相关的. Java 提供了一个可选的严格的浮点数模型,保证跨平台的一致性,不过可能会导致运行时效率比较差.
在 C++ 里, 指针可以作为内存地址直接操作. Java 没有指针—它只有对象引用和数组引用,这两者都不允许直接用来访问内存地址. 在 C++ 里可以构造一个指向指针的指针,而 Java 的引用只能指向对象. 在 C++ 里, 指针可以指向函数或者方法(函数指针). 在 Java 里的等价物是对象或者接口的引用. 虽然有使用栈内存分配的对象, C++ 还是支持区域资源管理, 一个用来自动管理内存和其他系统资源的技术,此技术支持确定性对象销毁(deterministic object destruction). 不过,区域资源管理在 C++ 里是不被保证的;它只是一个设计模式,所以需要依赖程序员遵守相关的规则. Java 通过使用垃圾搜集来支持自动内存管理,但对于其他的系统资源(窗口,通讯端口,线程),如果垃圾搜集器无法决定它们是否不再被用到,那通常还是需要显式的释放的.
C++ 的用户可自定义操作符重载的特性在 Java 里是不支持的. 唯一在 Java 里可以重载的操作符是 '+' 和 '+=' 操作符, 在字符串里重载为连接字符串.
Java 支持泛型, 其主要目的是提供类型安全的容器. C++ 支持模板, 在泛型编程方面提供了更强的支持.
C++ 方法可以声明为虚函数, 虚函数是在运行期根据对象的类型才确定的. C++ 方法缺省情况下不是虚的.
在 Java 里, 方法缺省情况下是虚的, 但可以使用final关键字使之声明为非虚的.
C++ 枚举属于基本类型,支持和其他整数类型之间的转换和比较. Java 枚举实际上是类的实例(它们从java.lang.Enum<E> 扩展而来),象其他的类一样可以定义构造函数,数据成员及方法.资源管理 Java 提供了自动化的垃圾搜集. 在 C++ 里内存管理通常通过构造函数,析构函数以及智能指针。C++ 标准允许垃圾搜集,但并不强制要求; 实际使用上垃圾搜集极少被用到. 强制使用自动垃圾搜集导致了在 Java 里编写实时软件是困难的.[3] C++ 可以申请任意的内存块.Java 只能通过对象实例化来申请内存. (注意:在 Java 里, 程序员可以通过创建一个字节数组模拟申请任意的内存块. 不过Java 数组仍然是对象.) Java 和 C++ 在资源管理上使用不同的习语, 虚函数是在运行期根据对象的类型才确定的. C++ 方法缺省情况下不是虚的. 在 Java 里, 方法缺省情况下是虚的, 但可以使用final关键字使之声明为非虚的.
C++ 枚举属于基本类型,支持和其他整数类型之间的转换和比较. Java 枚举实际上是类的实例(它们从java.lang.Enum<E> 扩展而来),象其他的类一样可以定义构造函数,数据成员及方法.资源管理 Java 提供了自动化的垃圾搜集. 在 C++ 里内存管理通常通过构造函数,析构函数以及智能指针。C++ 标准允许垃圾搜集,但并不强制要求; 实际使用上垃圾搜集极少被用到. 强制使用自动垃圾搜集导致了在 Java 里编写实时软件是困难的.[3] C++ 可以申请任意的内存块.Java 只能通过对象实例化来申请内存. (注意:在 Java 里, 程序员可以通过创建一个字节数组模拟申请任意的内存块. 不过Java 数组仍然是对象.) Java 和 C++ 在资源管理上使用不同的习语. Java 主要依赖只能回收内存的垃圾搜集机制,因为该机制如果用于
回收使用中的非内存的系统资源可能是非常危险的。而 C++ 主要依赖RAII (资源的获取就是初始化). 这反映了这两种语言的几方面的不同: 在 C++ 里在栈里申请复合类型的对象是很平常的,一旦退出栈的范围就会被销毁. 在 Java 里复合类型的对象总是在堆里申请的内存,而后被垃圾搜集器搜集 (除非在虚拟机里使用了逃逸分析技术来将堆的内存申请转成栈的. C++ 有析构函数, 而 Java 有finalizer(en:finalizer). 两者都会在对象释放之前被调用, 但是它们有显著的不同. 一个C++ 对象的析构函数必须被隐式(栈变量对象的情况)或者显式地调用来释放对象. 析构函数在对象释放之前同步地执行. 同步,协调的反初始化以及释放在 C++ 里满足 RAII 的要求. 在 Java 里, 对象的释放是被垃圾搜集器隐式处理的. 一个Java 对象的 finalizer 在它被最后一次访问之后和在实际释放之前的某个时间点被异步(en:asynchrony) 地调用, 这个调用有
可能一直不产生. 非常少的对象需要 finalizer; 只有那些在释放前必须保证一些清理工作一定要做的对象来说才是需要的 —典型的情况是:释放对JVM 来说是外部的资源. 在 Java 里,企图安全同步的释放某些系统资源,只能用显式的 try/finally 结构来进行.
在 C++ 里是有可能有一个迷途指针的 –过时的对一个已释放的对象的引用(en:reference (computer science)); 试图使用一个迷途指针的结果是导致程序错误. 在 Java 里, 垃圾搜集器不会销毁一个正在被引用的对象. 在 C++ 里未初始化过的基本类型对象是有可能存在的, Java 强制要做缺省初始化. 在 C++ 里有可能申请了一个对象,但对它没有任何引用. 这样的不可达对象(en:unreachable object)是无法被销毁
的,导致了内存泄漏. 作为对比, 在 Java 里一个对象不会被回收直到它变得不可达(对于用户程序来说). (注意: 弱引用(en:weak reference) 是被支持的, 这个特性让Java 的垃圾搜集器能够识别不同 程度的可达性.) 在 Java 里垃圾搜集阻止了很多内存泄漏的情况, 但某些情况下泄漏仍然是可能的.[5] Java 更容易泄漏非内存资源, 而 C++ 的惯用做法更不会导致这种泄漏.
运行时C++ 通常来说会直接被编译成机器码,被操作系统直接执行. Java 通常会被编译成字节码,被Java虚拟机和解释器或者即时编译器编译成机器码然后执行. 因为表达方式不受限制,低级的 C++ 语言特性(例如:不被检查的数组访问,原始指针,类型双关语(en:type punning))
不能在编译期间或者运行期间可靠地被检查. 相关的编程错误会导致低级的缓存溢出和段错误(en:segmentation fault). 标准模板库提供了高级的抽象(例如 vector,list 和 map)来帮助避免这样的错误. 在 Java 里, 低级错误不会发生或者会被JVM检测到并以异常的形式报告给应用. Java 语言在越界访问数组的时候一般来说会对数组进行边界检查(en:bounds checking). 这消除了导致程序不稳定的一个可能因素,但这是以执行速度更慢一些作为代价的. 在一些情况下,编译器分析(en:compiler analysis) 可以检测到不必要的边界检查并去掉. C++ 对于原生数组的越界访问没有要求特定的处理, 所以需要对于原生数组确认不越界. 但
C++ 标准库里的一部分库象 std::vector 也提供了可选的边界检查. 总的来说, Java 数组是'总是安全;严
格限制;开销较多' ,而 C++ 原生数组是'可选的开销; 完全不限制; 有潜在的不安全.' Java 泛型和 c++ 模板
java 泛型: 参数只能是能被引用的类型(非基本类型).static 变量在不同类型参数生成的类的对象之间是共享的.泛型类的类型参数无法用在 static 方法和变量上.不允许生成有参模板类的实例 (除非使用反射).支持类型参数边界, 分别以 'extends' 和 'super' 来定义上界和下界; 同时允许定义类型参数之间的继承关系.泛型类参数无法拥有缺省参数.泛型不能被具体化.编译完成以后类型参数的类型是被消除的; 同一个类用不同类型参数生成的对象在运行期是相同类型的.泛型类和函数在声明的时候强制了类参数的类限制(Generic classes and functions can enforce type relationships for type parameters in their declaration). 使用一个错误的参数会在使用它的时候导致一个类错误. 在泛型代码里操作和参数化类型只能按声明的时候保证安全的方式来使用. 这用失去弹性的代价来换取好得多的类型方面的安全性.
c++模板:与上述的java 泛型特点相反。
Java 和 C++ 在使代码在不同的文件分开方面使用了不同的技术. Java 使用了一个包系统,这个系统对所有的程序都要指定了文件名和路径. 在 Java 里, 编译器负责导入可执行的类文件. C++ 使用了头文件源代码的包含系统来在不同的文件共享声明.
编译好的 Java 代码一般来说比 C++ 文件小,因为Java字节码(en:Java bytecode)一般来说比机器码要
更紧凑[来源请求],Java 程序都不是静态链接的. C++ 编译多了一个文本预处理过程, Java 是没有的. 因此一些使用者在他们的编译过程之前增加了一个预处理的过程,这样能更好的支持需要条件编译的情况. 两个语言里数组都是定长的. 在 Java 里, 数组是一等对象(en:first-class object), 而在 C++ 里它们只是它们的基本类型元素的连续的序列, 经常用一个指向第一个元素的指针和一个可选的长度来引用. 在 Java 里, 数组是被边界检查的,而且知
道它们的长度, 而在 C++ 里你可以将任意的序列当成一个数组. C++和 Java 都提供了相关的
容器类(分别为std::vector 和 java.util.ArrayList),可以改变大小. Java 的除法和模除操作符是
定义成零截断的. C++ 没有定义这两个操作符是零截断的还是'负无穷截断'的. 在 Java 里-3/2
总是得到 -1, 但一个C++ 编译器可能会返回 -1 或 -2, 视平台而定. C99定义了和 Java 一
样的除法方式. 两种语言都保证对于所有的 a 和 b(b!=0)(当  a 和 b都是整型的时候)(a/b)*b +
(a%b) == a. C++ 版本有时候会更快,因为它允许直接使用处理器的截断方式. 整型的长度在 Java 里是已定义好的(int 为32-bit, long 为64-bit), 而在 C++ 里整型和指针的长度是和编译器以及应用二进制接口相 关的. 因此仔细编写的 C++ 代码可以利用64位处理器的能力而又
可以在32位处理器上工作. 但是需要很仔细的用可移植的方式编写. 作为对比, Java 的固定整
型大小使得程序员无法做到这样,没办法利用处理器的字长会导致 Java 在64位处理器上表现
较差. 性能
想运行一个编译好的 Java 程序,计算机上要运行JVM;而编译好的 C++ 程序不需要额外
的应用。比较早期的 Java 版本在性能上比静态编译的语言如 C++ 差得很多,这是因为用
C++ 是直接编译成一些机器指令,而当Java 编译成字节码以后用 JVM 解释执行的时候又牵涉了不少额外的机器指令。
C++ 在大部分的情况下都比 Java 要快,[7]有几个数值方面的基准测试的研究争辩说Java 在某些情况下可能会比 C++ 的性能好得多。[8][9][10]但有人说数值方面的基准测试对于语言的评估是不合适的,因为编译器都可以做相关的优化,甚至可能将被测试的代码彻底删除。[11][12][13]如果涉及到一个真正现实应用的程序,Java 会因为很多原因导致性能变差:[14][15][16]
所有的对象都在堆里被申请。对于使用小对象的函数来说会导致很大的性能损失,因为在栈
里申请内存几乎没有性能损失。方法缺省是虚的。这对于小对象来说会因为虚表增加好几倍
的内存使用。它也会引起性能损失,因为JIT 编译器不得不对查虚表的过程做额外的优化。
即使使用标准的容器依然会有很多的类型转换,这会引起性能损失,因为需要遍历整个继承
树。虚拟机更进一步增加了内存的使用,因此降低了内存的局部性,增加了缓存命中失败
率,从而导致整个程序变慢。缺乏低级细节的操作方式使得开发者无法将程序进一步优化,
因为编译器不支持。[17]有人争论说,和 Java 相比 C++也有很多劣势:
指针使得优化变得困难,因为它们可能指向任意的数据。当然现在这一点也并非完全正确,
因为一些现代的编译器引入了 '严格别名' 的规则[18]并且支持 C99的关键字 restrict,从
而严格限制了指针的使用,使其只能用于指向已知的变量 [19] Java 的垃圾搜集和使用
malloc/new来申请内存相比能拥有更好的缓存连贯性,因为它的申请一般来说是顺序的。然而,始终有争论认为二者同样会导致内存的“零碎化”(即多次分配和回收之后内存空间会变得不连续),且并没有哪一个比对方有更明显的缓存优势。运行时编译可能可以更好的优化代码,因为可以利用运行时的额外的信息,例如知道代码是在什么样的处理器上运行。然而当今的情况也并非完全如此,因为目前最先进的 C++ 编译器也会针对不同系统生成不同的目标代码,以期充分利用该系统的计算能力 [20]此外,有争议的是,花在更复杂的 C++ 代码上的 debug 时间太多,用 Java 开发完全可以把这些时间用来优化 Jav
a 代码。当然对于一个给定的程序来说两种语言能优化到什么程度也是一方面。最后,对于处理器负担很重的情况,例如视频渲染,C++ 能直接访问硬件,在同样一个硬件规格下 C++ 总是会比 Java 的表现好很多。
所有权控制 C++ 不是任何一个公司或者组织的商标,不被任何个人拥有。[21] Java 是Sun
c和java先学哪个
的商标,现在被甲骨文公司拥有。[22]
C++ 语言由ISO/IEC 14882定义,是一个ISO标准,由 ISO/IEC JTC1/SC22/WG21委员会发布。 Java 语言由Java Language Specification[1]定义,这是一本Sun公司(现在是甲骨文)出版的书。