这是很久以前我刚刚开始学Java时候做的笔记,当时分成四篇,搬过来就合在一起了。当时C++基础比较好,所以是站在C++的基础上理解Java。

重赏之下必有勇夫,这话说的,太有道理了。如果改成:“鄙赏之下必有贪夫”,就太符合我了!

  看到CSDN上公布的NetBeans插件大赛,看的本池蠢蠢欲动,贪念一上来,也顾不得那台嘎吱了七年的电脑能不能跑动NetBeans,就打算把这七天假放两天出来,好歹做个什么东西就有东西哦!两三本书,几张DVD光盘(可惜我那台电脑读不了……),这点鄙赏,正对我这个贪夫的口味儿。至于那些重赏,留给勇夫们吧!

  但是鄙赏也不是说拿就来的,还要学点Java才可以。于是在网上随便下了点Java方面的教材,比着学呗!今天晚上看了一些,那些书都是针对刚刚开始学Java的人的,从最最最简单最最最原始的高级开发语言的源头讲起,对我这样有了相当的其他语言开发经验的人,特别是C/C++的,未免烦琐,所以开了这篇文章,把我自己见到的Java与C++之间不一样的地方,一一列出。

似乎在Java中,类成员默认访问权限是Public

  但是在C++中,默认的是private的,只有struct的才是public的。这个,我仅仅是看到书上程序如此才有此一猜,也许那书错了呢。

在Java里,没有指针、对象之间没有赋值

  没指针这个,是确信无疑的了。记得以前看书,说C/C++好处之一就是比Pascal多了指针,后来才发现Pascal也有指针,而且指针是好是坏,还真难说。反正现在我在项目里,看到一个指针干掉一个指针,然后还要把写的人找来质询一遍、强调一遍。虽然这样做挺招人烦,但是指针更招我烦。

  可是对象之间的赋值,在C++中是调用了operator =函数,看书上说的,Java如果把两个对象用等号赋值,那么其效果和C++中定义和初始化一个引用一样。不同的是,这里没定义引用,而且被赋值的那个对象,还可以改成赋别的对象,还可以赋成null!这个太震惊了,一会儿得试试。

Java里,执行的起点是main函数,但是这个是类的静态成员函数

  果然是完全面向对象,连全局函数也没了。但是这个差别没什么关系,不影响编程。

finalize方法

  这个,是比C++多出来的,它应该是protected类型。我觉得,在讲解的时候,只要说了这个东西是做什么的就可以了,然后指明它没有一个确定的时间调用。把它和C++中的析构函数结合一起来讲,反而会混淆视听。

数组也是对象

  有一个Length方法,可以获得数组的长度。在C++里,似乎用模板可以,但是那个有点复杂。

final关键字

  相当于C++中的const,不过也不太一样。在定义变量的时候相当于是const,但是还可以阻止一个方法被重载,那么这时候就是virtual的反关键字了。还可以阻止一个类被继承,这个时候……

变态的String

  这个,和语法没关系。String仅仅是Java定义的一个类,但是我还是忍不住上来骂两句:干什么不让修改?!当初我坚决不学Java就是因为String不能修改。有了StringBuffer为什么还要用String?

extends和super

在Java中,使用extends表示继承一个类。但是从这个关键字的含义看来,似乎是在扩展一个类。与C++的不同在于,那么Java是否像C++一样有public、protected、private三种继承方式呢,还是只有public一种?

super关键字是为了让继承类能访问基类,可是如果我想访问基类的基类,该怎么用呢?

继续昨天的内容,看看从C ++到Java的学习过程中,会遇到那些不一样的地方。

  在C++中用的是名字空间(name space),但是使用上和Java的包还是不一样。包的关键字是package,声明包的时候,只需要在文件头加这么一句,就可以了,不像C++,还要用个大括号包起来。引入的时候,使用import关键字。

  还有个比较大的不同在与,Java要求语法元素与硬盘文件对应,每个类要有放在一个和自己同名的文件里面,每个包要有个对应的文件夹。关于这点,我觉得很好,组织的方便了些。

访问控制

  在昨天的内容里,有提到这方面的,今天终于看到了。原来在Java里,比C++多出来了一个默认级别,有Public - Protected - Default - Private,四个级别。

接口

  接口的作用在于给出了一个大家都需要遵守的规范。在C++中对应的语法元素是抽象类,但是我觉得接口的设计比抽象类要好。它明确的区分了需要遵守的规范和类型,感觉上接口的作用有一点点接近模板参数。

  接口的定义和使用于类很相似,也可以继承,也可以拥有成员变量。一个类需要实例化一个接口的时候,使用implement关键字,一个类也可以实例化多个接口,这样就实现了多重继承。这种对多重继承的处理,个人感觉比C++的处理方式好多了。

  今天就先到这里吧。后面还有很多语法元素,比如异常处理啊什么的,但是我想这些不会影响到本贪夫拿鄙赏,就先不理会。明天开始写点程序试一试,做个简单的窗口程序看看。

昨天完成了语法方面的比较,那今天就是实践的编程了。

  说实话,如果C++学得很好的话,写起来Java程序是相当的顺手,感觉就好象是在写C++一样。这点上,和学好了Delphi再去写C#程序还不一样,学好了Delphi再看C#,会觉得首先,这是门全新的语言,然后在逐渐的编程和学习的过程中发现,嘿,怎么和Delphi有那么多巧合呢?!比如事件响应代码里的Sender参数什么的,Delphi和C#是同一个架构师,整体上完全不同,细节上却很多一样的地方。但是先学了C++再学Java,那感觉就是一门相同的语言么,他们之间的区别,比从C到C++还小,大概好象是从C++到CXX,仅仅旋转45度而已了。

  写的第一个程序,相当相当简单,把NetBeans的一个实例程序打开,然后做了一点点修改:找到按钮的MouseClick事件,在那里面把一个Edit框设置成了”Cook’s String”而已。不过还是受了点折磨,首先NetBeans的快捷方式和Visual C++有类似的也有不一样的,和Delphi也有类似的有不一样的,偏偏这两个我都很熟悉,于是乎就完蛋了。最终不得不全用菜单操作,想想我的赛扬II-766/SDRAM-256M在Java环境里调试Java程序有多慢!还好当年俺是用赛扬I-466/SDRAM-32M在Delphi环境里调试过Delphi程序的,能受的了。其次,就是受不了的地方了,放假前两天,项目小组刚刚统一强调了,要用CString,不要用std::string。我可是std::string的忠实拥趸,每次使用字符串的时候,总是提醒自己要写CString,要写CString……结果今天在Java里面也写成了CString……,然后到处找String的包,用各种方式引入近来,直到过了很久才自己发现了这个错误。说实话,那Java报的错也相当没水平,说个未定义的符号就可以了呗,偏要咕哝玄虚(故弄)折腾我。

  不过也发现了NetBeans的一个很不方便的地方,我觉得是个Bug。同一个程序,如果你两次按F5,就会出现两个Java实例同时被一个NetBeans实例调试。在Visual C++和Delphi中,这种情况都是不会出现的,首先人家的启动和继续是同一个快捷键,其次人家就不允许你这么做。

  上面的故事告诉我:1、统一的操作方式很重要,要么自己独立规定一套很好的,要么适应别人已经很流行的一套,轻松汇编的新版本,大概需要考虑一下这方面的问题;2、不管我是哪方面怎么样的高手,到了新的领域,难免把以前的经验变成现在的教训。

  尝试的第二步,是把示例中的一个窗口搬过来,我找的是个查找窗口。然后直接放到工具里面,希望它能显示出来。本池的意思很明显,我的插件仅仅是增加查找的功能,你不能说我没做吧?然后骗两本书就可以了,要求不高。

  要求不高也没达到。根本不显示窗口。倒是在后来查找帮助文件,想看看JFrame的用法时候,发现了一点让人摸不着头脑的地方。Sun说它给Java提供了全部的API中文文档,让我挺感动的,就下载下来了。今天用的时候发现,娘的,这中文文档不说没英文的MSDN好用吧,连Delphi的英文帮助也比它好用!而且有些翻译工作做的也不好,比如这句:“提供启用可以与 Java 运行时环境一起使用的输入方法开发的接口。”猛一看说什么也不明白。找到对应的英文句子才明白,哦,原来从“启用”到“开发的”全是一个长长的定语啊!英文句子是:”Provides interfaces that enable the development of input methods that can be used with any Java runtime environment.”。这个翻译真的没错,但是它应该是带了英文习惯的中文句子。

  今天是搞不定了,我手头边上就有个Java高手,刚刚参加完了Java的培训。明天问问去!做出来查找窗口了,就把代码也放上来,将来俺拿鄙赏,就靠这个查找窗口呢!

到今天,终于能弹出来一个小窗口,还可以在窗口上放置控件了。做法也很简单,寥寥数行代码而已:

import java.awt.*;
import javax.swing.*;

JFrame frame = new JFrame();
frame.setSize(new Dimension(300, 200));
frame.setVisible(true);
frame.setTitle("Regular Expression Tester");

  前两行代码,是用来引入Java包的,要放在最前面。后面四行代码,是创建一个小窗口,要放在你想创建并且弹出小窗口的函数里。很简单,根据函数的名字,也能猜出来每句是做什么的。下面的四行代码,就是往创建的窗口上添加一个按钮而已,也很简单,根据所调用的函数的名字,就可以知道代码的含义。

javax.swing.JButton jBtnMatch = new javax.swing.JButton();
jBtnMatch.setText("Match 1");
frame.add(jBtnMatch);
jBtnMatch.setSize(new Dimension(100, 50));

疑问

  但是还有个问题,在Java中,看起来是只有指针,没有对象。不同的是,这里的指针,不需要释放,系统会替你管理的。我大略的看过一些介绍自动清理内存机制的文章,没认真的详细研究,仅仅是对自动清理内存的原理有个概念上的认识,让我来实现,还真实现不了。

  我的问题就是,为什么Java要这样做呢?自动清理内存的机制当然很好,相信它很有效,也很好用。但是无论如何,这在效率上是打了折扣的——折扣有多大不好说。在C++中,如果对类的设计中不使用new关键字,尽量使用引用而不用指针,同样也不存在内存管理的问题。当然这样对设计的要求比较高,可是如果做到这一点了的话,那么C++与Java相比,就没有内存管理这个缺陷,但是效率却高很多。当然,new的使用是不可避免的,但是我们可以在自己的代码里不使用,而是把这个东西推给std::vector这样久经考验的库函数或者库的类来代替,同样是不存在内存管理的问题。

  如果说Java没有采用自动清理内存的机制,而是取消了new,确保对象在退出作用域的时候(比如在退出自己所在大括号的时候)销毁,那么Java的效率会不会提高一些呢?当然,这样做的话Java就不如现在这么好用了,做设计和实现的时候会有点碍手碍脚的感觉。一来,我想虽然这样限制了我们的设计和实现,但是同样确保了安全性;二来,我也不过是提出这样一个就事论事的问题而已,Java当然是绝对不可能这样来改的。

  在C++中,如果根本不使用new,那么会避免很多错误。我在项目里已有尝试。如果C++中可以做到这一点,那么我觉得Java也可以不使用new和自动内存清理机制——当然Java没必要也不可能改了。在我印象里,Delphi似乎也和Java类似,创建起来的对象要先调用一个create()函数才可以用,Delphi中的对象,其实仅仅是引用(也就是指针了),而不是一个实际的占有内存的对象。只不过,Delphi中的对象,是要程序员调用Free()函数或者Destroy()函数来释放的。难道使用引用和指针来代替对象是个潮流?

原文来自我的教育网博客