??xml version="1.0" encoding="utf-8" standalone="yes"?>
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS?br />
2. 你们的项目组使用~陷理pȝ?jin)么Q?br /> 应该用。ClearQuest太复杂,我的推荐是BugZilla?
3. 你们的测试组q在用Word写测试用例么Q
不要用Word写测试用例(Test CaseQ。应该用一个专门的pȝQ可以是Test ManagerQ也可以是自己开发一个ASP.NET的小|站。主要目的是Track和Browse?br />
4. 你们的项目组有没有徏立一个门L(fng)站?
要有一个门L(fng)站,用来放Contact Info、Baselined Schedule、News{等。推荐Sharepoint Portal Server 2003来实玎ͼ15分钟搞定。买不vSPS 2003可以用WSS (Windows Sharepoint Service)?
5. 你们的项目组用了(jin)你能买到最好的工具么?
应该用尽量好的工h工作。比如,应该用VS.NET而不是Notepad来写C(j)#。用Notepad写程序多半只是一U炫耀。但也要考虑到经费,所以说?你能买到最好的"?br />
6. 你们的程序员工作在安?rn)的环境里么Q
需要安?rn)环境。这Ҏ(gu)端重要,而且要保证每个h的空间大于一定面U?br />
7. 你们的员工每个h都有一部电(sh)话么Q?br />需要每Z部电(sh)话。而且?sh)话最好是带留a功能的。当?dng)上这么一套带留言?sh)话pȝ开销不小。不q至每Z部电(sh)话要有,千万别搞得经常有人站h喊:(x)"某某某电(sh)?。《h件》里面就强烈谴责q种做法?br />
8. 你们每个人都知道Z(jin)问题应该找谁么?
应该知道。Q何一个Feature臛_都应该有一个OwnerQ当?dng)Owner可以l箋Dispatchl其他h?
9. 你遇到过有h?我以为?么?
要消?我以?。Never assume anything?br />
10. 你们的项目组中所有的人都坐在一起么Q
需要。我反对Virtual TeamQ也反对Dev在美国、Test在中国这U开发方式。能坐在一起就最好坐在一P好处多得不得?jin)?br />
11. 你们的进度表是否反映最新开发进展情况?
应该反映。但是,应该用Baseline的方法来理q度表:(x)l护一份稳定的ScheduleQ再l护一份最新更攏VBaseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手Dc(din)?br />
12. 你们的工作量是先由每个h自己估算的么Q
应该让每个h自己估算。要从下而上估算工作量,而不是从上往下分z。除非有其他原因Q比如政MQ务工期固定等?br />
13. 你们的开发h员从目一开始就加班么?
不要q样。不要一开始就搞疲x。从目一开始就加班Q只能说明项目进度不合理。当?dng)一些对日Y件外包必d天加班,那属于剥削的范畴?br />
14. 你们的项目计划中Buffer Time是加在每个小d后面的么Q
不要。Buffer Time加在每个Q务后面,很容易轻易的p消耗掉。Buffer Time要整D늚加在一个Milestone或者checkpoint前面?br />
15. 值得再多׃些时_(d)?5%做到100%好值得Q非常值得。
其当项目后期h困马乏的时候,要坚持。这?x)给产品带来质的区别?br />
16. 登记新缺hQ是否写清了(jin)重现步骤Q?br /> 要。这属于Dev和Test之间的沟通手Dc(din)面寚w沟通需要,详细填写Repro Steps也需要?br />
17. 写新代码前会(x)把已知缺陯决么Q?br /> 要。每个h的缺陷不能超q?0个或15个,否则必须先解册的bug才能l箋写新代码?br />
18. 你们对缺L(fng)轻重~急有事先的约定么Q
必须有定义。Severity要分1??Q约定好Q蓝屏和Data LostSev 1QFunction ErrorSev 2Q界面上的算Sev 3。但q种U定可以Ҏ(gu)产品质量现状适当q行调整?br />
19. 你们Ҏ(gu)见不一的缺h三国?x)议么?br /> 必须要有。要有一个明的决策q程。这cM于CCB (Change Control Board)的概c(din)?br />
20. 所有的~陷都是q记的人最后关闭的么?
Bug应该由O(jin)pener关闭。Dev不能U自关闭Bug?br />
21. 你们的程序员厌恶修改老的代码么?
厌恶是正常的。解x法是l织Code ReviewQ单独留出时间来。XP也是一个方法?br />
22. 你们目l有Team Morale Activity么?
每个月都要搞一ơ,吃饭、唱歌、Outing、打球、开卡丁车等{,一定要有。不要剩q些钱?br />
23. 你们目l有自己的Logo么?
要有自己的Logo。至应该有自己的Codename?br />
24. 你们的员工有印有公司Logo的T-Shirt么?
要有。能增强归属感。当?dng)T-Shirt要做的好看一些,最好用80支的来做。别没穿几次q破烂烂的?
25. ȝ理至每月参加次目l会(x)议要的。
要让team member觉得高层xq个目?br />
26. 你们是给每个Dev开一个分支么Q
反对。Branch的管理以?qing)Merge的工作量太大Q而且Ҏ(gu)出错?br />
27. 有h长期不Check-In代码么?
不可以。对大部分项目来_(d)最多两三天应该Check-In?br />
28. 在Check-In代码旉填写注释?jin)么Q
要写的,臛_一两句话,比如"解决?jin)Bug No.225Q给bug~号Q?。如果往高处拔,q也做"配置审计"的一部分?br />
29. 有没有设定每天Check-In的最后期限?
要的Q要明确Check-In Deadline。否则会(x)Build Break?br />
30. 你们能把所有源码一下子~译成安装文件吗Q?
要的。这是每日编译(Daily BuildQ的基础。而且必须要能够做成自动的?br />
31. 你们的项目组做每日编译么Q
当然要做。有三样东西是Y仉?产品开发必备的Q?. bug management; 2. source control; 3. daily build?
32. 你们公司有没有积累一个项目风险列表?
要。Risk Inventory。否则,下个目开始的时候,又只能拍脑袋分析Risk?jin)?br />
33. 设计简单越好越单越好。
设计时候多一句话Q将来可能就带来无穷无尽的烦(ch)恹{应该从一开始就勇敢的砍。这叫scope management?
34. 量利用现有的品、技术、代码千万别什么东襉K自己Coding?br />BizTalk和Sharepoint是最好的例子Q有q两个作为基Q可以把L(fng)提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XMLQ而不是自己去Parse一个文本文Ӟ量用RegExpQ而不是自׃头操作字W串Q等{等{。这是"软g复用"的体现?br />
35. 你们?x)隔一D|间就停下来夯实代码么Q
要。最好一个月左右一ơ。传adq初Windowsl在Stevb的命令下停过一个月增强安全。BtwQ??q个字念"hang"Q第一声?
36. 你们的项目组每个人都写Daily Report么?
要写。五分钟够?jin),?0句话左右Q告诉自己小l的Z天我q了(jin)什么。一则ؓ(f)?jin)沟通,二则鞭策自己Q要是游手好闲一天,自己都会(x)不好意思写的)(j)?
37. 你们的项目经理会(x)发出Weekly Report么?
要。也是ؓ(f)?jin)沟通。内容包括目前进度,可能的风险,质量状况Q各U工作的q展{?br />
38. 你们目l是否至每周全体开?x)一ơ?
要。一定要开?x)。程序员讨厌开?x),但每个礼拜开?x)时间加h臛_应该?时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code?br />
39. 你们目l的?x)议、讨论都有记录么Q
?x)前发meeting request和agendaQ会(x)中有责主持和记录Q会(x)后有责发meeting minutesQ这都是effective meeting的要炏V而且Q每个会(x)议都要Ş成agreements和action items?br />
40. 其他部门知道你们目l在q什么么Q
要发一些Newsflashl整个大l织。Show your team's value。否则,当你坐在甉|里面Q其他部门的人问Q?你们在干?Q你回答"ABC目"的时候,别h全然不知Q那U感觉不太好?br />
41. 通过Emailq行所有正式沟?br />Email的好处是免得抵赖。但也要避免矫枉q正Q最好的Ҏ(gu)是先用电(sh)话和当面_(d)然后Email来确认?
42. 为项目组建立多个Mailing Group
如果在AD+Exchange里面Q就建Distribution List。比如,我会(x)建ABC Project Core TeamQABC Project Dev TeamQABC Project All TestersQABC Project Extended Team{等。这样发起Email来方便,而且能让该收到email的h都收到、不该收C被骚(d)扰?br />
43. 每个人都知道哪里可以扑ֈ全部的文档么Q
应该每个人都知道。这叫做知识理QKnowledge ManagementQ。最方便的就是把文档攑֜一个集中的File ShareQ更好的Ҏ(gu)是用Sharepoint?br />
44. 你做军_、做变化Ӟ告诉大家原因?jin)么Q
要告诉大家原因。Empower team member的手D之一是提供够的informationQ这是MSF一开的几个原则之一。的如此,tell me why是h之常情,tell me why?jin)才能有understanding。中国h做事喜欢搞限Ӟ限制信息Q似乎能够看到某一份文件的人就是有w䆾的h。大错特错。权威、权力,不在于是不是能access information/dataQ而在于是不是掌握资源?br />
45. Stay agile and expect change 要这栗
需求一定会(x)变的Q已l写好的代码一定会(x)被要求修改的。做好心(j)理准备,对change不要抗拒Q而是expect change?br />
46. 你们有没有专职的软g试人员Q
要有专职试。如果h手不够,可以peer testQ交换了(jin)试。千万别自己试自己的?br />
47. 你们的测试有一份ȝ计划来规定做什么和怎么做么Q?br /> q就是Test Plan。要不要做性能试Q要不要做Usability试Q什么时候开始测试性能Q测试通过的标准是什么?用什么手D,自动的还是手动的Q这些问题需要用Test Plan来回{?br />
48. 你是先写Test Case然后再测试的么?
应该如此。应该先设计再编E、先test case再测试。当?dng)事情是灵zȝ。我有时候在做第一遍测试的同时补上test case。至于先test case再开发,我不喜欢Q因Z?fn)惯Q太ȝ(ch)Q至于别人推荐,那试试看也无妨?br />
49. 你是否会(x)为各U输入组合创建测试用例?
不要Q不要搞边界条gl合。当?j)组合爆炸。有很多test case工具能够自动生成各种边界条g的组?-但要x楚,你是否有旉去运行那么多test case?
50. 你们的程序员能看到测试用例么Q
要。让Dev看到Test Case吧。我们都是ؓ(f)?jin)同一个目的走Ch的:(x)提高质量?
51. 你们是否随便抓一些h来做易用性测试?
要这么做。自q自己写的E序界面Q怎么看都是顺眼的。这叫做审美疲劳--臭的看久?jin)也׃臭?jin)Q不方便的永久了(jin)也就?fn)惯了(jin)?br />
52. 你对自动试的期望正么Q
别期望太高。依我看Q除?jin)性能试以外Q还是暂时先忘掉"自动试"吧,忘掉WinRunner和LoadRunner吧。对于国内的软g试的现状来_(d)只能"矫枉必须q正"?jin)?
53. 你们的性能试是等所有功能都开发完才做的么Q
不能q样。性能试不能被归到所谓的"pȝ试"阶段。早早Ҏ(gu)Q早L升天?br />
54. 你注意到试中的杀虫剂效应?jin)么Q
虫子有抗药性,Bug也有。发现的新Bug来少是正常的。这时候,最好大家交换一下测试的areaQ或者用用看其他工具和手法,又?x)发C些新bug?jin)?br />
55. 你们目l中有h能说Z品的当前整体质量情况么?
要有。当老板问vq个产品目前质量如何QTest Lead/Manager应该负责回答?br />
56. 你们有单元测试么Q
单元试要有的。不q没有单元测试也不是不可以,我做q没有单元测试的目Q也做成功了(jin)--可能是oq,可能是大安是熟手的关系。还是那句话QY件工E是非常实践、非常工E、非常灵zȝ一套方法,某些Ҏ(gu)在某些情况下?x)比另一些方法好Q反之亦然?
57. 你们的程序员是写完代码就扔过墙的么?
大忌。写好一块程序以后,即便不做单元试Q也应该自己先跑一跑。虽然有?jin)专门的试人员Q做开发的Z不可以一Ҏ(gu)试都不做。微软还有Test Release Document的说法,E序太烂的话Q测试有权踢回去?br />
58. 你们的程序中所有的函数都有输入(g)查么Q
不要。虽然说做输入检查是write secure code的要点,但不要做太多的输入检查,有些内部函数之间的参C递就不必(g)查输入了(jin)Q省点功夫。同L(fng)道理Q未必要l所有的函数都写注释。写一部分主要的就够了(jin)?br />
59. 产品有统一的错误处理机制和报错界面么?
要有。最好能有统一的error messageQ然后每个error message都带一个error number。这P用户可以自己Ҏ(gu)error number到user manual里面ȝ看错误的具体描述和可能原因,像SQL Server的错误那栗同PASP.NET也要有统一的Exception处理。可以参考有关的Application Block?br />
60. 你们有统一的代码书写规范么Q
要有。Code Convention很多Q搞一份来发给大家可以了(jin)。当?dng)要是有FxCopq种工具来检查代码就更好?jin)?br />
61. 你们的每个h都了(jin)解项目的商业意义么?
要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在Z国某某行业的信息化作先驱者,或者时不时的告诉team memberQ这个项目能够ؓ(f)某某某国安门每q节省多多百万的U税人的钱,q样有动力?jin)。^凡的事情也是可以有个崇高的目标的?br />
62. 产品各部分的界面和操作习(fn)惯一致么Q
要这栗要让用戯得整个程序好像是一个h写出来的那样?br />
63. 有可以作为宣传亮点的Cool Feature么?
要。这是增强团队凝聚力、信?j)的。而且Q?一俊遮百丑"Q有亮点可以掩盖一些问题。这P对于客户来说Q会(x)感觉产品从质量角度来说还是acceptable的。或者说Qcool feature或者说亮点可以作ؓ(f)质量问题的一个事后I补措施?br />
64. 可能羃短品的启动旉要这栗
软g启动旉QStart-Up timeQ是客户Ҏ(gu)能好坏的第一印象?br />
65. 不要q于注重内在品质而忽视了(jin)W一眼的外在印象E序员容易犯q个错误Q太看重性能、稳定性、存储效率,但忽视了(jin)外在感受。而高层经理、客h相反。这两方面要兼顾Q协调这些是PM的工作?br />
66. 你们Ҏ(gu)详细产品功能说明书做开发么Q
要这栗要有设计才能开发,q是必须的。设计文档,应该说清楚这个品会(x)怎么q行Q应该采取一些讲故事的方法。设计的时候千万别ȝ节,别钻到数据库、代码等具体实现里面去,那些是后面的事情Q一步步来不能着急?br />
67. 开始开发和试之前每个人都仔细审阅功能设计么?
要做。Function Spec review是用来统一思想的。而且Qreviewq以后Ş成了(jin)一致意见,来再也没有人可以说"你看Q当初我是反对q么设计的,现在吃苦头了(jin)?
68. 所有h都始l想着The Whole Image么?
要这栗项目里面每个h虽然都只是在刉一片叶子,但每个h都应该知道自己在刉的那片叶子所在的?wi)是怎么样子的。我反对软g蓝领Q反对过分的把Y件制造看成流水线、R间。参见第61条?br />
69. Dev工作的划分是单纯U向或横向的么?
不能单纯的根据功能模块分Q或者单U根据表现层、中间层、数据库层分。我推荐q么做:(x)首先Ҏ(gu)功能模块分,然后每个"?都有一个Owner来Review所有h的设计和代码Q保证consistency?br />
70. 你们的程序员写程序设计说明文档么Q
要。不q我听说微Y的程序员1999q以前也不写。所以说Q写不写也不是绝对的Q偷懒有时候也是可以的。参见第56条?br />
71. 你在招h面试时让他写一D늨序么Q
要的。我最喜欢让h做字W串和链表一cȝ题目。这U题目有很多循环、判断、指针、递归{,既不偏向q于考算法,也不偏向q于考特定的API?br />
72. 你们有没有技术交讲座?
要的。每一两个C拜搞一ơ内部的Tech Talk或者Chalk Talk吧。让l员之间分n技术心(j)得,q笔花钱送到外面d训划?
73. 你们的程序员都能专注于一件事情么Q
要让E序员专注一件事。例如说Q一个部门有两个目?0个hQ一U方法是?0个h同时参加两个目Q每个项目上每个人都?0%旉Q另一U方法是5个h去项目AQ?个h去项目BQ每个h?00%在某一个项目上。我一定选后面一U。这个道理很多h都懂Q但很多领导实践h把属下当成可以L拆分的资源了(jin)?br />
74. 你们的程序员?x)夸大完成某工作所需要的旉么?
?x)的Q这是常见的Q尤其会(x)在项目后期夸大做某个change所需要的旉Q以ơ来抵制change。解决的Ҏ(gu)是坐下来慢慢,掉E序员的逆反?j)理Q一起分析,q把估算旉的颗_度变小?br />
75. 量不要用Virtual Heads 最好不要用Virtual Heads。 Virtual heads意味着resource is not secureQshared resource?x)降低resource的工作效率,Ҏ(gu)增加出错的机?x),会(x)让一?j)二用的人没有太多时间去review spec、review design。一个dedicated的hQ要两个只能投入50%旉和精力的人。我是吃q亏的:(x)7个part time的testerQ发现的Bug和干的活Q加hq不如两个full-time的。参见第73条?3条是针对E序员的Q?5条是针对Resource Manager的?br />
C是Q!Q?
]]>
我们的目的是在eclipse中创Z个工E,把Sync4j主要的代码放q去Q能够编译通过Q哈哈其实这个没什么,只是有一些注意事:(x)
1.在eclipse中新Z个工E,通过模板“java project”创建;
2.在这个新的工E中Q新Z个“source folder”,通过文gpȝ导入Sync4j的源代码Qƈ把工E的源代码目录指向Sync4j/src/java子目录;
3.定义一个新的“external tool”生成ant build.xml fileQ?BR>4.在工E的“build path”中d所有需要的jar包到l(f)ib目录Q?BR>5.dant.jar和j2ee.jar包到l(f)ib中;
6.定义一个新的jreq且配置好assertQassertQ俗U断aQ是在JDK1.4引入的关键字Q用于判断值是否ؓ(f)真,当不为真Ӟ抛出异常,eclipse默认时assert是关闭的Q你需要在eclipse中的讄界面里的java->compiler里把assert打开Q?BR>7.~辑sync4j-build.properties文g从你的home目录Q?BR>
文g的内容可能这P(x)
sunj2eesdk-rootdir=c:/Sun/AppServer
jdom.jar=c:/jar/jdom.jar
junit.jar=c:/jar/junit.jar
cactus.home=c:/jar/jakarta-cactus
dbms=mysql
jdbc.classpath=c:/jar/mysql-connector-java-3.0.14-production-bin.jar
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/sync4j
jdbc.user=sync4j
jdbc.password=sync4j
server=jboss
server.jboss.deploy=c:/dev/jboss-3.0.8/server/default/deploy
最后你可以用ant~译q|到你的应用服务器上Q就可以q行手机QpdaQwindows mbile{移动设备的数据同步开发?/P>
在我们学?fn)Java的过E中,掌握其中的基本概念对我们的学?fn)无论是J2SE,J2EE,J2ME都是很重要的,J2SE是Java的基,所以有必要对其中的基本概念做以归纳,以便大家在以后的学习(fn)q程中更好的理解java的精?在此我ȝ?0条基本的概念.
Java概述:
目前Java主要应用于中间g的开?middleware)---处理客户Z服务器之间的通信技?早期的实践证?Java不适合pc应用E序的开?其发展逐渐变成在开发手持设?互联|信息站,?qing)R载计机的开?Java于其他语a所不同的是E序q行时提供了(jin)q_的独立?U许可以在windows,solaris,linux其他操作pȝ上用完全相同的代码.Java的语法与C++语法cM,C++/CE序员很Ҏ(gu)掌握,而且Java是完全的d的面向对象的,其中提出?jin)很好的GC(Garbage Collector)垃圾处理机制,防止内存溢出.
Java的白皮书为我们提Z(jin)Java语言的关键特?
(1)Easy:Java的语法比C++的相对简?另一个方面就是Java能软g在很的机器上运?基础解释其和cd的支持的大小Uؓ(f)40kb,增加基本的标准库和线E支持的内存需要增?25kb.
(2)分布?Java带有很强大的TCP/IP协议族的例程?Java应用E序能够通过URL来穿q网l来讉Kq程对象,׃servlet机制的出?使Java~程非常的高?现在许多的大的web server都支持servlet.
(3)OO:面向对象设计是把重点攑֜对象?qing)对象的接口上的一个编E技?光向对象和C++有很多不?在与多重l承的处理及(qing)Java的原cL?
(4)健壮Ҏ(gu)?Java采取?jin)一个安全指针模?能减重写内存和数据崩溃的可能型
(5)安全:Java用来设计|\和分布系l?q带来了(jin)新的安全问题,Java可以用来构徏防病毒和防攻ȝSystem.事实证明Java在防毒这一斚w做的比较?
(6)中立体系l构:Java~译其生成体pȝ构中立的目标文g格式可以在很多处理器上执?~译器生的指o(h)字节?Javabytecode)实现此特?此字节码可以在Q何机器上解释执行.
(7)可移植?Java中对基本数据l构cd的大和法都有严格的规定所以可UL性很?
(8)多线E?Java处理多线E的q程很简?Java把多U程实现交给底下操作pȝ或线E程序完?所以多U程是Java作ؓ(f)服务器端开发语a的流行原因之一
(9)Applet和servlet:能够在网上执行的程序叫Applet,需要支持Java的浏览器很多,而applet支持动态的|页,q是很多其他语言所不能做到?
基本概念:
1.OOP中惟一关系的是对象的接口是什?像计算机的销售商她不电(sh)源内部结构是怎样?他只关系能否l你提供?sh)就行?jin),也就是只要知道can or not而不是how and why.所有的E序是由一定的属性和行ؓ(f)对象l成?不同的对象的讉K通过函数调用来完?对象间所有的交流都是通过Ҏ(gu)调用,通过对封装对象数?很大限度上提高复用率.
2.OOP中最重要的思想是类,cL模板是蓝?从类中构造一个对?卛_Z(jin)q个cȝ一个实?instance)
3.装:是把数据和行ؓ(f)l合起在一个包?q对对象使用者隐藏数据的实现q程,一个对象中的数据叫他的实例字段(instance field)
4.通过扩展一个类来获得一个新cdl承(inheritance),而所有的c都是由O(jin)bject根超cL展而得,根超cM文会(x)做介l?
5.对象?个主要特?
behavior---说明q个对象能做什?
state---当对象施加方法时对象的反?
identity---与其他相D为对象的区分标志.
每个对象有惟一的indentity 而这3者之间相互媄(jing)?
6.cM间的关系:
use-a :依赖关系
has-a :聚合关系
is-a :l承关系--?Acȝ承了(jin)Bc?此时AcM仅有?jin)BcȝҎ(gu),q有其自qҎ(gu).(个性存在于共性中)
7.构造对象用构造器:构造器的提?构造器是一U特D的Ҏ(gu),构造对象ƈ对其初始?
?Datacȝ构造器叫Data
new Data()---构造一个新对象,且初始化当前旉.
Data happyday=new Data()---把一个对象赋值给一个变量happyday,从而该对象能够多ơ?此处要声明的使变量与对象变量二者是不同?newq回的值是一个引?
构造器特点:构造器可以??一个或多个参数构造器和类有相同的名字一个类可以有多个构造器Q构造器没有q回|构造器L和newq算W一起?
8.重蝲:当多个方法具有相同的名字而含有不同的参数?便发生重?~译器必L选出调用哪个Ҏ(gu).
9.?package)Java允许把一个或多个cL集在一hZl?UC?以便于组lQ?标准Java库分多包.java.lang java.util java,net{?包是分层ơ的所有的java包都在java和javax包层ơ内.
10.l承思想:允许在已l存在的cȝ基础上构建新的类,当你l承一个已l存在的cL,那么你就复用?jin)这个类的方法和字?同时你可以在新类中添加新的方法和字段.
11.扩展c?扩展cd分体C(jin)is-a的承关p? 形式?class (子类) extends (基类).
12.多?在java?对象变量是多态的.而java中不支持多重l承.
13.动态绑?调用对象Ҏ(gu)的机?
(1)~译器检查对象声明的cd和方法名.
(2)~译器检查方法调用的参数cd.
(3)?rn)态绑?若方法类型ؓ(f)priavte static final ~译器会(x)准确知道该调用哪个方?
(4)当程序运行ƈ且用动态绑定来调用一个方法时,那么虚拟机必调用x所指向的对象的实际cd相匹配的Ҏ(gu)版本.
(5)动态绑?是很重要的特?它能使程序变得可扩展而不需要重~译已存代码.
14.finalc?为防止他Z你的cMz新类,此类是不可扩展的.
15.动态调用比?rn)态调用花费的旉要长,
16.抽象c?规定一个或多个抽象Ҏ(gu)的类本n必须定义为abstract
? public abstract string getDescripition
17.Java中的每一个类都是从ObjectcL展而来?
18.objectcM的equal和toStringҎ(gu).equal用于试一个对象是否同另一个对象相{?toStringq回一个代表该对象的字W串,几乎每一个类都会(x)重蝲该方?以便q回当前状态的正确表示.(toString Ҏ(gu)是一个很重要的方?
19.通用~程:Mcȝ型的所有值都可以同objectcL的变量来代?
20.数组列表:ArrayList动态数l列?是一个类?定义在java.uitl包中,可自动调节数l的大小.
21.classc?objectcM的getClassҎ(gu)q回classcd的一个实?E序启动时包含在mainҎ(gu)的类?x)被加?虚拟加蝲他需要的所有类,每一个加载的c都要加载它需要的c?
22.classcMؓ(f)~写可动态操Ujava代码的程序提供了(jin)强大的功?反射,q项功能为JavaBeans特别有用,使用反射Java能支持VBE序员习(fn)惯用的工具.
能够分析c能力的E序叫反器,Java中提供此功能的包叫Java.lang.reflect反射机制十分强大.
1.在运行时分析cȝ能力.
2.在运行时探察cȝ对象.
3.实现通用数组操纵代码.
4.提供Ҏ(gu)对象.
而此机制主要针对是工兯(g)而不是应用及(qing)E序.
反射机制中的最重要的部分是允许你检查类的结?用到的API?
java.lang.reflect.Field q回字段.
java.reflect.Method q回Ҏ(gu).
java.lang.reflect.Constructor q回参数.
Ҏ(gu)指针:java没有Ҏ(gu)指针,把一个方法的地址传给另一个方?可以在后面调用它,而接口是更好的解x?
23.接口(Interface)说明c该做什么而不指定如何d,一个类可以实现一个或多个interface.
24.接口不是一个类,而是对符合接口要求的cȝ一套规?
若实C个接口需?个步?
1.声明c需要实现的指定接口.
2.提供接口中的所有方法的定义.
声明一个类实现一个接口需要用implements 关键?BR>class actionB implements Comparable 其actionb需要提供CompareToҎ(gu),接口不是c?不能用new实例化一个接?
25.一个类只有一个超c?但一个类能实现多个接?Java中的一个重要接口Cloneable
26.接口和回?~程一个常用的模式是回调模?在这U模式中你可以指定当一个特定时间发生时回调对象上的Ҏ(gu).
?ActionListener 接口监听.
cM的API?java.swing.JOptionPane
java.swing.Timer
java.awt.Tookit
27.对象clone:cloneҎ(gu)是object一个保护方?q意味着你的代码不能单的调用?
28.内部c?一个内部类的定义是定义在另一个类的内部,原因?1.一个内部类的对象能够访问创建它的对象的实现,包括U有数据
2.对于同一个包中的其他cL?内部c能够隐藏v?
3.匿名内部cd以很方便的定义回?
4.使用内部cd以非常方便的~写事g驱动E序.
29.代理c?proxy):1.指定接口要求所有代?BR>2.objectcd义的所有的Ҏ(gu)(toString equals)
30.数据cd:Java是强调类型的语言,每个变量都必dx它都cd,java中d?个基本类?4U是整型,2U是点?一U是字符?被用于Unicode~码中的字符,布尔?QT111Q?
★文件流
文g操作是最单最直接也是最Ҏ(gu)惛_的一U方式,我们说的文g操作不仅仅是通过FileInputStream/FileOutputStreamq么“裸”的方式直接把数据写入到本地文gQ像我以前写的一个扫L(fng)游戏JavaMine是q样保存一局的状态的Q,q样比较“底层”了(jin)?
主要cMҎ(gu)和描q?
FileInputStream.read() //从本地文件读取二q制格式的数?nbsp;
FileReader.read() //从本地文件读取字W(文本Q数?nbsp;
FileOutputStream.write() //保存二进制数据到本地文g
FileWriter.write() //保存字符数据到本地文?
★XML
和上面的单纯的I/O方式相比QXML显得“高档”得多,以至于成ZU数据交换的标准。以DOM方式ZQ它兛_(j)的是首先在内存中构造文档树(wi)Q数据保存在某个l点上(可以是叶子结点,也可以是标签l点的属性)(j)Q构造好?jin)以后一ơ性的写入到外部文Ӟ但我们只需要知道文件的位置Qƈ不知道I/O是怎么操作的,XML操作方式可能多数Z实践q,所以这里也只列出相关的Ҏ(gu)Q供初学者预先了(jin)解一下。主要的包是javax.xml.parsersQorg.w3c.domQjavax.xml.transform?
主要cMҎ(gu)和描q?
DocumentBuilderFactory.newDocumentBuilder().parse() //解析一个外部的XML文gQ得C个Document对象的DOM?nbsp;
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() //初始化一DOM?nbsp;
Document.getDocumentElement().appendChild() //Z个标{Ҏ(gu)加一个子l点
Document.createTextNode() //生成一个字W串l点
Node.getChildNodes() //取得某个l点的所有下一层子l点
Node.removeChild() //删除某个l点的子l点
Document.getElementsByTagName() 查找所有指定名U的标签l点
Document.getElementById() //查找指定名称的一个标{点,如果有多个符合,则返回某一个,通常是第一?nbsp;
Element.getAttribute() //取得一个标{某个属性的的?nbsp;
Element.setAttribute() //讄一个标{某个属性的的?nbsp;
Element.removeAttribute() //删除一个标{某个属?nbsp;
TransformerFactory.newInstance().newTransformer().transform() //一DOM?wi)写入到外部XML文g
★序列化
使用基本的文件读写方式存取数据,如果我们仅仅保存相同cd的数据,则可以用同一U格式保存,譬如在我的JavaMine中保存一个盘局Ӟ需要保存每一个方格的坐标、是否有地雷Q是否被d{,q些信息l合成一个“复合类型”;相反Q如果有多种不同cd的数据,那我们要么把它分解成若干部分Q以相同cdQ譬如StringQ保存,要么我们需要在E序中添加解析不同类型数据格式的逻辑Q这很不方ѝ于是我们期望用一U比较“高”的层次上处理数据,E序员应该花可能少的时间和代码Ҏ(gu)据进行解析,事实上,序列化操作ؓ(f)我们提供?jin)这样一条途径?BR> 序列化(SerializationQ大家可能都有所接触Q它可以把对象以某种特定的编码格式写入或从外部字节流Q即ObjectInputStream/ObjectOutputStreamQ中d。序列化一个对象非怹单,仅仅实现一下Serializable接口卛_Q甚至都不用为它专门dMҎ(gu)Q?
public class MySerial implements java.io.Serializable
{
//...
}
但有一个条Ӟ(x)即你要序列化的类当中Q它的每个属性都必须是是“可序列化”的。这句话说v来有Ҏ(gu)口,其实所有基本类型(是intQcharQboolean之类的)(j)都是“可序列化”的Q而你可以看看JDK文档Q会(x)发现很多cd实已l实C(jin)SerializableQ即已经是“可序列化”的?jin)?j)Q于是这些类的对象以?qing)基本数据类型都可以直接作?f)你需要序列化的那个类的内部属性。如果碰C(jin)不是“可序列化”的属性怎么办?对不P那这个属性的c还需要事先实现Serializable接口Q如此递归Q直到所有属性都是“可序列化”的?
主要cMҎ(gu)和描q?
ObjectOutputStream.writeObject() //一个对象序列化到外部字节流
ObjectInputStream.readObject() //从外部字节流dq新构造对?
从实际应用上看来Q“Serializable”这个接口ƈ没有定义MҎ(gu)Q仿?jng)它只是一个标讎ͼ或者说像是Java的关键字Q而已Q一旦虚拟机看到q个“标记”,׃(x)试调用自n预定义的序列化机Ӟ除非你在实现Serializable接口的同时还定义?jin)私有的readObject()或writeObject()Ҏ(gu)。这一点很奇怪。不q你要是不愿意让pȝ使用~省的方式进行序列化Q那必d义上面提到的两个Ҏ(gu)Q?
public class MySerial implements java.io.Serializable
{
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
//...
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
//...
}
//...
}
譬如你可以在上面的writeObject()里调用默认的序列化方法ObjectOutputStream.defaultWriteObject();譬如你不愿意某些敏感的属性和信息序列化,你也可以调用ObjectOutputStream.writeObject()Ҏ(gu)明确指定需要序列化那些属性。关于用户可定制的序列化Ҏ(gu)Q我们将在后面提到?
★Bean
上面的序列化只是一U基本应用,你把一个对象序列化到外部文件以后,用notepad打开那个文gQ只能从为数不多的一些可dW中猜到q是有关q个cȝ信息文gQ这需要你熟?zhn)序列化文件的字节~码方式Q那是比较痛苦的(在《Core Java 2》第一卷里提到?jin)相关编码方式,有兴的话可以查看参考资料)(j)Q某些情况下我们可能需要被序列化的文gh更好的可L。另一斚wQ作为Javalg的核?j)概念“JavaBeans”,从JDK 1.4开始,其规范里也要求支持文本方式的“长期的持久化”(long-term persistenceQ?BR> 打开JDK文档Qjava.beans包里的有一个名为“Encoder”的c,q就是一个可以序列化bean的实用类。和它相关的两个主要cLXMLEcoder和XMLDecoderQ显?dng)q是以XML文g的格式保存和dbean的工兗他们的用法也很单,和上面ObjectOutputStream/ObjectInputStream比较cM?
主要cMҎ(gu)和描q?
XMLEncoder.writeObject() //一个对象序列化到外部字节流
XMLDecoder.readObject() //从外部字节流dq新构造对?nbsp;
如果一个bean是如下格式:(x)
public class MyBean
{
int i;
char[] c;
String s;
//...(get和set操作省略)...
}
那么通过XMLEcoder序列化出来的XML文ghq样的Ş式:(x)
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0" class="java.beans.XMLDecoder">
<object class="MyBean">
<void property="i">
<int>1</int>
</void>
<void property="c">
<array class="char" length="3">
<void index="0">
<int>a</int>
</void>
<void index="1">
<int>b</int>
</void>
<void index="2">
<int>c</int>
</void>
</array>
</void>
<void property="s">
<string>fox jump!</string>
</void>
</object>
</java>
像AWT和Swing中很多可视化lg都是beanQ当然也是可以用q种方式序列化的Q下面就是从JDK文档中摘录的一个JFrame序列化以后的XML文gQ?
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.0" class="java.beans.XMLDecoder">
<object class="javax.swing.JFrame">
<void property="name">
<string>frame1</string>
</void>
<void property="bounds">
<object class="java.awt.Rectangle">
<int>0</int>
<int>0</int>
<int>200</int>
<int>200</int>
</object>
</void>
<void property="contentPane">
<void method="add">
<object class="javax.swing.JButton">
<void property="label">
<string>Hello</string>
</void>
</object>
</void>
</void>
<void property="visible">
<boolean>true</boolean>
</void>
</object>
</java>
因此但你惌保存的数据是一些不是太复杂的类型的话,把它做成bean再序列化也不׃ؓ(f)一U方便的选择?
★Properties
在以前我ȝ的一关于集合框架的文章里提到q,Properties是历史集合类的一个典型的例子Q这里主要不是介l它的集合特性。大家可能都l常接触一些配|文Ӟ如Windows的ini文gQApache的conf文gQ还有Java里的properties文g{,q些文g当中的数据以“关键字-值”对的方式保存。“环境变量”这个概念都知道吧,它也是一U“key-value”对Q以前也常常看到版上问“如何取得系l某某信息”之cȝ问题Q其实很多都保存在环境变量里Q只要用一?/P>
System.getProperties().list(System.out);
p获得全部环境变量的列表:(x)
-- listing properties --
java.runtime.name=Java(TM) 2 Runtime Environment, Stand...
sun.boot.library.path=C:\Program Files\Java\j2re1.4.2_05\bin
java.vm.version=1.4.2_05-b04
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=CN
sun.os.patch.level=Service Pack 1
java.vm.specification.name=Java Virtual Machine Specification
user.dir=d:\my documents\目\eclipse\SWTDemo
java.runtime.version=1.4.2_05-b04
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Program Files\Java\j2re1.4.2_05\li...
os.arch=x86
java.io.tmpdir=C:\DOCUME~1\cn2lx0q0\LOCALS~1\Temp\
line.separator=
java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows XP
sun.java2d.fontpath=
java.library.path=C:\Program Files\Java\j2re1.4.2_05\bi...
java.specification.name=Java Platform API Specification
java.class.version=48.0
java.util.prefs.PreferencesFactory=java.util.prefs.WindowsPreferencesFac...
os.version=5.1
user.home=D:\Users\cn2lx0q0
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=GBK
java.specification.version=1.4
user.name=cn2lx0q0
java.class.path=d:\my documents\目\eclipse\SWTDemo\bi...
java.vm.specification.version=1.0
sun.arch.data.model=32
java.home=C:\Program Files\Java\j2re1.4.2_05
java.specification.vendor=Sun Microsystems Inc.
user.language=zh
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.4.2_05
java.ext.dirs=C:\Program Files\Java\j2re1.4.2_05\li...
sun.boot.class.path=C:\Program Files\Java\j2re1.4.2_05\li...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.isalist=pentium i486 i386
主要cMҎ(gu)和描q?
load() //从一个外部流d属?nbsp;
store() //属性保存到外部(特别是文Ӟ(j)
getProperty() //取得一个指定的属?nbsp;
setProperty() //讄一个指定的属?nbsp;
list() //列出q个Properties对象包含的全部“key-value”对
System.getProperties() //取得pȝ当前的环境变?nbsp;
你可以这样保存一个properties文gQ?
Properties prop = new Properties();
prop.setProperty("key1", "value1");
...
FileOutputStream out = new FileOutputStream("config.properties");
prop.store(out, "--q里是文件头Q可以加入注?-");
★Preferences
如果我说Java里面可以不用JNI的手D|作Windows的注册表你信不信Q很多Y件的菜单里都有“Setting”或“Preferences”这L(fng)选项用来讑֮或修改Y件的配置Q这些配|信息可以保存到一个像上面所q的配置文g当中Q如果是Windowsq_下,也可能会(x)保存到系l注册表中。从JDK 1.4开始,Java在java.util下加入了(jin)一个专门处理用户和pȝ配置信息的java.util.prefs包,其中一个类Preferences是一U比较“高U”的玩意。从本质上讲QPreferences本n是一个与q_无关的东西,但不同的OS对它的SPIQService Provider InterfaceQ的实现却是与^台相关的Q因此,在不同的pȝ中你可能看到首选项保存为本地文件、LDAP目录V数据库条目{,像在Windowsq_下,它就保存C(jin)pȝ注册表中。不仅如此,你还可以把首选项导出为XML文g或从XML文g导入?
主要cMҎ(gu)和描q?
systemNodeForPackage() //Ҏ(gu)指定的Class对象得到一个Preferences对象Q这个对象的注册表\径是从“HKEY_LOCAL_MACHINE\”开始的
systemRoot() //得到以注册表路径HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs 为根l点的Preferences对象
userNodeForPackage() //Ҏ(gu)指定的Class对象得到一个Preferences对象Q这个对象的注册表\径是从“HKEY_CURRENT_USER\”开始的
userRoot() //得到以注册表路径HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs 为根l点的Preferences对象
putXXX() //讄一个属性的|q里XXX可以为基本数值型cdQ如int、long{,但首字母大写Q表C参Cؓ(f)相应的类型,也可以不写而直接用putQ参数则为字W串
getXXX() //得到一个属性的?nbsp;
exportNode() //全部首选项导出Z个XML文g
exportSubtree() //部分首选项导出Z个XML文g
importPreferences() //从XML文g导入首选项
你可以按如下步骤保存数据Q?/P>
Preferences myPrefs1 = Preferences.userNodeForPackage(this);// q种Ҏ(gu)是在“HKEY_CURRENT_USER\”下按当前类的\径徏立一个注册表?
Preferences myPrefs2 = Preferences.systemNodeForPackage(this);// q种Ҏ(gu)是在“HKEY_LOCAL_MACHINE\”下按当前类的\径徏立一个注册表?
Preferences myPrefs3 = Preferences.userRoot().node("com.jungleford.demo");// q种Ҏ(gu)是在“HKEY_CURRENT_USER\SOFTWARE\Javasoft\Prefs\”下按“com\jungleford\demo”的路径建立一个注册表?
Preferences myPrefs4 = Preferences.systemRoot().node("com.jungleford.demo");// q种Ҏ(gu)是在“HKEY_LOCAL_MACHINE\SOFTWARE\Javasoft\Prefs\”下按“com\jungleford\demo”的路径建立一个注册表?
myPrefs1.putInt("key1", 10);
myPrefs1.putDouble("key2", -7.15);
myPrefs1.put("key3", "value3");
FileOutputStream out = new FileOutputStream("prefs.xml");
myPrefs1.exportNode(out);
|络I/OQSocket→RMI
★Socket
Socket~程可能大家都很熟,所以就不多讨论?jin),只是说通过socket把数据保存到q端服务器或从网lsocketd数据也不׃ؓ(f)一U值得考虑的方式?/P>
★RMI
RMI机制其实是RPCQ远E过E调用)(j)的Java版本Q它使用socket作ؓ(f)基本传输手段Q同时也是序列化最重要的一个应用。现在网l传输从~程的角度来看基本上都是以流的方式操作,socket是一个例子,对象{换成字节的一个重要目标就是ؓ(f)?jin)方便网l传输?BR> 惌一下传l的单机环境下的E序设计Q对于Java语言的函敎ͼҎ(gu)Q调用(注意与C语言函数调用的区别)(j)的参C递,?x)有两种情况Q如果是基本数据cdQ这U情况下和C语言是一L(fng)Q采用g递方式;如果是对象,则传递的是对象的引用Q包括返回g是引用,而不是一个完整的对象拯Q试想一下在不同的虚拟机之间q行Ҏ(gu)调用Q即使是两个完全同名同类型的对象他们也很可能是不同的引用Q此外对于方法调用过E,׃被调用过E的压栈Q内存“现场”完全被被调用者占有,当被调用Ҏ(gu)q回Ӟ才将调用者的地址写回到程序计数器QPCQ,恢复调用者的状态,如果是两个虚拟机Q根本不可能用简单压栈的方式来保存调用者的状态。因为种U原因,我们才需要徏立RMI通信实体之间的“代理”对象,譬如“存根”就相当于远E服务器对象在客h上的代理Qstub是q么来的Q当然这是后话了(jin)?BR> 本地对象与远E对象(未必是物理位|上的不同机器,只要不是在同一个虚拟机内皆为“远E”)(j)之间传递参数和q回|可能有这么几U情形:(x)
g递:(x)q又包括两种子情形:(x)如果是基本数据类型,那么都是“可序列化”的Q统l序列化成可传输的字节流Q如果是对象Q而且不是“远E对象”(所谓“远E对象”是实现?jin)java.rmi.Remote接口的对象)(j)Q本来对象传递的应该是引用,但由于上q原因,引用是不以证明对象w䆾的,所以传递的仍然是一个序列化的拷贝(当然q个对象也必L上q“可序列化”的条gQ?
引用传递:(x)可以引用传递的只能是“远E对象”。这里所谓的“引用”不要理解成?jin)真的只是一个符P它其实是一个留在(客户机)(j)本地stub中的Q和q端服务器上那个真实的对象张得一模一L(fng)镜像而已Q只是因为它有点“特权”(不需要经q序列化Q,在本地内存里已经有了(jin)一个实例,真正引用的其实是q个“孪生子”?BR>
由此可见Q序列化在RMI当中占有多么重要的地位?/P>
数据库I/OQCMP、Hibernate
★什么是“Persistence?BR> 用过VMWare的朋友大概都知道当一个guest OS正在q行的时候点几ZSuspend”将虚拟OS挂vQ它?x)把整个虚拟内存的内容保存到盘上,譬如你?f)虚拟OS分配?28M的运行内存,那挂起以后你?x)在虚拟OS所在的目录下找C个同h128M的文Ӟq就是虚拟OS内存的完整镜像!q种内存的镜像手D其实就是“Persistence”(持久化)(j)概念的由来?/P>
★CMP和Hibernate
因ؓ(f)我对J2EE的东西不是太熟?zhn)Q随便找?jin)点材料看看Q所以担?j)说的不CQ这ơ就不作具体ȝ?jin),学?fn)……真是一件痛苦的事情
序列化再探讨
从以上技术的讨论中我们不难体?x)到Q序列化是Java之所以能够出色地实现光吹的两大卖点??分布式(distributedQ和跨^収ͼOS independentQ的一个重要基。TIJQ即“Thinking in Java”)(j)谈到I/OpȝӞ把序列化UCؓ(f)“lightweight persistence??“轻量的持久化”,q确实很有意思?/P>
★ؓ(f)什么叫做“序列”化Q?BR> 开场白里我说更?fn)惯于把“Serialization”称为“序列化”而不是“串行化”,q是有原因的。介l这个原因之前先回顾一些计机基本的知识,我们知道C计算机的内存I间都是U性编址的(什么是“线性”知道吧Q就是一个元素只有一个唯一的“前驱”和唯一的“后l”,当然头尾元素是个例外Q对于地址来说Q它的下一个地址当然不可能有两个Q否则就乱套?jin)?j)Q“地址”这个概忉|q到数据l构Q就相当于“指针”,q个在本U低q大概q道了(jin)。注意了(jin)Q既然是U性的Q那“地址”就可以看作是内存空间的“序号”,说明它的l织是有序的,“序号”或者说“序列号”正是“Serialization”机制的一U体现。ؓ(f)什么这么说呢?譬如我们有两个对象a和b,分别是类A和B的实例,它们都是可序列化的,而A和B都有一个类型ؓ(f)C的属性,Ҏ(gu)前面我们说过的原则,C当然也必L可序列化的?/P>
import java.io.*;
...
class A implements Serializable
{
C c;
...
}
class B implements Serializable
{
C c;
...
}
class C implements Serializable
{
...
}
A a;
B b;
C c1;
...
注意Q这里我们在实例化a和b的时候,有意让他们的c属性用同一个Ccd对象的引用,譬如c1Q那么请试想一下,但我们序列化a和b的时候,它们的c属性在外部字节(当然可以不仅仅是文gQ里保存的是一份拷贝还是两份拷贝呢Q序列化在这里用的是一U类g“指针”的Ҏ(gu)Q它为每个被序列化的对象标上一个“序列号”(serial numberQ,但序列化一个对象的时候,如果其某个属性对象是已经被序列化的,那么q里只向输出写入该属性的序列P从字节流恢复被序列化的对象时Q也Ҏ(gu)序列h到对应的来恢复。这是“序列化”名U的由来Q这里我们看到“序列化”和“指针”是极相似的Q只不过“指针”是内存I间的地址链,而序列化用的是外部流中的“序列号䏀?BR> 使用“序列号”而不是内存地址来标识一个被序列化的对象Q是因ؓ(f)从流中恢复对象到内存Q其地址可能未必是原来的地址??我们需要的只是q些对象之间的引用关p,而不是死板的原始位置Q这在RMI中就更是必要Q在两台不同的机器之间传递对象()(j)Q根本就不可能指望它们在两台机器上都h相同的内存地址?
★更灉|的“序列化”:(x)transient属性和Externalizable
Serializable实很方便,方便C几乎不需要做M额外的工作就可以L内存中的对象保存到外部。但有两个问题得Serializable的威力收到束~:(x)
一个是效率问题Q《Core Java 2》中指出QSerializable使用pȝ默认的序列化机制?x)?jing)响Y件的q行速度Q因为需要ؓ(f)每个属性的引用~号和查P再加上I/O操作的时_(d)I/O和内存读写差的可是一个数量的大)(j)Q其代h(hun)当然是可观的?BR> 另一个困扰是“裸”的Serializable不可定制Q傻乎乎C么都l你序列化了(jin)Q不你是不是想q么做。其实你可以有至三U定制序列化的选择。其中一U前面已l提C(jin)Q就是在implements Serializable的类里面dU有的writeObject()和readObject()Ҏ(gu)Q这USerializable׃怺(jin)Q)(j)Q在q两个方法里Q该序列化什么,不该序列化什么,那就׃说了(jin)了(jin)Q你当然可以在这两个Ҏ(gu)体里面分别调用ObjectOutputStream.defaultWriteObject()和ObjectInputStream.defaultReadObject()仍然执行默认的序列化动作Q那你在代码上不做无用功了(jin)Q呵呵)(j)Q也可以用ObjectOutputStream.writeObject()和ObjectInputStream.readObject()Ҏ(gu)对你中意的属性进行序列化。但虚拟Z看到你定义了(jin)q两个方法,它就不再用默认的机制?jin)?BR> 如果仅仅Z(jin)跌某些属性不让它序列化,上面的动作似乎显得麻?ch),更简单的Ҏ(gu)是对不想序列化的属性加上transient关键字,说明它是个“暂态变量”,默认序列化的时候就不会(x)把这些属性也塞到外部里?jin)。当?dng)你如果定义writeObject()和readObject()Ҏ(gu)的化Q仍然可以把暂态变量进行序列化。题外话Q像transient、violate、finallyq样的关键字初学者可能会(x)不太重视Q而现在有的公司招聘就偏偏喜欢问这L(fng)问题 :(
再一个方案就是不实现Serializable而改成实现Externalizable接口。我们研I一下这两个接口的源代码Q发现它们很cMQ甚臛_易淆。我们要C的是QExternalizable默认q不保存M对象相关信息QQ何保存和恢复对象的动作都是你自己定义的。Externalizable包含两个public的方法:(x)
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
乍一看这和上面的writeObject()和readObject()几乎差不多,但Serializable和Externalizable走的是两个不同的程QSerializable在对象不存在的情况下Q就可以仅凭外部的字节序列把整个对象重徏出来Q但Externalizable在重建对象时Q先是调用该cȝ默认构造函敎ͼ即不含参数的那个构造函敎ͼ(j)使得内存中先有这么一个实例,然后再调用readExternalҎ(gu)对实例中的属性进行恢复,因此Q如果默认构造函C和readExternalҎ(gu)中都没有赋值的那些属性,特别他们是非基本cd的话Q将?x)是I(nullQ。在q里需要注意的是,transient只能用在对Serializable而不是Externalizable的实现里面?
★序列化与克?BR> 从“可序列化”的递归定义来看Q一个序列化的对象貌似对象内存映象的外部克隆Q如果没有共享引用的属性的化,那么应该是一个深度克隆。关于克隆的话题有可以谈很多Q这里就不细说了(jin)Q有兴趣的话可以参考IBM developerWorks上的一文章:(x)JAVA中的指针,引用?qing)对象的clone
一点启C?/P>
作ؓ(f)一个实际的应用Q我在写那个易的邮g客户端JExp的时候曾l对比过好几U保存Message对象Q主要是几个关键属性和邮g的内容)(j)到本地的Ҏ(gu)Q譬如XML、Properties{,最后还是选择?jin)用序列化的方式Q因U方法最单, 大约可算是“学以致用”Ş。这里“存取程序状态”其实只是一个引子话题Ş?jin),我想说的??如同前面我们讨论的关于logging的话题一??在Java面前对同一个问题你可以有很多种solutionQ熟(zhn)文件操作的Q你可能?x)觉得Properties、XML或Bean比较方便Q然后又发现?jin)还有Preferencesq么一个东东,大概又会(x)感慨“天外有天”了(jin)Q等C接触?jin)很多种新方法以后,l果又会(x)“殊途同归”,重新反省Serialization机制本n。这不仅是JavaQ科学也是同L(fng)道理?/P>
参考资?/P>
Core Java 2. by Cay S. Horstmann, Gary Cornell
J2SEq阶. by JavaResearch.org
Thinking in Java. by Bruce Eckel
J2SE 1.4.2 Documentation. by java.sun.com
Java Network Programming. by Elliotte R. Harold
Java分布式对象:(x)RMI和CORBA. by IBM developerWorks
(Wang hailong)
关于~程的参C递问题,L存在着q样的争论。传|q是传引用?Q还是传指针Q还是传地址Q)(j)q些提法Q经常出现在C++, java, C#的编E技术文档里面。这个问题也l常引v开发h员的争论Q徒耗h力物力。实际上Q这Ҏ(gu)不成为问题,只是׃Zؓ(f)加入的概念,h?jin)h们的视听?/SPAN>
从程序运行的角度来看Q参C递,只有传|从不传递其它的东西。只不过Q?B style="mso-bidi-font-weight: normal">值的内容有可能是数据Q也有可能是一个内存地址?/SPAN>
开发h员应该了(jin)解程序的~译l果是怎样在计机中运行的。程序运行的时候,使用的空间可以分Z个部分,栈和堆。栈是指q行栈,局部变量,参数Q都分配在栈上。程序运行的时候,新生成的对象Q都分配在堆里,堆里分配的对象,栈里的数据参敎ͼ或局部变量?/FONT>
下面举一?/SPAN>C++的例子?/SPAN>
public class Object{
int i;
public Object(int i){
this.i = i;
}
public int getValue(){
return i;
}
public void setValue(int i){
this.i = i;
}
};
class A {
Void func1(int a, Object b){
Object * c = new Object( a );
b = c;
}
public void main(){
Object * param = new Object( 1 );
func1( 2, param )Q?/SPAN>
// what is value of parram now ?
// it is still 1.
}
};
我们来看一下,当调用到func1函数Ӟq行?/SPAN>Object * c = new Object( a ); 栈和堆的状态。不同编译器生成的代码运行的l果可能?x)稍有不同。但参数和局部变量的大致排放序都是相同的?/SPAN>
q时候,我们来看Q?/SPAN>param变量被压入运行栈的时候,只是q行?jin)简单的复制。把param里面的内Ҏ(gu)贝到b里面。这时候,b指向了(jin)Object(1)。这里的参数传递,是把param的g递给b?/SPAN>
下面我们来看Q程序执行到b = c;时候的堆栈状态?/SPAN>
我们可以看到Q?/SPAN>b现在指向?/SPAN>Object(2)。但是对param的值毫无媄(jing)响?/SPAN>param的D?/SPAN>Object(1)?/SPAN>
所以,我们_(d)对参数的赋g?x)?jing)响到外层函数的数据,但是Q调用参数的操作Ҏ(gu)Q却{于直接操作外层函数的数据。比如,如果我们?/SPAN>func1()函数中,不调?/SPAN>b=c;而调?/SPAN>b.setValue(3)Q那?/SPAN>Object(1)的数据就?x)变?/SPAN>3Q?/SPAN>param的数据也?x)改变?f)3?/SPAN>
?/SPAN>java?/SPAN>C#中的情况Q也都是一栗?/SPAN>
C++q有一U变量定义方法,表面上看hQ不W合上面的说明,q里q行说明?/SPAN>
Object * a = new Object(1);
Object & * b = a;
q里?/SPAN>bq于是a的另外一个别名,b是a。对b赋值就{于?/SPAN>a赋倹{甚至作为参C递时Q也是如此。对q种cd的参数的赋|q于对外层函数数据的赋倹{?/SPAN>
public class B{
void func1(Object & * b){
b = new Object(4);
}
public void main(){
Object * a = new Object(1);
func1(a);
// a is changed to Object(4) now.
}
}
当运行完func1(a);Ӟa的值变化ؓ(f)Object(4)。这是因为编译器实际把参?/SPAN>Object & * b~译?/SPAN>Object ** b_addrQ?/SPAN>b_addr的值是b的地址Q也是a的地址?/SPAN>
当调?/SPAN>func1()的时候,实际上是?/SPAN>b_addr作ؓ(f)参数压到栈里Q?/SPAN>b_addr的值是a的地址?/SPAN>
当执?/SPAN>b = new Object(4); Ӟ实际执行?/SPAN> b_addr->b = new Object(4); 也就是执行了(jin) b_addr->a = new Object(4); a的值当然变化了(jin)?/SPAN>
q有一炚w要说明,当?/SPAN>COMQ?/SPAN>CORBA{中间g规范q行开发时Q我们需要定?/SPAN>IDL语言。参数的cd分ؓ(f)Q?/SPAN>[in]Q?/SPAN>[out]Q?/SPAN>[in, out]Q其中的RPCq程调用的参数打包规范,更复杂?jin),但原理却是一L(fng)?/SPAN>