Java和C++的对比

事实上, Java 原本就是从 C++衍生出来的。 java

 

C++和 Java 之间仍存在一些显著的差别。能够这样说,这些差别表明着技术的极大进步。一旦咱们弄清楚了这些差别,就会理解为何说 Java 是一种优秀的程序设计语言。这里将引导你们认识用于区分Java 和 C++的一些重要特征。程序员

 

(1) 最大的障碍在于速度:解释过的 Java 要比 C 的执行速度慢上约 20 倍。不管什么都不能阻止 Java 语言进行编译。出现了一些准实时编译器,它们能显著加快速度。固然,咱们彻底有理由认为会出现适用于更多流行平台的纯固有编译器,但倘若没有那些编译器,因为速度的限制,必须有些问题是Java 不能解决的。数据库


(2) 和 C++同样, Java 也提供了两种类型的注释。
编程

 

(3) 全部东西都必须置入一个类。不存在全局函数或者全局数据。若是想得到与全局函数等价的功能,可考虑将 static 方法和 static 数据置入一个类里。注意没有象结构、枚举或者联合这一类的东西,一切只有“类”( Class)!数组


(4) 全部方法都是在类的主体定义的。因此用 C++的眼光看,彷佛全部函数都已嵌入,但实情并不是如此。
安全


(5) 在 Java 中,类定义采起几乎和 C++同样的形式。但没有标志结束的分号。没有 class foo 这种形式的类声明,只有类定义。
网络

1 class aType()
2   void aMethod() {/* 方法主体 */}
3 }

 

(6) Java 中没有做用域范围运算符“ ::”。 Java 利用点号作全部的事情,但能够不用考虑它,由于只能在一个类里定义元素。即便那些方法定义,也必须在一个类的内部,因此根本没有必要指定做用域的范围。咱们注意到的一项差别是对 static 方法的调用:使用 ClassName.methodName()。 除此之外, package(包)的名字是用点号创建的,并能用 import 关键字实现 C++的“ #include”的一部分功能。例以下面这个语句:
多线程

1 import java.awt.*;

( #include 并不直接映射成 import,但在使用时有相似的感受。)框架

 

(7) 与 C++相似, Java 含有一系列“主类型”( Primitive type),以实现更有效率的访问。在 Java 中,这些类型包括 boolean, char, byte , short, int, long, float 以及 double。全部主类型的大小都是固有的,且与具体的机器无关(考虑到移植的问题)。这确定会对性能形成必定的影响,具体取决于不一样的机器。对类型的检查和要求在 Java 里变得更苛刻。例如:
■条件表达式只能是 boolean(布尔)类型,不可以使用整数。
■必须使用象 X+Y 这样的一个表达式的结果;不能仅仅用“ X+Y”来实现“反作用”。
分布式


(8) char(字符)类型使用国际通用的 16 位 Unicode 字符集,因此能自动表达大多数国家的字符。


(9) 静态引用的字串会自动转换成 String 对象。和 C 及 C++不一样,没有独立的静态字符数组字串可供使用。

 

(10) Java 增添了三个右移位运算符“ >>>”,具备与“逻辑”右移位运算符相似的功用,可在最末尾插入零值。“ >>”则会在移位的同时插入符号位(即“算术”移位)。


(11) 尽管表面上相似,但与 C++相比, Java 数组采用的是一个颇为不一样的结构,并具备独特的行为。有一个只读的 length 成员,经过它可知道数组有多大。并且一旦超过数组边界,运行期检查会自动丢弃一个异常。全部数组都是在内存“堆”里建立的,咱们可将一个数组分配给另外一个(只是简单地复制数组句柄)。数组标识符属于第一级对象,它的全部方法一般都适用于其余全部对象。


(12) 对于全部不属于主类型的对象,都只能经过 new 命令建立。和 C++不一样, Java 没有相应的命令能够“在堆栈上”建立不属于主类型的对象。全部主类型都只能在堆栈上建立,同时不使用new 命令。全部主要的类都有本身的“封装(器)”类,因此可以经过 new 建立等价的、之内存“堆”为基础的对象(主类型数组是一个例外:它们可象 C++那样经过集合初始化进行分配,或者使用 new)。


(13) Java 中没必要进行提早声明。若想在定义前使用一个类或方法,只需直接使用它便可—— 编译器会保证使用恰当的定义。因此和在 C++中不一样,咱们不会碰到任何涉及提早引用的问题。

 

(14) Java 没有预处理机。若想使用另外一个库里的类,只需使用import 命令,并指定库名便可。不存在相似于预处理机的宏。


(15) Java 用包代替了命名空间。因为将全部东西都置入一个类,并且因为采用了一种名为“封装”的机制,它能针对类名进行相似于命名空间分解的操做,因此命名的问题再也不进入咱们的考虑之列。数据包也会在单独一个库名下收集库的组件。咱们只需简单地“ import”(导入)一个包,剩下的工做会由编译器自动完成。


(16) 被定义成类成员的对象句柄会自动初始化成 null。对基本类数据成员的初始化在 Java 里获得了可靠的保障。若不明确地进行初始化,它们就会获得一个默认值(零或等价的值)。可对它们进行明确的初始化(显式初始化):要么在类内定义它们,要么在构建器中定义。采用的语法比C++的语法更容易理解,并且对于 static 和非 static 成员来讲都是固定不变的。咱们没必要从外部定义 static 成员的存储方式,这和 C++是不一样的。


(17) 在 Java 里,没有象 C 和 C++那样的指针。用 new 建立一个对象的时候,会得到一个引用。例如:

1 String s = new String("howdy");

然而, C++引用在建立时必须进行初始化,并且不可重定义到一个不一样的位置。但Java 引用并不必定局限于建立时的位置。它们可根据状况任意定义,这便消除了对指针的部分需求。在C 和 C++里大量采用指针的另外一个缘由是为了能指向任意一个内存位置(这同时会使它们变得不安全,也是Java 不提供这一支持的缘由)。指针一般被看做在基本变量数组中四处移动的一种有效手段。 Java 容许咱们以更安全的形式达到相同的目标。解决指针问题的终极方法是“固有方法”。将指针传递给方法时,一般不会带来太大的问题,由于此时没有全局函数,只有类。并且咱们可传递对对象的引用。 Java 语言最开始声称本身“彻底不采用指针!”但随着许多程序员都质问没有指针如何工做?因而后来又声明“采用受到限制的指针”。你们可自行判断它是否“真”的是一个指针。但无论在何种状况下,都不存在指针“算术”。


(18) Java 提供了与 C++相似的“构建器”( Constructor)。若是不本身定义一个,就会得到一个默认构建器。而若是定义了一个非默认的构建器,就不会为咱们自动定义默认构建器。这和C++是同样的。注意没有复制构建器,由于全部自变量都是按引用传递的。


(19) Java 中没有“破坏器”( Destructor)。变量不存在“做用域”的问题。一个对象的“存在时间”是由对象的存在时间决定的,并不是由垃圾收集器决定。有个 finalize()方法是每个类的成员,它在某种程度上相似于 C++的“破坏器”。但 finalize()是由垃圾收集器调用的,并且只负责释放“资源”(如打开的文件、套接字、端口、 URL 等等)。如需在一个特定的地点作某样事情,必须建立一个特殊的方法,并调用它,不能依赖 finalize()。而在另外一方面, C++中的全部对象都会(或者说“应该”)破坏,但并不是 Java 中的全部对象都会被看成“垃圾”收集掉。因为 Java 不支持破坏器的概念,因此在必要的时候,必须谨慎地建立一个清除方法。并且针对类内的基础类以及成员对象,须要明确调用全部清除方法。


(20) Java 具备方法“过载”机制,它的工做原理与 C++函数的过载几乎是彻底相同的。


(21) Java 不支持默认自变量。


(22) Java 中没有 goto 。它采起的无条件跳起色制是“ break 标签”或者“ continue 标准”,用于跳出当前的多重嵌套循环。


(23) Java 采用了一种单根式的分级结构,所以全部对象都是从根类 Object 统一继承的。而在 C++中,咱们可在任何地方启动一个新的继承树,因此最后每每看到包含了大量树的“一片森林”。在Java 中,咱们不管如何都只有一个分级结构。尽管这表面上看彷佛形成了限制,但因为咱们知道每一个对象确定至少有一个Object 接口,因此每每能得到更强大的能力。 C++目前彷佛是惟一没有强制单根结构的惟一一种 OO 语言。


(24) Java 没有模板或者参数化类型的其余形式。它提供了一系列集合: Vector(向量), Stack(堆栈)以及 Hashtable(散列表),用于容纳 Object 引用。利用这些集合,咱们的一系列要求可获得知足。但这些集合并不是是为实现象 C++“标准模板库”( STL)那样的快速调用而设计的。 Java 1.2 中的新集合显得更加完整,但仍不具有正宗模板那样的高效率使用手段。


(25) “垃圾收集”意味着在 Java 中出现内存漏洞的状况会少得多,但也并不是彻底不可能(若调用一个用于分配存储空间的固有方法,垃圾收集器就不能对其进行跟踪监视)。然而,内存漏洞和资源漏洞可能是因为编写不当的 finalize()形成的,或是因为在已分配的一个块尾释放一种资源形成的(“破坏器”在此时显得特别方便)。垃圾收集器是在 C++基础上的一种极大进步,使许多编程问题消弥于无形之中。但对少数几个垃圾收集器力有不逮的问题,它倒是不大适合的。但垃圾收集器的大量优势也使这一处缺点显得微不足道。


(26) Java 内建了对多线程的支持。利用一个特殊的 Thread 类,咱们可经过继承建立一个新线程(放弃了run()方法)。若将 synchronized(同步)关键字做为方法的一个类型限制符使用,相互排斥现象会在对象这一级发生。在任何给定的时间,只有一个线程能使用一个对象的synchronized 方法。在另外一方面,一个synchronized 方法进入之后,它首先会“锁定”对象,防止其余任何 synchronized 方法再使用那个对象。只有退出了这个方法,才会将对象“解锁”。在线程之间,咱们仍然要负责实现更复杂的同步机制,方法是建立本身的“监视器”类。递归的 synchronized 方法能够正常运做。若线程的优先等级相同,则时间的“分片”不能获得保证。

 

(27) 咱们不是象 C++那样控制声明代码块,而是将访问限定符( public, private 和 protected)置入每一个类成员的定义里。若未规定一个“显式”(明确的)限定符,就会默认为“友好的”( friendly )。这意味着同一个包里的其余元素也能够访问它(至关于它们都成为C++的“ friends” —— 朋友),但不可由包外的任何元素访问。类—— 以及类内的每一个方法—— 都有一个访问限定符,决定它是否能在文件的外部“可见”。 private 关键字一般不多在 Java 中使用,由于与排斥同一个包内其余类的访问相比,“友好的”访问一般更加有用。然而,在多线程的环境中,对 private 的恰当运用是很是重要的。 Java 的 protected 关键字意味着“ 可由继承者访问,亦可由包内其余元素访问”。注意 Java 没有与 C++的 protected 关键字等价的元素,后者意味着“只能由继承者访问”(之前可用“ private protected”实现这个目的,但这一对关键字的组合已被取消了)。


(28) 嵌套的类。在 C++中,对类进行嵌套有助于隐藏名称,并便于代码的组织(但 C++的“命名空间”已使名称的隐藏显得多余)。 Java 的“封装”或“打包”概念等价于 C++的命名空间,因此再也不是一个问题。Java 1.1 引入了“内部类”的概念,它秘密保持指向外部类的一个句柄—— 建立内部类对象的时候须要用到。这意味着内部类对象也许能访问外部类对象的成员,毋需任何条件—— 就好象那些成员直接隶属于内部类对象同样。这样便为回调问题提供了一个更优秀的方案—— C++是用指向成员的指针解决的。


(29) 因为存在前面介绍的那种内部类,因此 Java 里没有指向成员的指针。


(30) Java 不存在“嵌入”( inline)方法。 Java 编译器也许会自行决定嵌入一个方法,但咱们对此没有更多的控制权力。在 Java 中,可为一个方法使用 final 关键字,从而“建议”进行嵌入操做。然而,嵌入函数对于 C++的编译器来讲也只是一种建议。


(31) Java 中的继承具备与 C++相同的效果,但采用的语法不一样。 Java 用 extends 关键字标志从一个基础类的继承,并用 super 关键字指出准备在基础类中调用的方法,它与咱们当前所在的方法具备相同的名字(然而, Java 中的 super 关键字只容许咱们访问父类的方法—— 亦即分级结构的上一级)。经过在 C++中设定基础类的做用域,咱们可访问位于分级结构较深处的方法。亦可用super 关键字调用基础类构建器。正如早先指出的那样,全部类最终都会从 Object 里自动继承。和 C++不一样,不存在明确的构建器初始化列表。但编译器会强迫咱们在构建器主体的开头进行所有的基础类初始化,并且不容许咱们在主体的后面部分进行这一工做。经过组合运用自动初始化以及来自未初始化对象句柄的异常,成员的初始化可获得有效的保证。

1 public class Foo extends Bar {
2   public Foo(String msg) {
3     super(msg); // Calls base constructor
4   }
5   public baz(int i) { // Override
6     super.baz(i); // Calls base method
7   }
8 }

 

(32) Java 中的继承不会改变基础类成员的保护级别。咱们不能在 Java 中指定 public, private 或者protected 继承,这一点与 C++是相同的。此外,在衍生类中的优先方法不能减小对基础类方法的访问。例如,假设一个成员在基础类中属于 public,而咱们用另外一个方法代替了它,那么用于替换的方法也必须属于public(编译器会自动检查)。


(33) Java 提供了一个 interface 关键字,它的做用是建立抽象基础类的一个等价物。 在其中填充抽象方法,且没有数据成员。这样一来,对于仅仅设计成一个接口的东西,以及对于用 extends 关键字在现有功能基础上的扩展,二者之间便产生了一个明显的差别。不值得用 abstract 关键字产生一种相似的效果,由于咱们不能建立属于那个类的一个对象。一个 abstract (抽象)类可包含抽象方法(尽管并不要求在它里面包含什么东西),但它也能包含用于具体实现的代码。所以,它被限制成一个单一的继承。经过与接口联合使用,这一方案避免了对相似于 C++虚拟基础类那样的一些机制的须要。为建立可进行“例示”(即建立一个实例)的一个 interface(接口)的版本,需使用 implements 关键字。它的语法相似于继承的语法,以下所示:

1 public interface Face {
2   public void smile();
3 }
4 public class Baz extends Bar implements Face {
5   public void smile( ) {
6     System.out.println("a warm smile");
7   }
8 }

 

(34) Java 中没有 virtual 关键字,由于全部非 static 方法都确定会用到动态绑定。在 Java 中,程序员没必要自行决定是否使用动态绑定。 C++之因此采用了 virtual,是因为咱们对性能进行调整的时候,可经过将其省略,从而得到执行效率的少许提高(或者换句话说:“若是不用,就不必为它付出代价”)。 virtual常常会形成必定程度的混淆,并且得到使人不快的结果。 final 关键字为性能的调整规定了一些范围—— 它向编译器指出这种方法不能被取代,因此它的范围可能被静态约束(并且成为嵌入状态,因此使用C++非virtual 调用的等价方式)。这些优化工做是由编译器完成的。


(35) Java 不提供多重继承机制( MI),至少不象 C++那样作。与 protected 相似, MI 表面上是一个很不错的主意,但只有真正面对一个特定的设计问题时,才知道本身须要它。因为Java 使用的是“单根”分级结构,因此只有在极少的场合才须要用到 MI。 interface 关键字会帮助咱们自动完成多个接口的合并工做。


(36) 运行期的类型标识功能与 C++极为类似。例如,为得到与句柄 X 有关的信息,可以使用下述代码:

1 X.getClass().getName();

为进行一个“类型安全”的紧缩造型,可以使用:

1 derived d = (derived)base;

这与旧式风格的 C 造型是同样的。编译器会自动调用动态造型机制,不要求使用额外的语法。尽管它并不象C++的“ new casts”那样具备易于定位造型的优势,但 Java 会检查使用状况,并丢弃那些“异常”,因此它不会象 C++那样容许坏造型的存在。


(37) Java 采起了不一样的异常控制机制,由于此时已经不存在构建器。可添加一个finally 从句,强制执行特定的语句,以便进行必要的清除工做。 Java 中的全部异常都是从基础类 Throwable 里继承而来的,因此可确保咱们获得的是一个通用接口。

 1 public void f(Obj b) throws IOException {
 2   myresource mr = b.createResource();
 3   try {
 4     mr.UseResource();
 5   } catch (MyException e) {
 6     // handle my exception
 7   } catch (Throwable e) {
 8     // handle all other exceptions
 9   } finally {
10     mr.dispose(); // special cleanup
11   }
12 }

 

(38) Java 的异常规范比 C++的出色得多。丢弃一个错误的异常后,不是象 C++那样在运行期间调用一个函数, Java 异常规范是在编译期间检查并执行的。除此之外,被取代的方法必须遵照那一方法的基础类版本的异常规范:它们可丢弃指定的异常或者从那些异常衍生出来的其余异常。这样一来,咱们最终获得的是更为“健壮”的异常控制代码。


(39) Java 具备方法过载的能力,但不容许运算符过载。 String 类不能用+和+=运算符链接不一样的字串,并且String 表达式使用自动的类型转换,但那是一种特殊的内建状况。


(40) 经过事先的约定, C++中常常出现的 const 问题在 Java 里已获得了控制。咱们只能传递指向对象的句柄,本地副本永远不会为咱们自动生成。若但愿使用相似 C++按值传递那样的技术,可调用 clone(),生成自变量的一个本地副本(尽管 clone()的设计依然尚显粗糙)。根本不存在被自动调用的副本构建器。为建立一个编译期的常数值,可象下面这样编码:

1 static final int SIZE = 255
2 static final int BSIZE = 8 * SIZE

 

(41) 因为安全方面的缘由,“应用程序”的编程与“程序片”的编程之间存在着显著的差别。一个最明显的问题是程序片不容许咱们进行磁盘的写操做,由于这样作会形成从远程站点下载的、不明来历的程序可能胡乱改写咱们的磁盘。随着 Java 1.1 对数字签名技术的引用,这一状况已有所改观。根据数字签名,咱们可确切知道一个程序片的所有做者,并验证他们是否已得到受权。 Java 1.2 会进一步加强程序片的能力。


(42) 因为 Java 在某些场合可能显得限制太多,因此有时不肯用它执行象直接访问硬件这样的重要任务。Java 解决这个问题的方案是“固有方法”,容许咱们调用由其余语言写成的函数(目前只支持C 和 C++)。这样一来,咱们就确定可以解决与平台有关的问题(采用一种不可移植的形式,但那些代码随后会被隔离起来)。程序片不能调用固有方法,只有应用程序才能够。


(43) Java 提供对注释文档的内建支持,因此源码文件也能够包含它们本身的文档。经过一个单独的程序,这些文档信息能够提取出来,并从新格式化成 HTML。这无疑是文档管理及应用的极大进步。


(44) Java 包含了一些标准库, 用于完成特定的任务。 C++则依靠一些非标准的、由其余厂商提供的库。这些任务包括(或不久就要包括):
■连网
■数据库链接(经过 JDBC)
■多线程
■分布式对象(经过 RMI 和 CORBA)
■压缩
■商贸
因为这些库简单易用,并且很是标准,因此能极大加快应用程序的开发速度。


(45) Java 1.1 包含了 Java Beans 标准,后者可建立在可视编程环境中使用的组件。因为遵照一样的标准,因此可视组件可以在全部厂商的开发环境中使用。因为咱们并不依赖一家厂商的方案进行可视组件的设计,因此组件的选择余地会加大,并可提升组件的效能。除此以外, Java Beans 的设计很是简单,便于程序员理解;而那些由不一样的厂商开发的专用组件框架则要求进行更深刻的学习。


(46) 若访问 Java 句柄失败,就会丢弃一次异常。这种丢弃测试并不必定要正好在使用一个句柄以前进行。根据 Java 的设计规范,只是说异常必须以某种形式丢弃。许多C++运行期系统也能丢弃那些因为指针错误形成的异常。


(47) Java 一般显得更为健壮,为此采起的手段以下:
■对象句柄初始化成 null(一个关键字)
■句柄确定会获得检查,并在出错时丢弃异常
■全部数组访问都会获得检查,及时发现边界违例状况
■自动垃圾收集,防止出现内存漏洞
■明确、“傻瓜式”的异常控制机制
■为多线程提供了简单的语言支持
■对网络程序片进行字节码校验

 

可爱博主:AlanLee

博客地址:http://www.cnblogs.com/AlanLee

本文出自博客园,欢迎你们加入博客园。

相关文章
相关标签/搜索