JAVA和C++对比学习

JAVA与C++的比较网上有很多讨论。比较清晰完整的有:

http://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83Java%E5%92%8CC%2B%2B

我无意比较哪个语言更好,只是希望总结对比一下两种语言,各自取其优点用于自己的开发中。

我认为是优点的标准是:是否能让代码更易理解,更不容易出错。至于运行效率未作为考虑因数。

1 编译与连接

1.1 导入

  • java使用import关键字直接导入目标码文件,IDE可以自动从中导出可用的接口信息
  • C++使用预处理命令导入头文件,之后才进行链接

头文件必须要作为代码连接的“门面”好好维护

1.2 文件

1.2.1 源代码

  • JAVA每个类一个文件,每个目录一个package
  • C++可以多个类一个文件

可以借鉴JAVA的package概念,以目录结构划分源代码。多用文件分割不同的类。

1.2.2

  • JAVA可直接使用和运行(只要带有mian())任何.class文件,或者打包成JAR文件
  • C++可以使用.o文件参与链接,但通常发布为静态库或动态库

需要注意维护.h文件和makefile文档说明,以免编译错误

1.3 组织

  • JAVA使用ClassLoader在运行时载入和调用
  • C++静态库在编译时写入可执行文件,动态库则在运行时通过系统调用加载和调用

每个库都提供动态和静态两种方式发布,以及足够简洁的makefile和安装脚本

2 语法特色

2.1 const

  • C++独有,可以限定指针指向的对象不可变,同时也可以限定指针本身不可变,常用于函数参数的声明,减少修改输入参数的恶劣实践
  • JAVA只有final关键字,只能限定对象的属性不可改变对象,但是其指向的对象本身是可变的

JAVA的推荐编码实践中有一条:不得修改函数参数传入的对象,以保持对象封装的完整性。如果有const修饰符就不需要靠人工来遵守了

2.2 默认参数

  • C++可以在声明函数时添加参数的默认值
  • JAVA没有办法添加默认值,只能通过方法重载,声明一堆不同参数数量的同名函数来实现

让用户可以用尽量少的参数来调用函数,是节省开发时间的重要手段,如果参数列表确实太长,考虑使用setter方法来简化对象的使用

2.3 函数指针

  • C++可以定义函数指针,并且可以放入各种STL容器
  • JAVA必须要通过定义一个Interface来声明函数的形式,然后用一个对象实现这个接口,最后把整个对象作为函数指针的载体来操作

现代脚本语言基本都有类似函数指针的设计,用以简化“回调”。JAVA的实现较为重型,需要仔细规划需要回调的模型

2.4 操作符重载

  • C++独有,可以用以实现很多特别的功能,STL容器就是一个。可以自造语法糖,非常不错。
  • JAVA只有String类的+、+=是内部重新定义过的,语法比较固定和标准

JAVA可以使用接口以及实现接口的方法,来增加更多的表意,如经典的equal()方法代替==运算符

2.5 异常

  • C++的异常可以是任何类型的数据,不强制处理

应该使用异常代替错误码返回值,而且应该通过宏功能让异常加入更多源代码信息,程序员应该强制自己处理所有的异常。

  • JAVA的异常全部是基于某个“可抛出类”,带有调用栈信息,在编译时强制处理

2.6 多线程

  • C++语言定义没有涉及多线程部分,STL也不考虑并发情况

通常并发锁是一个int或者文件,如果能与需锁对象关联起来,会让代码更易读,学习JAVA的synchonize的逻辑做法

  • JAVA语言有synchonize关键字用以锁定,标准库也有Thread类和Runable接口

3 内存管理

3.1 内存回收

  • C++可以自由选择在堆还是栈上申请内存(变量),栈上的变量会被自动回收,而且会自动调用析构函数,在堆上申请的变量,使用delete来回收内存以及调用析构函数
  • JAVA所有类对象只能new在堆上,不需要手动回收,也无法主动回收;

JAVA的对象使用起来较简单,但是没有C++的标准析构规则,对于非内存资源,需要手动关闭,要在代码文档中强调对close()方法的调用,new和close要成对使用

3.2 基本变量类型

  • C++变量类型长度不固定,有带符号和不带符号的区别

为了在32和64位机上通用,通常需要定义uint32_t之类的类型来统一长度

  • JAVA变量长度固定,全部都是带符号的

3.3 复合变量类型

  • C++中的struct实际上连续存放的内存块

利用指针运算读写结构比较容易出错或者溢出,挨个赋值虽然笨拙却较易找到问题

  • JAVA的对象内存结构比较复杂,无顺序规则

3.4 指针与句柄

  • C++拥有* & . -> []数种利用指针操作数据的手段,对于内存操作非常灵活
  • JAVA固定了基本类型只能按值传递,类对象只能按句柄(值)传递,类似某种智能指针

严格理解按值传递和句柄的理解,严防不合理的修改类对象数据

3.5 复制

  • C++拥有复制三法则,可以自己控制复制的细节

自己定义复制细节过于繁琐,而且不正确的复制容易产生“截断”属性,不如统一用clone()方法更实用

  • JAVA有默认的clone()方法,也可以自己实现clone(),hashCode(),equals()来实现细节

3.6 数组

  • C++的数组是连续内存空间

数组常用于申请一块内存供任何用途,从而缺乏对指针的控制,应该学习JAVA的数组,严格按照声明类型使用,并且小心记录自己的长度

  • JAVA数组是一种定长容器,下标溢出会有异常抛出

4 面向对象

4.1 多重继承

  • C++直接可以多重继承,因此引出了虚继承等比较复杂的概念

大部分情况下多重继承都容易让事情变得更复杂。一般来说认为委托比继承好,多写一些代码,用纯虚类继承加上委托来处理,会让耦合度降低

  • JAVA无法多重继承,必须要用接口和委托的方法来实现多重继承

4.2 覆盖

  • C++使用virtual关键字指定可覆盖方法
  • JAVA使用final关键指定不可覆盖的方法

JAVA的覆盖规则比较宽松,为了限定覆盖的扩散,应尽量收窄方法的访问权限,多用final和private,不要随便一写public

4.3 多态

  • C++使用指针或引用来实现动态绑定

C++需要额外注意需要动态绑定的时候,使用的是否引用和虚函数。

  • JAVA的类对象都是句柄,全部可以动态绑定

4.4 访问权限控制

  • C++有友元
  • JAVA的默认权限是friendly,包内可用

为了灵活划分代码的可耦合程度,必须善用“包”和friendly权限,减少public权限的内容

4.5 构造器

  • C++有初始化列表,可以在其中选择不同的基类构造函数
  • JAVA在子类构造器中假模假样的调用一下选择的基类构造器,实际上那行代码并非在那个时间被调用

JAVA缺乏明确的初始化个成员以及自己的语法,需要非常注意各属性的初始化写法,以防出现null句柄成员

4.6 反射

  • C++只能在运行时获取类型名字,无法进行进一步操作

用宏或者存储工厂函数指针的方法来实现反射,虽然麻烦但是也只能这样了

  • JAVA可以用类名和Class类执行全部的对象操作,如构造对象、调用方法

5 API与库

5.1 标准库

  • C++拥有STL库,可以完成基础的数据结构和最简单的IO任务,也有boost这个比较丰富的准标准库

统一的API库也许会丧失一定的灵活性,但是可以更好的提升代码的可读性,在学习API的使用技巧方面也能提供更大的空间

  • JAVA拥有一个包罗万象的标准库:JDK,而且发展和改进的非常快

5.2 扩展性

  • C++兼容C语言,windows和linux都是用C语言编写的软件,使用系统API时完全没有门槛
  • JAVA基本上只能用标准JDK来构造功能,另外也可以用JNI来引入本地(C语言编写)的代码

很多最时髦的操作系统功能,都不能做到跨平台,因此需要多多利用JNI功能,可以大大提高JAVA的工作效能

6 模板

6.1 运行机制

  • C++在编译时生成所有具体类的代码,在运行前已经自动生成好一批新的类
  • JAVA采用运行时动态转换类的做法处理

JAVA编译期间并未生成新的类,但应当视之为创建了新的类,不应该大量滥用,特别是和反射混搭来使用

6.2 算法基础

  • C++使用算术运算符如<来实现STL算法,需要用户重载运算符

运算符的数量和意义都比较有限,适用面比较窄,还是使用扩展纯虚基类方法来为特定算法服务比较好

  • JAVA使用equals(),compare()等接口方法来实现通用算法

最后不能免俗的总结一下:

1)编译构建部分,JAVA在易用性和规范性上完胜C++,基于VM的语言确实能让机器帮人做更多的事情

2)语法特色部分,C++从语法上实现了很多JAVA最佳实践,JAVA只在异常和多线程这类“时髦”特性上有所改进

3)内存管理各有千秋,C++更加严谨,而JAVA则更易用。C++就好像食堂吃饭,须自己交盘子,JAVA则好像饭店,有人会帮你收拾碗筷。但是JAVA如此更容易诱导程序员泄露非内存资源。

4)模板和API部分各自有优秀的地方,但是觉得模板范式C++更正宗,更能体现静态之美,JAVA只是利用动态的优势效颦了一下。

5)号称为面向对象而生的JAVA,在OO上确实得了VM动态运行的好处,但是也有很多容易诱导程序员犯错的地方,需要《最佳实践》之类的教条来自我约束。而C++则更加严格。

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。

原文发布于微信公众号 - 韩大(handa1740168)

原文发表时间:2016-01-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT技术篇

gcc 编译参数 -fno-strict-aliasing

  最近在项目中遇到一个问题,当使用double类型数据时,在进行jce编解码后会出现乱数据问题,比如encode一个数据.

47927
来自专栏向治洪

Kotlin 1.2 新特性

在Kotlin 1.1中,团队正式发布了JavaScript目标,允许开发者将Kotlin代码编译为JS并在浏览器中运行。在Kotlin 1.2中,团队增加了在...

19410
来自专栏haifeiWu与他朋友们的专栏

Java命令之javap初探

javap是jdk自带的一个工具在jdk安装目录的/bin下面可以找到,可以对代码反编译,也可以查看java编译器生成的字节码,对代码的执行过程进行分析,了解j...

592
来自专栏iOS开发笔记

iOS开发之单例模式你用对了吗

、 单例在iOS开发中可以说是很常见的一种设计模式,在你的项目中或许你已经用过很多次,大家可能都会想不就是单例吗,我闭着眼睛单手就能写。是的,单例可以说是所有设...

784
来自专栏逆向技术

C++反汇编第六讲,认识C++中的Try catch语法,以及在反汇编中还原

      C++反汇编第六讲,认识C++中的Try catch语法,以及在反汇编中还原 我们以前讲SEH异常处理的时候已经说过了,C++中的Try catch...

20110
来自专栏PHP技术

PHP程序员容易忽略的几点精华

1、变量、数组的应用技巧   (1)很多人用得不多的数组函数。foreach、list、each。分别举几个例子,应该就能知道了。例:   $dat...

33510
来自专栏Flutter入门到实战

Android插件化开发核心类ClassLoader相关详解

最近在研究插件化开发,顺便就了解了 ClassLoader 这个类加载器,顺藤摸瓜,查到了jvm里面的双亲委派模型,这里就简单的讲一下什么是预定义类加载器和双亲...

913
来自专栏java学习

面试题7(考察运算符的优先级)

请选择下面代码运行后打印的结果。 public static void main(String[]args){ int x=5; int y=3; x=x+(x...

2898
来自专栏人工智能LeadAI

深入浅出地,彻彻底底地理解python中的编码

python处理文本的功能非常强大,但是如果是初学者,没有搞清楚python中的编码机制,也经常会遇到乱码或者decode error。本文的目的是简明扼要地说...

3359
来自专栏杂烩

duubo分组聚合 原

除了官网上有这部分的简单介绍外,在别的地方几乎找到真正可行的测试了,这里自己捣鼓一下,已做备忘。

521

扫码关注云+社区