从C++到Java
这是很久以前我刚刚开始学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的培训。明天问问去!做出来查找窗口了,就把代码也放上来,将来俺拿鄙赏,就靠这个查找窗口呢!
四
到今天,终于能弹出来一个小窗口,还可以在窗口上放置控件了。做法也很简单,寥寥数行代码而已:
前两行代码,是用来引入Java包的,要放在最前面。后面四行代码,是创建一个小窗口,要放在你想创建并且弹出小窗口的函数里。很简单,根据函数的名字,也能猜出来每句是做什么的。下面的四行代码,就是往创建的窗口上添加一个按钮而已,也很简单,根据所调用的函数的名字,就可以知道代码的含义。
疑问
但是还有个问题,在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()函数来释放的。难道使用引用和指针来代替对象是个潮流?
标签集合/Tag clouds
C++
Symbain
轻松汇编
算法
论文学习
资治通鉴
Delphi
编程之美
Poco
MFC
Linux
IFC
知乎
汇编
数据分析
交叉编译
poco
j2me
android
XML
Java
DTD
飞信
零宽断言
诺基亚
联系人
编程
真值表
池西木
正则表达式
多线程
命令行
优化
stream
configure
cmake
VIM
UiAutomator
TDD
Symbian
Sqlite
SourceInsight
Python
MPAndroidChart
Kotlin
Flutter
Dokka
Chatgpt