`
yuanlanjun
  • 浏览: 1184273 次
文章分类
社区版块
存档分类
最新评论

C++和java技术特性对比

 
阅读更多

转自 http://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83Java%E5%92%8CC%2B%2B#.E8.B5.84.E6.BA.90.E7.AE.A1.E7.90.86

C++和Java语言之前的不同可以追溯到它们的历史,它们有着不同的设计目标.

不同的开发目标导致 C++ 和 Java 这两种语言的不同的规则以及设计上的平衡点不同. 如下列出不同点:

C++ Java
C语言兼容,除了一些比较少见的情况 没有对任何之前的语言向前兼容.但在语法上受 C/C++ 的影响很大
一次编写到处编译 一次编写到处运行
允许过程编程面向对象编程 鼓励面向对象的编程方式
允许直接调用原生的系统库 要通过JNI(en:Java Native Interface)调用, 或者 JNA(en:Java Native Access)
能直接使用底层系统接口 在一个保护模式下的虚拟机中运行
只提供对象的类型和类型名 反射的, 允许元编程和运行时的动态生成代码
有多种二进制兼容标准 (例如:微软和Itanium/GNU) 一种二进制兼容标准,允许运行时库的正确性检查
可选的自动边界检查. (例如: vectorstring 这两个容器的 at() 方法) 一般都有做边界检查. HotSpot (java)(Sun 的虚拟机实现) 可以去掉边界检查.
支持原生的无符号数学运算 不支持原生的无符号数学运算
对所有的数字类型有标准的范围限制,但字节长度是跟实现相关的. 标准化的类型可以用 typdef 定义 (uint8_t, ..., uintptr_t). 在所有平台上对所有的基本类型都有标准的范围限制和字节长度.
支持指针,引用,值传递 基本类型总是使用值传递. 对象以可以为空的引用的方式传递 (相当于在C++里使用指向 class 或者 struct 参数的指针).[1]
显式的内存管理,但有第三方的框架可以提供垃圾搜集的支持. 支持析构函数. 自动垃圾搜集(可以手动触发).没有析构函数的概念,对 finalize() 的使用是不推荐的.
支持类,结构,联合,可以在或者里为它们动态分配内存. 只支持类,只在中为对象分配内存.Java SE 6在栈为一些对象分配内存的使用了逃逸分析(en:escape analysis)的优化方法.
允许显式的覆盖(也叫重写)类型 严格的类型安全(en:type safety),除了变宽的类型转换. Java 1.5 开始支持自动类型包装和解包装(Autoboxing/Unboxing).
C++标准库包括:语言支持,诊断工具,常用工具,字符串,本地化,容器,算法,迭代器,数值,输入/输出,C标准库. Boost库提供了更多的功能,包括线程和网络I/O.使用者必须在一大堆(大部分互相不兼容)第三方GUI或者其他功能库中进行选择. 标准库在每次 Java 发布新版本的时候都会更新并增强功能. 1.6版本支持:本地化,logging,容器和迭代器,算法,GUI 编程(但没有用到系统的GUI),图形,多线程,网络,平台安全,自省机制,动态类加载,阻塞和非阻塞的I/O,对于XML,XSLT,MIDI也提供了相关接口或者支持类,数据库,命名服务(例如 LDAP),密码学,安全服务(例如 Kerberos),打印服务,WEB 服务.SWT 提供了一个系统相关的GUI的抽象.
对大部分的操作符都可以进行操作符重载(en:Operator overloading) 操作符的意义一般来说是不可变的,例外是 + 和 += 操作符被字符串重载了.
完全的多重继承,包括虚拟继承 类只允许单继承,需要多继承的情况要使用接口.
支持编译期模板 泛型(en:Generics in Java)被用来达到和C++模板类似的效果,但由于类型消除(en:Type Erasure)它们不能在编译期间从代码被编译成字节码.
支持函数指针,函数对象,lambda(在 C++0x)和接口 没有函数指针机制.替代的概念是接口,Adapter 和 Listener也是被广泛使用的.
没有标准的代码内嵌文档机制. 不过有第三方的软件(例如 Doxygen). Javadoc 标准文档生成系统.
const 关键字用来定义不可改变的常量和成员函数 final 提供了一个限制版本的 const, 等价于 type* const 的对象指针或者 const的基本类型数据. 没有 const 成员函数, 也没有const type* 指针的等价物.
支持 goto 语句. 支持循环标签(label)和语句块.
源代码可以写成平台无关的 (可以被 Windows, BSD, Linux, Mac OS X, Solaris 等编译, 不用修改) ,也可以写成利用平台特有的特性. 通常被编译成原生的机器码. 被编译成Java虚拟机的字节码. 和Java平台相关,但是源代码一般来说是不依赖操作系统特有的特性的.

C++ 是一门强大的语言,设计用在系统编程方面.Java语言是设计成简单易用易学习,并有一个强大的跨平台的库.Java标准库对一个标准库来说相当的大.但Java并不会提供所在平台的所有特性和接口. C++标准库简单健壮,提供容器(en:container (data structure))和关联数组(en:associative arrays)的支持.[2]

语言特性

语法

  • Java语法上下文无关文法,可以用一个简单的LALR语法分析器(en:LALR parser)来分析.而分析C++就复杂多了;例如 Foo<1>(3); ,如果 Foo 是一个变量,那么它是一个比较的表达式,但如果 Foo 是一个类模板的名字,那么它会创建一个对象.
  • C++允许名字空间级别的常量,变量和函数. 而所有这样的 Java 声明必须在一个类或者接口当中.
  • 在 C++ 的声明中,一个类名可以用来声明一个此类对象的值. Java 里没办法做到这点. 在Java里对象不是值. 在 Java 的声明中,一个类名声明的是对此类的一个对象的引用. 而在 C++ 里与之等价的做法是用 "*" 来声明一个指针.
  • 在 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() 返回一个新的这个对象的拷贝
a.x = 5; // 修改 a 对象
a.x = 5; // 修改 a 对象
cout << b.x << endl;
// 输出 0,因为 b 和 a 是两个对象
System.out.println(b.x);
// 输出 0,因为 b 和 a 是两个对象
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()
cout << d->x << endl;
// 输出 5,因为 d 引用的对象和 c 一样
System.out.println(d.x);
// 输出 5,因为 d 引用的对象和 c 一样
  • 在 C++ 里,声明一个指向常量(en:Constant (programming))的指针是可能的, 也就是说, 你不能修改这个指针指向的对象的内容. 函数和方法也都保证不会修改用 "const" 关键字的指针指向的对象的内容,是强制常量正确性(en:const-correctness)的. 在 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++ 支持 goto 语句; Java 强制结构化流程控制( structured control flow), 依赖break标签continue标签 语句来提供类似于 goto 的部分功能. 一些评论者指出这些标签化的流程控制打破了结构化编程的单退出点的特点.[3]
  • C++ 提供了一些 Java 缺乏的低级特性. 在 C++ 里, 指针可以用来操作特定的内存位置, 这是在写低级操作系统模块的时候必须用到的. 类似的, 许多 C++ 编译期支持内联汇编(en:inline assembler). 在 Java 里, 这样的代码只能放在外来的库中,而且在调用的时候只能通过JNI来访问这些外来库提供的接口.

语义

  • C++ 允许给函数/方法的参数设置缺省值, Java 不提供这个特性. 但是方法重载(en:method overloading)可以达到同样的效果.
  • C++ 里最小的编译单位是一个函数; Java 里最小的编译单位是一个类. 在 C++ 里, 函数可以被单独编译. 在 Java 里, 要编译和维护单独的方法需要把它们移到超类(en:Superclass (computer science))或子类(en:Subclass (computer science))或者使用其他的代码重构(en:code refactoring)的技巧.
  • C++ 允许基本类型之间的一些隐式的转换, 也允许程序员对于用户自定义类型相关的隐式转换规则. 在 Java 里, 只有基本类型之间变宽类型的转换可以是隐式的; 其余的转换需要显式的类型转换语法.
    • 这造成的一个后果是,虽然在 Java 和 C++ 里循环的条件(if, whilefor 里的退出条件)预期的都是一个布尔表达式, 但 if(a = 5) 这样的代码在 Java 里会导致编译错误,因为没有从整型到布尔的隐式变窄转换. 如果代码是 if(a == 5) 的输错的情况那么是很方便发现这个错误的. 而目前的 C++ 编译期一般来说只会针对这种情况产生一个警告.
  • 对于传参数给函数的情况, C++ 支持引用传递值传递. 在 Java 里, 参数总是值传递的.[4] 但在 Java 里,所有的非基本类型的值都只是对于对象的引用 (用 C++ 的术语来说, 它们是智能指针). 对象在 Java 里不是作为值直接被使用的,只有对象的引用可以被直接操作; 习惯于将对象当做值直接使用的 C++ 开发者经常会把这个跟引用传递搞混.
  • Java 内建的类型在字节宽度和取值范围上是被虚拟机定义好的; 在 C++ 里, 内建的类型有定义一个最小取值范围, 但是其他的部分(字节宽度)可以被映射成具体平台上支持的原生类型.
    • 举个例子, Java 字符是16位的Unicode字符, 字符串是由这样的字符组成的序列. C++ 提供窄和宽两种字符,但实际的字符宽度是和平台相关的, 视所用的字符集而定. 字符串可以由这两种字符中的一种组成.
  • 浮点数及其操作的精度和舍入方式在 C++ 里是平台相关的. Java 提供了一个可选的严格的浮点数模型(en:strictfp),保证跨平台的一致性,不过可能会导致运行时效率比较差.
  • 在 C++ 里, 指针可以作为内存地址直接操作. Java 没有指针 — 它只有对象引用和数组引用,这两者都不允许直接用来访问内存地址. 在 C++ 里可以构造一个指向指针的指针,而 Java 的引用只能指向对象.
  • 在 C++ 里, 指针可以指向函数或者方法 (函数指针(en:function pointer)). 在 Java 里的等价物是对象或者接口的引用.
  • 虽然有使用栈内存分配的对象, C++ 还是支持区域资源管理, 一个用来自动管理内存和其他系统资源的技术,此技术支持确定性对象销毁(deterministic object destruction). 不过,区域资源管理在 C++ 里是不被保证的;它只是一个设计模式,所以需要依赖程序员遵守相关的规则. Java 通过使用垃圾搜集来支持自动内存管理,但对于其他的系统资源(窗口,通讯端口,线程),如果垃圾搜集器无法决定它们是否不再被用到,那通常还是需要显式的释放的.
  • C++ 的用户可自定义操作符重载的特性在 Java 里是不支持的. 唯一在 Java 里可以重载的操作符是 "+" 和 "+=" 操作符, 在字符串里重载为连接字符串.
  • Java 的标准应用程序接口支持反射动态加载(en:Dynamic loading)任意代码.
  • C++ 支持静态和动态的库连接.
  • Java 支持泛型, 其主要目的是提供类型安全的容器. C++ 支持模板, 在泛型编程方面提供了更强的支持.
  • Java 和 C++ 都对基本类型(也叫"内建"类型)和用户自定义类型(也叫"复合"类型). 在 Java 里, 基本类型只有值的语义,复合类型只有引用的语义. 在 C++ 里所有的值都有值语义,可以创建对于任何类型的引用,这样就允许通过引用语义来操作对象.
  • C++ 支持任意类型的多重继承. 在 Java 里一个类只能从单个的类继承而来,但一个类可以实现多个的接口(en:Interface (Java))(换句话说,它支持类型的多重继承,但对于实现只能单继承(it supports multiple inheritance of types, but only single inheritance of implementation)).
  • Java 对于类和接口是显式区分的. 在 C++ 里多重继承和纯虚函数使得定义出类似于 Java 的接口的类是可能的,不过会有少许区别.
  • Java 在语言和标准库都对多线程有良好的支持. synchronized 这个 Java 的关键字为了支持多线程应用提供了简单而安全的互斥锁 ,但同步(synchronized)区只能用 LIFO 的顺序离开. Java 也为更高阶的多线程同步提供了健壮而复杂的库. 在 C++ 里没有专门为多线程定义的内存模型; 但第三方库提供了和 Java 差不多的功能; 不过这些 C++ 库之间差异较大,一致性不好.
  • C++ 方法可以声明为虚函数, 虚函数是在运行期根据对象的类型才确定的. C++ 方法缺省情况下不是虚的. 在 Java 里, 方法缺省情况下是虚的, 但可以使用final关键字使之声明为非虚的.
  • C++ 枚举属于基本类型,支持和其他整数类型之间的转换和比较. Java 枚举实际上是类的实例(它们从 java.lang.Enum<E> 扩展而来),象其他的类一样可以定义构造函数,数据成员及方法.

资源管理

  • Java 提供了自动化的垃圾搜集. 在 C++ 里内存管理通常通过构造函数,析构函数以及智能指针(en:smart pointer). C++ 标准允许垃圾搜集,但并不强制要求; 实际使用上垃圾搜集极少被用到. 强制使用自动垃圾搜集导致了在 Java 里编写实时软件(en:Real-time computing)是困难的.[3]
  • C++ 可以申请任意的内存块.Java 只能通过对象实例化来申请内存. (注意:在 Java 里, 程序员可以通过创建一个字节数组模拟申请任意的内存块. 不过 Java 数组仍然是对象.)
  • Java 和 C++ 在资源管理上使用不同的习语. Java 主要依赖垃圾搜集,which can only reclaim memory and may be a last shot at other resources(不知道咋翻译...), 而 C++ 主要依赖 RAII (资源的获取就是初始化). 这反映了这两种语言的几方面的不同:
    • 在 C++ 里在栈里申请复合类型的对象是很平常的,一旦退出栈的范围就会被销毁. 在 Java 里复合类型的对象总是在堆里申请的内存,而后被垃圾搜集器搜集 (除非在虚拟机里使用了逃逸分析(en:escape analysis)技术来将堆的内存申请转成栈的.
    • 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 到原生的操作系统和硬件相关的函数的直接访问需要用到JNI(en:Java Native Interface).

运行时

  • C++ 通常来说会直接被编译成机器码,被操作系统直接执行. Java 通常会被编译成字节码,被Java虚拟机解释器或者即时编译器编译成机器码然后执行.
  • 因为表达方式不受限制,低级的 C++ 语言特性(例如:不被检查的数组访问,原始指针,类型双关语(en:type punning))不能在编译期间或者运行期间可靠地被检查. 相关的编程错误会导致低级的缓存溢出段错误(en:segmentation fault). 标准模板库 提供了高级的抽象(例如 vetor,list 和 map)来帮助避免这样的错误. 在 Java 里, 低级错误不会发生或者会被JVM检测到并以异常的形式报告给应用.
  • Java 语言在越界访问数组的时候一般来说会对数组进行边界检查(en:bounds checking). 这消除了程序不稳定的一个可能原因但是以更慢一些的执行速度作为代价的. 在一些情况下,编译器分析(en:compiler analysis)可以检测到不必要的边界检查并去掉. C++ 对于原生数组的越界访问没有要求特定的处理, 所以需要对于原生数组确认不越界. 但C++ 标准库里的一部分库象 std::vector 也提供了可选的边界检查. 总的来说, Java 数组是"总是安全;严格限制;开销较多" ,而 C++ 原生数组是"可选的开销; 完全不限制; 有潜在的不安全."

模板 vs. 泛型

C++ 和 Java 都提供泛型编程的能力,分别是模板泛型(en:Generics in Java). 虽然它们被创造用来解决类似的问题,有类似的语法,但实际上很不一样.

C++ 模板 Java 泛型
类和函数都可以使用模板. 类和方法都可以使用泛型.
参数可以是任意类型或者整型. 参数只能是能被引用的类型(非基本类型).
在编译的时候对于每种类型生成类或者函数的拷贝. 对于所有类型的参数,只有一个版本的类或者函数生成.
同一个类用不同类型生成的对象在运行期也是不同类型的 编译完成以后类型参数的类型是被消除的; 同一个类用不同类型参数生成的对象在运行期是相同类型的.
想要用到模板类或者函数的实现代码的话必须 include 它(只是声明是不够的). 有一个编译好的类文件里的类或者函数的签名就足以使用泛型了
模板可以被具体化 -- 可以为某个特定的模板参数提供单独的实现. 泛型不能被具体化.
模板参数可以有缺省参数(en:default argument)(只针对对于模板类,模板函数是没有此特性的). 泛型类参数无法拥有缺省参数.
不支持通配符. 返回的类型经常是嵌套的 typedef 形式的. 如果只用一次,那么支持通配符作为类型参数.
不直接支持设置类型参数的边界 (即, 不允许说明类型参数必须为某个类型的子类/父类), 但超编程提供了这个特性[6] 支持类型参数边界, 分别以 "extends" 和 "super" 来定义上界和下界; 同时允许定义类型参数之间的继承关系
允许生成有参模板的类的实例 (如 foo = new Foo<T>, T 为参数) 不允许生成有参模板类的实例 (除非使用反射)
模板类的类型参数可以用在 static 方法和变量上. 泛型类的类型参数无法用在 static 方法和变量上.
static 变量不在在不同的类型参数生成的类之间共享. static 变量在不同类型参数生成的类的对象之间是共享的.
泛型类和函数在声明时不强制类参数的类限制. 使用错误的类参数会导致模板代码"不工作". 值得注意的是, 如果使用了错误的参数, 则错误信息将出现在定义模板的代码处 (而非调用模板的代码处), 说明 "不支持以该类型作为参数来实例化模板". 这种错误信息往往难以帮助人们找出真正的问题所在 (编程时究竟使用了何种 "错误的" 参数). 因此, 模板类或者函数的正确使用更依赖于正确的文档. 超编程以额外的代价提供了这些特性. 泛型类和函数在声明的时候强制了类参数的类限制(Generic classes and functions can enforce type relationships for type parameters in their declaration). 使用一个错误的参数会在使用它的时候导致一个类错误. 在泛型代码里操作和参数化类型只能按声明的时候保证安全的方式来使用. 这用失去弹性的代价来换取好得多的类型方面的安全性.
模板是图灵完全的 (参见 模板超编程). 泛型不是图灵完全的.

杂项

  • 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::vectorjava.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 解释执行的时候又牵涉了不少的机器码. 例如:

Java/C++ 语句 C++ 生成的代码 (x86) Java 生成的字节码
vector[i]++; mov edx,[ebp+4h]

mov eax,[ebp+1Ch]
inc dword ptr [edx+eax*4]

aload_1

iload_2
dup2
iaload
iconst_1
iadd
iastore

C++ 在大部分的情况下都比 Java 要快, 有几个数值方面的基准测试的研究争辩说 Java 在某些情况下可能会比 C++ 的性能好得多. 但有人说数值方面的基准测试对于语言的评估是不合适的,因为编译器都可以做相关的优化,甚至可能将被测试的代码彻底删除.如果涉及到一个真正现实应用的程序, Java 会因为很多原因导致性能变差:

  • 所有的对象都在堆里被申请. 对于使用小对象的函数来说会导致很大的性能损失,因为在栈里申请内存几乎没有性能损失.
  • 方法缺省是虚的. 这对于小对象来说会因为虚表增加好几倍的内存使用. 它也会引起性能损失,因为 JIT 编译器不得不对查虚表的过程做额外的优化.
  • 即使使用标准的容器依然会有很多的类型转换,这会引起性能损失,因为需要遍历整个继承树.
  • 虚拟机更进一步增加了内存的使用,因此降低了内存的局部性,增加了缓存命中失败率,从而导致整个程序变慢.
  • 缺乏低级细节的操作方式使得开发者无法将程序进一步优化,因为编译器不支持.

有人争论说,和 Java 相比 C++也有很多劣势:

  • 指针使得优化变得困难,因为它们可能指向任意的数据. 当然现在这一点也并非完全正确, 因为一些现代的编译器引入了 "严格别名" 的规则 并且支持 C99 的关键字 restrict, 从而严格限制了指针的使用, 使其只能用于指向已知的变量 [19]
  • Java 的垃圾搜集和使用malloc/new来申请内存相比能拥有更好的缓存连贯性,因为它的申请一般来说是顺序的. 然而, 始终有争论认为二者同样会导致内存的 "零碎化" (即多次分配和回收之后内存空间会变得不连续), 且并没有哪一个比对方有更明显的缓存优势.
  • 运行时编译可能可以更好的优化代码,因为可以利用运行时的额外的信息, 例如知道代码是在什么样的处理器上运行. 然而当今的情况也并非完全如此, 因为目前最先进的 C++ 编译器也会针对不同系统生成不同的目标代码, 以期充分利用该系统的计算能力 [20]

此外, 有争议的是,花在更复杂的 C++ 代码上的 debug 时间太多,用 Java 开发完全可以把这些时间用来优化 Java 代码.当然对于一个给定的程序来说两种语言能优化到什么程度也是一方面.最后, 对于处理器负担很重的情况,例如视频渲染,C++ 能直接访问硬件,在同样一个硬件规格下总是会比 Java 的表现好很多.

所有权控制

C++ 不是任何一个公司或者组织的商标,不被任何个人拥有.Java 是Sun的商标, 现在被甲骨文公司拥有.[22]

C++ 语言被ISO/IEC 14882定义, 是一个 ISO 标准, 由 ISO/IEC JTC1/SC22/WG21委员会发布. Java 语言由Java Language Specification[1]定义, 这是一本升阳电脑 (现在是甲骨文) 出版的书.

分享到:
评论

相关推荐

    C++与java比较

    C++与java语法及特性比较,非常适合于两者间来回切换的开发者学习。

    java基础学习笔记 java整合技术 java工具类.rar

    简单性:相对于其他编程语言而言,java较为简单,例如:java不再支持多继承,C++是支持多继承的,多继承比较复杂,C++中有指针,java中屏蔽了指针的概念,避免了绝大部分的指针越界和内存泄露的问题,这里说明一下,...

    Java实时性及嵌入式实时Java处理器研究

    和桌面系统的软件开发相比,嵌入式软件开发普遍还使用比较传统的C/C++甚至汇编语言进行,难以适应嵌入式系统的迅猛发展,因此需要新的开发方法和开发手段来解决。Java语言的面向对象、跨平台、语言级并发支持、安全...

    C++入门经典(第三版)

    初学者常常觉得C++比其他语言难懂,这可能是因为它的功能和适用范围比较复杂。但是,C++并不比其他语言难学,只是比其他语言多一些内容而已。 本书的宗旨是尽可能使C++容易理解和掌握,读者不需要有任何编程经验,...

    ICE讲座资料,包括PPT和C++源程序

    写ICE程序的客户端,而服务器端一般利用C++或者JAVA 来实现). • 提供一组完整的特性,支持广泛的领域中的实际的分布式应用的开发。 • 避免不必要的复杂性,使平台更易于学习和使用。 ICE的学习比较曲线比较短,很...

    Visual C++实践与提高-COM和COM+篇『PDF』

    6.1.2 比较MFC和ATL 6.2 MFC对COM开发的支持 6.2.1 MFC简介 6.2.2 MFC对自动化的支持 6.2.2.1 MFC AppWizard支持 6.2.2.2 CCmdTarget类支持 6.2.3 MFC对复合文档的支持 6.2.4 MFC对ActiveX控件的支持 6.3 使用MFC...

    Understand for c++ 2.6

    1、支持多语言:Ada, C, C++, C#, Java, FORTRAN, Delphi, Jovial, and PL/M ,混合语言的project也支持 2、多平台: Windows/Linux/Solaris/HP-UX/IRIX/MAC OS X 3、代码语法高亮、代码折迭、交叉跳转、书签等基本...

    java 编程入门思考

    附录B 对比C++和Java 附录C Java编程规则 附录D 性能 D.1 基本方法 D.2 寻找瓶颈 D.2.1 安插自己的测试代码 D.2.2 JDK性能评测[2] D.2.3 特殊工具 D.2.4 性能评测的技巧 D.3 提速方法 D.3.1 常规手段 D.3.2 依赖...

    C++入门经典第3版.pdf

    初学者常常觉得C++比其他语言难懂,这可能是因为它的功能和适用范围比较复杂。但是,C++并不比其他语言难学,只是比其他语言多一些内容而已。 本书的宗旨是尽可能使C++容易理解和掌握,读者不需要有任何编程经验,...

    Java初学者入门教学

    附录B 对比C++和Java 附录C Java编程规则 附录D 性能 D.1 基本方法 D.2 寻找瓶颈 D.2.1 安插自己的测试代码 D.2.2 JDK性能评测[2] D.2.3 特殊工具 D.2.4 性能评测的技巧 D.3 提速方法 D.3.1 常规手段 D.3.2 依赖...

    java联想(中文)

    附录B 对比C++和Java 附录C Java编程规则 附录D 性能 D.1 基本方法 D.2 寻找瓶颈 D.2.1 安插自己的测试代码 D.2.2 JDK性能评测[2] D.2.3 特殊工具 D.2.4 性能评测的技巧 D.3 提速方法 D.3.1 常规手段 D.3.2 依赖...

    JAVA上百实例源码以及开源项目

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    【文献综述】基于JAVA的俄罗斯方块游戏设计与实现.pdf

    甲骨文公司对于 Java 的许可是"全兼容的" ,这也导致了微软和升阳关于微软的程序不 支持 RMI 和 JNI 接口、并且增加特性为己所用的法律争端。升阳最终赢得了官司,获得了大 约两千万美元的赔偿,法院强制要求微软...

    JAVA上百实例源码以及开源项目源代码

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 301 11.3.2 公共子表达式消除 / 305 11.3.3 数组边界检查消除 / 307 11.3.4 方法内联 / 307 11.3.5 逃逸分析 / 309 11.4 Java与C/C++的编译器对比 / 311 11.5 本章小结 / 313 第五部分 高效并发 第12章 ...

    java学习方法

    对于初学者来说,最好是找一本Java入门的书籍,但是比较完整的循序的介绍Java的语法,面向对象的特性,核心类库等等,在看这本书的同时,可以同步来看《Thinking in Java》,来加深对Java的理解和原理的运用,同时又...

    Java面试宝典和大学生面试宝典

    金融软件公司 通信公司 数据通信公司 软件公司 笔 试 内 容 C++ ,Linux,UNIX C++ ,网络 C++或 Java Java,数据库 C++ C++ C++或 Java 或 C# C++ ,数据结构,智力测试 C++或 Java,数据结构,数据库(SQL) ...

    JAVA_Thinking in Java

    附录B 对比C++和Java 附录C Java编程规则 附录D 性能 D.1 基本方法 D.2 寻找瓶颈 D.2.1 安插自己的测试代码 D.2.2 JDK性能评测[2] D.2.3 特殊工具 D.2.4 性能评测的技巧 D.3 提速方法 D.3.1 常规手段 D.3.2 依赖...

    java并发编程实战 pdf

    工业界目前最流行的面向对象编程语言就是C++和Java。所以基本上锁定这两个方向就可以了。而且完全可以同时掌握。  3。掌握Java的精华特性而且一定要知道为什么。比如,Interface和multi-thread。用interface是更好...

    c++书稿 C++语言的基础知识和一般的编程思想有机结合

    本书由三个部分组成:第一部分(第1章到第8章)是对C++基本特性的介绍,有些是和C有类似的地方。第二部分(第9章到第11章)是关于C++面向对象的基本思想及设计方法。这些是C中所没有的,正是这一部分,使得许多人...

Global site tag (gtag.js) - Google Analytics