??xml version="1.0" encoding="utf-8" standalone="yes"?> Java内存泄漏是每个JavaE序员都会遇到的问题,E序在本地运行一切正?可是布v到远端就会出现内存无限制的增?最后系l瘫?那么如何最快最好的程序的E_?防止pȝ崩盘,作者用自已的亲w经历与各位分n解决q些问题的办? 一. Java是如何管理内? Z判断Java中是否有内存泄露,我们首先必须了解Java是如何管理内存的.Java的内存管?
是对象的分配和释放问题.在Java?内存的分配是q序完成的,而内存的释放是由垃圾攉?Garbage
Collection,GC)完成?E序员不需要通过调用函数来释攑ֆ?但它只能回收无用q且不再被其它对象引用的那些对象所占用的空? Java的内存垃圑֛收机制是从程序的主要q行对象开始检查引用链,当遍历一遍后发现没有被引用的?
立对象就作ؓ垃圾回收.GCZ能够正确释放对象,必须监控每一个对象的q行状?包括对象的申诗引用、被引用、赋值等,GC都需要进行监?监视对象
状态是Z更加准确地、及时地释放对象,而释攑֯象的Ҏ原则是该对象不再被引用. 在Java?q些无用的对象都由GC负责回收,因此E序员不需要考虑q部分的内存泄露.虽然,我们
有几个函数可以访问GC,例如q行GC的函数System.gc(),但是ҎJava语言规范定义,该函C保证JVM的垃圾收集器一定会执行.因ؓ?
同的JVM实现者可能用不同的法理GC.通常GC的线E的优先U别较低.JVM调用GC的策略也有很多种,有的是内存用到达一定程度时,GC才开
始工?也有定时执行?有的是^~执行GC,有的是中断式执行GC.但通常来说,我们不需要关心这? ? 什么是Java中的内存泄露 D内存泄漏主要的原因是,先前甌了内存空间而忘C释放.如果E序中存在对无用对象的引?那么
q些对象׃ȝ内存,消耗内?因ؓ无法让垃圑֛收器GC验证q些对象是否不再需?如果存在对象的引?q个对象p定义?有效的活?,同时不会
被释?要确定对象所占内存将被回?我们p务必认该对象不再会被?典型的做法就是把对象数据成员设ؓnull或者从集合中移除该对象.但当局?
变量不需要时,不需明显的设为null,因ؓ一个方法执行完毕时,q些引用会自动被清理. 在Java?内存泄漏是存在一些被分配的对?q些对象有下面两个特?首先,q些对象是有被引
用的,卛_有向树Ş图中,存在树枝通\可以与其相连Q其?q些对象是无用的,即程序以后不会再使用q些对象.如果对象满q两个条?q些对象可以判
定ؓJava中的内存泄漏,q些对象不会被GC所回收,然而它却占用内? q里引用一个常看到的例?在下面的代码?循环甌Object对象,q将所甌的对象放入一?
Vector?如果仅仅释放对象本n,但因为Vector仍然引用该对?所以这个对象对GC来说是不可回收的.因此,如果对象加入到Vector?
q必MVector中删?最单的Ҏ是Vector对象讄为null.实际上这些对象已l是无用?但还被引?GC无能ؓ力了(事实?
GC认ؓ它还有用),q一ҎD内存泄漏最重要的原?
再引用另一个例子来说明Java的内存泄?假设有一个日志类Logger,其提供一个静态的log(String
msg),M其它c都可以调用Logger.Log(message)来将message的内容记录到pȝ的日志文件中. LoggercL一个类型ؓHashMap的静态变量temp,每次在执行log(message)
的时?都首先将message的值写入temp?以当前线E?当前旉为键),在退Z前再从temp中将以当前线E和当前旉为键的条目删??
?q里当前旉是不断变化的,所以log在退Z前执行删除条目的操作q不能删除执行之初写入的条目.q样,M一个作为参Cllog的字W串最l由
于被Logger的静态变量temp引用,而无法得到回?q种对象保持是我们所说的Java内存泄漏.
ȝ来说,内存理中的内存泄漏产生的主要原因:保留下来却永q不再用的对象引用. ? 几种典型的内存泄? 我们知道了在Java中确实会存在内存泄漏,那么p我们看一看几U典型的泄漏,q找Z们发生的原因和解x? 3.1 全局集合 在大型应用程序中存在各种各样的全局数据仓库是很普遍?比如一个JNDI-tree或者一个session table.在这些情况下,必须注意理储存库的大小.必须有某U机制从储存库中U除不再需要的数据. 通常有很多不同的解决形式,其中最常用的是一U周期运行的清除作业.q个作业会验证仓库中的数据然?
清除一切不需要的数据.另一U管理储存库的方法是使用反向链接(referrer)计数.然后集合负责l计集合中每个入口的反向链接的数?q要求反向链
接告诉集合何时会退出入?当反向链接数目ؓ零时,该元素就可以从集合中U除? 3.2 ~存 常用的解决途径是用java.lang.ref.SoftReferencecd持将对象攑օ~存.q个Ҏ可以保证当虚拟机用完内存或者需要更多堆的时?可以释放q些对象的引? 3.3 c装载器 ? 如何和处理内存泄漏 如何查找引v内存泄漏的原因一般有两个步骤:W一是安排有l验的编Eh员对代码q行走查和分?扑և内存泄漏发生的位|?W二是用专门的内存泄漏试工具q行试. W一个步?在代码走查的工作?可以安排对系l业务和开发语a工具比较熟悉的开发h员对应用的代码进行了交叉走查,量扑և代码中存在的数据库连接声明和l果集未关闭、代码冗余等故障代码. W二个步?是Java的内存泄?在这里我们通常使用一些工h查JavaE序的内存泄?
问题.市场上已有几U专业检查Java内存泄漏的工?它们的基本工作原理大同小?都是通过监测JavaE序q行?所有对象的甌、释攄动作,内
存管理的所有信息进行统计、分析、可视化.开发h员将Ҏq些信息判断E序是否有内存泄漏问?q些工具包括Optimizeit
Profiler,JProbe Profiler,JinSight , Rational 公司的Purify{? 4.1内存泄漏的存在 一般说?一个正常的pȝ在其q行E_后其内存的占用量是基本稳定的,不应该是无限制的增长??
?对Q何一个类的对象的使用个数也有一个相对稳定的上限,不应该是持箋增长?Ҏq样的基本假?我们持箋地观察系l运行时使用的内存的大小和各实例
的个?如果内存的大持l地增长,则说明系l存在内存泄?如果特定cȝ实例对象个数随时间而增?是所谓的“增长?#8221;),则说明这个类的实例可能存
在泄漏情? 另一斚w通常发生内存泄漏的第一个迹象是Q在应用E序中出COutOfMemoryError.?
q种情况?需要用一些开销较低的工h监控和查扑ֆ存泄?虽然OutOfMemoryError也有可能应用E序实正在使用q么多的内存Q对于这
U情况则可以增加JVM可用的堆的数?或者对应用E序q行某种更改,使它使用较少的内? 但是,在许多情况下,OutOfMemoryError都是内存泄漏的信?一U查明方法是不间断地监控GC的活?定内存使用量是否随着旉增加.如果实如此,可能发生了内存泄漏. 4.2处理内存泄漏的方? Optimizeit是Borland公司的?主要用于协助对Y件系l进行代码优化和故障诊断,其中的Optimizeit Profiler主要用于内存泄漏的分?Profiler的堆视图是用来观察pȝq行使用的内存大和各个cȝ实例分配的个数的. 首先,Profiler会进行趋势分?扑և是哪个类的对象在泄漏.pȝq行长时间后可以得到四个?
存快?对这四个内存快照q行l合分析,如果每一ơ快照的内存使用都比上一ơ有增长,可以认定pȝ存在内存泄漏,扑և在四个快照中实例个数都保持增长的
c?q些cd以初步被认定为存在泄?通过数据攉和初步分?可以得出初步l论:pȝ是否存在内存泄漏和哪些对象存在泄?被泄?. 接下?看看有哪些其他的cM泄漏的类的对象相兌.前面已经谈到Java中的内存泄漏是无用的对
象保?单地说就是因为编码的错误D了一条本来不应该存在的引用链的存?从而导致了被引用的对象无法释放),因此内存泄漏分析的Q务就是找条多
余的引用?q找到其形成的原?查看对象分配到哪里是很有用的.同时只知道它们如何与其他对象相关?卛_些对象引用了它们)是不够的,关于它们在何?
创徏的信息也很有? 总而言? Java虽然有自动回收管理内存的功能,但内存泄漏也是不容忽?它往往是破坏系l稳定性的重要因素. 摘自Qhttp://www.51testing.com/?88979/spacelist-blog-page-2.html q行JVM字节码的工作是由解释? java命o
)来完成的。解释执行过E分三部q行Q代码的装入、代码的校验和代码的执行。装入代码的工作?c装载器"Qclass
loaderQ完成。类装蝲器负责装入运行一个程序需要的所有代码,q也包括E序代码中的cLl承的类和被其调用的cR当c装载器装入一个类Ӟ该类被放
在自q名字I间中。除了通过W号引用自己名字I间以外的类Q类之间没有其他办法可以影响其他cR在本台计算Z的所有类都在同一地址I间内,而所有从?
部引q的c,都有一个自q立的名字I间。这使得本地c通过׃n相同的名字空间获得较高的q行效率Q同时又保证它们与从外部引进的类不会怺影响。当装入
了运行程序需要的所有类后,解释器便可确定整个可执行E序的内存布局。解释器为符号引用同特定的地址I间建立对应关系及查询表。通过在这一阶段定代码?
内存布局QJava很好地解决了pcL变而子类崩溃的问题,同时也防止了代码对地址的非法访问?/p>
随后Q被装入的代码由字节码校验器q行查。校验器可发现操作数栈溢出,非法数据cd转化{多U错误。通过校验后,代码便开始执行了?/p>
Java字节码的执行有两U方式: 1.x~译方式Q解释器先将字节码编译成机器码,然后再执行该机器码?/p>
2.解释执行方式Q解释器通过每次解释q执行一段代码来完成Java字节码程序的所有操作?/p>
通常采用的是W二U方法。由于JVM规格描述h_的灵zL,q得将字节码翻译ؓ机器代码的工?/p>
h较高的效率。对于那些对q行速度要求较高的应用程序,解释器可Java字节码即时编译ؓ机器码,从而很好地保证了Java代码的可UL性和高性能?/p>
Q二QJVM规格描述 Java宣称的一处编写随处运行就是由JVM来完? 在sun的网站上你可以下载到Z各种cpu和各U操作系l的Jdk和jre的下载版?只要L到合适你使用的版?以前你所~写的class文gcopy到其他的机器上可以直接运?不需要再~译. 其实j2se是一U规?q种规范U定了其跨^台执行的所需要关注很多实?Z该规范开发h员可以Q意编写自qJava代码而不需要关心这个程序可能在其他的机器和cpu上无法很好运行问? 其实你也可以看到Ibm和Weblogic都有Zj2se规范的自己实现的Java
虚拟?. 而且Sun所宣称的不需要编译而可以直接用class文g在各个JVM上直接运行ƈ不精?博格曄遇到q用sun
jre开发的class文g在ibm
jre上有一个自动{换的q程,然后q个cd以很好的工作?q好q种情况是自动完?否则我们又要陷入cM于各Uc c++的版本编译器兼容性问题中. 以下下摘录了几个主要的概? JVM Java Virtual
MachineQJava虚拟机)Q它是一个虚构出来的计算?是通过在实际的计算Z仿真模拟各种计算机功能来实现的?
Java虚拟机有自己完善的硬件架?如处理器、堆栈、寄存器{?q具有相应的指opȝ。JVM屏蔽了与具体操作pȝq_相关的信?使得JavaE序?
需生成在Java虚拟Zq行的目标代?字节?,可以在多种q_上不加修改地q行。Java虚拟机在执行字节码时,实际上最l还是把字节码解释成?
体^C的机器指令执行?/p>
JRE Java Runtime EnvironmentQJavaq行环境Q,q行JAVAE序所必须的环境的集合Q包含JVM标准实现及Java核心cd?/p>
JSDK Java Software Development KitQ和JDK以及J2SE{同?/p>
JDK Java Development Kit(Java开发工具包):包括q行环境、编译工具及其它工具、源代码{,基本上和J2SE{同?/p>
J2ME Java 2 Micro
EditionQJAVA2_版)API规格ZJ2SE Q但是被修改为可以适合某种产品的单一要求。J2ME使JAVA
E序可以很方便的应用于电话卡、寻呼机{小型设备,它包括两U类型的lgQ即配置QconfigurationQ和描述QprofileQ?/p>
J2EE Java 2 Enterprise
EditionQJAVA2企业版)Q用Javaq行企业开发的一套扩展标准,必须ZJ2SEQ提供一个基于组件设计、开发、集合、展开企业应用的?
径。J2EE q_提供了多层、分布式的应用模型,重新利用lg的能力,l一安全的模式以及灵zȝ处理控制能力?J2EE包括EJB, JTA,
JDBC, JCA, JMX, JNDI, JMS, JavaMail, Servlet, JSP{规范?/p>
J2SE Java 2 Standard EditionQJAVA2标准版)Q用来开发JavaE序的基Q包括编译器、小工具、运行环境,SUN发布的标准版本中q包括核心类库的所有源代码?/p>
摘自Qhttp://www.diybl.com/course/3_program/java/javajs/20090304/157613.html 实际上语a学习有一定规律可循,对于已经掌握一门语a?
开发者来_对于一般的语言Q完全可以以最快的速度Q在几天至一周之内掌握其最常用?0%Q而且保证路子基本正宗Q没有出偏的弊病。其实真正写E序不?
完全不会Q最怕一知半解的L解决Ҏ。因Z完全不会Q就自然会去认真查书学习Q如果学习能力好的话Q写出来的代码质量不会差。而一知半解,自己动手?
法炼钢,那搞出来的基本上都是废铜烂铁。比如错误处理和序列化,很多ZM?#8220;正\?#8221;Q而是凭借自q一知半解去攒野路子Q这是最危险的。因此,即
旉再紧张,q些内容也是必须首先完整了解一遍的。掌握这些内容之后进入实际开发,即有问题,也基本不会伤及项目大体。而开发者本人则可以安步当RQ慢
慢在实践中提高自己?/p>
以下列出一个学习提UԌ主要针对的是有经验的人,初学者不合适。这个提U只能用于一般的怿~程语言学习Q目前在
行~程语言排行榜上排前20的基本上都是怿语言。如果你要学的是LISP之类非庸俗语aQ或是某个Y件中的二ơ开发语aQ这里的未必合适。还是那
句话Q仅供参考?/p>
1. 首先了解该语a的基本数据类型,基本语法和主要语a构?/font>Q主要数学运符和print函数的用,辑ֈ能够写K强E序设计书课后数学习题的E度Q?/p>
2. 其次掌握数组和其他集合类的?/font>Q有基础的话可以理解一下泛型,如果理解不了也问题不大,后面可以补; 3. 单字W串处理。所谓简单,是Regex和Parser以下的内容,什么查找替换,截断d串之cȝ。不q这个阶D|一个难点,是字符~码问题。如果理解不了,可以先蟩q,否则的话最好在q时候把q个问题搞定Q免留后患; 4. 基本面向对象或者函数式~程的特?/font>Q无非是什么ѝ多态、Lambda函数之类的,如果有经验的话很快就明白了; 5. 异常、错误处理、断a、日志和调试支持Q对单元试的支?/font>。你不一定要用TDDQ但是在q个时候应该掌握在q个语言里做TDD的基本技能; 6. E序代码和可执行代码的组l机Ӟq行时模块加载、符h找机?/font>Q这是初学时的一个难点,因ؓ大部分书都不太注意介l这个极为重要的内容Q?/p>
7. 基本输入输出和文件处理,输入输出类的组l?/font>Q这通常是比较繁琐的一部分Q可以提U挈领学一下,搞清楚概念,用到的时候查是了。到q个阶段可以写大部分控制台应用了Q?/p>
8. 该语a如何q行callbackҎ调用Q如何支持事仉动编E模型?/font>?
C~程环境下,q个问题是涉及开发思想的一个核心问题,几乎每种语言在这里都会用_夫,.NET的delegateQJava的anonymous
inner classQJava 7的closureQC++OX?
tr1::function/bindQ五花八门。如果能d理解q个问题Q不但程序就不至于写得太走样Q而且对该语言的设计思\也能有比较好的认识; 9. 如果有必要,可在q时研究regex和XML处理问题Q如无必要可跌Q?/p>
10. 序列化和反序列化Q掌握一下缺省的机制可以了Q?/p>
11. 如果必要Q可了解一下线E、ƈ发和异步调用机制Q主要是ZL别h的代码,如果自己要写q类代码Q必M门花旉严肃认真pȝ地学习,严禁半桶水上阵; 12. 动态编E,反射和元数据~程Q数据和E序之间的相互{化机Ӟq行时编译和执行的机Ӟ有抱负的开发者在q块可以多下些功夫,能够使你对语a的认识高Z个层面; 13. 如果有必要,可研I一下该语言对于泛型的支持,不必花太多时_只要能用现成的泛型集合和泛型函数就可以了,可在以后闲暇时抽旉pȝ学习。需要注意的是,泛型技术跟多线E技术一P用不好就成ؓ万恶之源Q必ȝl学习,谨慎使用Q否则不如不学不用; 14.
如果q有旉Q最好咨询一下有l验的hQ看看这个语a较常用的特色features是什么,如果之前没学q,应当补一下。比如Ruby的block
interator, Java的dynamic proxyQC# 3的LINQ和extension
method。没旉的话Q我认ؓ也可以边做边学,没有大问题?/p>
15. 有必要的话,在工作的闲暇旉Q可以着重考察两个问题Q第一Q这个语a有哪些惯用法和模式,W二Q这个语a的编?解释执行机制?/p>
?
此语a的基本部分就可以说掌握了Q之后是做数据库、网l还是做囑ŞQ可以根据具体需求去搞,扄应的成熟框架或库Q边做边学,加深理解。对于一个庸俗语
aQ我自己把上面的内容C遍大概要?-3周时_不能很快,但也耽误不了太多事情Q毕竟不是每个月都学新语a。掌握了以上的内容,ql武术打好了
基本功,虽然不见得有多优UQ但是肯定是Ҏ苗红Q将来不必绕大弯子。就是临时使用的语aQ把上面q个提纲_一下,只看蓝色重体字的部分Q大致能在几
天到一周内搞定Q不是太耗时Q而且写出来的代码不会太不靠谱?/p>
以上提纲未设及内存模型。对于C/C++Q这个问题很重要Q要攑֜显著位置来考虑Q但对于其他语言Q这个问题被透明化了Q除非你要做hardcore目Q否则不必太x?/p>
摘自Qhttp://blog.csdn.net/myan/archive/2008/10/25/3144661.aspx C++中怎么来实现呢Q当ӞC++兼容CQ用函数指针可以?nbsp; 同时C++又提供了面向对象的机Ӟ可不可以有不同的实现机制呢? 当然Q?
STL 中的functor(Function object)可以用到回调上?nbsp;
比如对一个存放int数据的vectorq行递减排序的话Q我们可以这栯行?/p>
sort(vec.begin(),vec.end(),greater()); greater()是我们传递的一个匿名对象,它重载了函数调用q算W?#8220;()”。我们没有显式地调用q个对象里面提供的函敎ͼsort函数对对象里面的函数q行call back?/p>
Java中要实现cMfunctor的功能,应该怎么办呢QCommand模式可以帮上忙。Command模式看v来很单,只要把command装C个接口中可以。Command模式是回调机制的一个面向对象的替代品?/p>
比如 java.io 中已l定义好的一个接?/p>
public interface FilenameFilter { q个FilenameFilter是CommandQ实现Command的类是ConcreteCommand。这个接口所声明的操?
“accept”
是看看目录dir中的文gname是否满某种要求Q如果满_q回trueQ否则就q回false。这个要求是什么呢Q你要对q个接口q行实现。比?
我想看看q个文g的名U包含不包含指定 class DirFilter implements FilenameFilter { this.afn = afn; 怎么样用它呢?FilecM有这样一个方?br />
public String[] list(FilenameFilter filter) 因此Q我们就可以q样做了Q?br />
File file = new File(”.”); 得到的list是一个当然目录中所有包含字W串”wf”的文件名U的字符串数l?/p>
怎么P看v来是不是和C++中的functor差不多呢Q?/p>
anonymous inner class ?nbsp; closure Q?.0Q都是体现回调的思想 Reference Reference是什么? 设计选择Q?/strong> q和Java有什么关p? 一D小E序 // just for format private static void changeReference(ReferenceTricks r) { private static void changeInteger(ReferenceTricks r) { public int i; OKQ你已经q行q了吗?l果如何Q是否如你预期?下面是我在自q机器上运行的l果Q?br />
Before changeInteger:0 Before changeReference:0 p涂的讲?/span> Reference +--------+ Reference +--------+ 调用changeInteger之前 调用changeInteger之后 让我们把目光转向changeReference?br />
从代码上Q我们可以看出,同changeInteger之间的差别仅仅在于多了这么一句?br />
r = new ReferenceTricks(); Reference +--------+ +--------+ 调用changeReference之前 调用changeReference之后 着q个思\l箋下去的话Q执行完changeReferenceQ输出的r的i字段Q那么应该是应该是新内存中的iQ所以应该是5。至于那块被我们抛弃的内存,Java的GC功能自然会替我们善后的?br />
事与愿违?br />
实际的结果我们已l看CQ输出的??br />
肯定哪个地方错了Q究竟是哪个地方呢? 参数传递的U密 摘自Qhttp://azi.javaeye.com/blog/182792 今天在WCS的测试中邂逅了q个从未接触的exception q我对它做了一些分?/p>
首先Q?br />
“不断的将被选中的字W串加到某一字符串末,当长度超q一定量时提C: Java API指出StringIndexOutOfBoundsException异常 String是没有长度限制的Q而是有JVM的内存限制了String的长?/p>
在dayworker的blog中还提到 [quote] public class testString{ 摘自Qhttp://blog.chinaunix.net/u/18/showart_18583.html W一Q谈谈final, finally, finalize的区别? 以下是答案: Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q?/p>
W一Q谈谈final, finally, finalize的区别?br />
final—修饰符Q关键字Q如果一个类被声明ؓfinalQ意味着它不能再z出新的子 finalize—方法名。Java 技术允怋?finalize() Ҏ在垃圾收集器对象从内存 HashMap允许null作ؓ一个entry?a target="_blank" >key或者valueQ而Hashtable不允?/p>
q有是QHashMap把Hashtable的containsҎL了,Ҏcontainsvalue和conta 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是Q在 q有是QHashMap把Hashtable的containsҎL了,Ҏcontainsvalue和conta 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是Q在 W六QCollection ?Collections的区别?br />
Collections是个java.util下的c,它包含有各种有关集合操作的静态方法?br />
Collection是个java.util下的接口Q它是各U集合结构的父接? javac -source 1.4 Test.java 一般Singleton模式通常有几U种形式:一、避免在循环条g中用复杂表辑ּ
在不做编译优化的情况下,在@环中Q@环条件会被反复计,如果不用复杂表辑ּQ而循环条gg变的话,E序会q行的更快?br />
例子Q?br />
import java.util.Vector;
class CEL {
void method (Vector vector) {
for (int i = 0; i < vector.size (); i++) // Violation
; // ...
}
}
更正Q?br />
class CEL_fixed {
void method (Vector vector) {
int size = vector.size ()
for (int i = 0; i < size; i++)
; // ...
}
}
二、ؓ'Vectors' ?'Hashtables'定义初始大小
JVM为Vector扩充大小的时候需要重新创Z个更大的数组Q将原原先数l中的内容复制过来,最后,原先的数l再被回收。可见Vector定w的扩大是一个颇Ҏ间的事?br />
通常Q默认的10个元素大是不够的。你最好能准确的估计你所需要的最佛_?br />
例子Q?br />
import java.util.Vector;
public class DIC {
public void addObjects (Object[] o) {
// if length > 10, Vector needs to expand
for (int i = 0; i< o.length;i++) {
v.add(o); // capacity before it can add more elements.
}
}
public Vector v = new Vector(); // no initialCapacity.
}
更正Q?br />
自己讑֮初始大小?br />
public Vector v = new Vector(20);
public Hashtable hash = new Hashtable(10);
参考资料:
Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
Techniques" Addison Wesley, ISBN: 0-201-70429-3 pp.55 – 57
三、在finally块中关闭Stream
E序中用到的资源应当被释放Q以避免资源泄漏。这最好在finally块中d。不程序执行的l果如何Qfinally块L会执行的Q以保资源的正关闭?br />
例子Q?br />
import java.io.*;
public class CS {
public static void main (String args[]) {
CS cs = new CS ();
cs.method ();
}
public void method () {
try {
FileInputStream fis = new FileInputStream ("CS.java");
int count = 0;
while (fis.read () != -1)
count++;
System.out.println (count);
fis.close ();
} catch (FileNotFoundException e1) {
} catch (IOException e2) {
}
}
}
更正Q?br />
在最后一个catch后添加一个finally?br />
参考资料:
Peter Haggar: "Practical Java - Programming Language Guide".
Addison Wesley, 2000, pp.77-79
四、?System.arraycopy ()'代替通过来@环复制数l?/font>
'System.arraycopy ()' 要比通过循环来复制数l快的多?br />
例子Q?br />
public class IRB
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i++) {
array1 [i] = i;
}
int[] array2 = new int [100];
for (int i = 0; i < array2.length; i++) {
array2 [i] = array1 [i]; // Violation
}
}
}
更正Q?br />
public class IRB
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i++) {
array1 [i] = i;
}
int[] array2 = new int [100];
System.arraycopy(array1, 0, array2, 0, 100);
}
}
参考资料:
http://www.cs.cmu.edu/~jch/java/speed.html
五、让讉K实例内变量的getter/setterҎ变成”final”
单的getter/setterҎ应该被置成finalQ这会告诉编译器Q这个方法不会被重蝲Q所以,可以变成”inlined”
例子Q?br />
class MAF {
public void setSize (int size) {
_size = size;
}
private int _size;
}
更正Q?br />
class DAF_fixed {
final public void setSize (int size) {
_size = size;
}
private int _size;
}
参考资料:
Warren N. and Bishop P. (1999), "Java in Practice", p. 4-5
Addison-Wesley, ISBN 0-201-36065-9
六、避免不需要的instanceof操作
如果左边的对象的静态类型等于右边的Qinstanceof表达式返回永qؓtrue?br />
例子Q?nbsp;
public class UISO {
public UISO () {}
}
class Dog extends UISO {
void method (Dog dog, UISO u) {
Dog d = dog;
if (d instanceof UISO) // always true.
System.out.println("Dog is a UISO");
UISO uiso = u;
if (uiso instanceof Object) // always true.
System.out.println("uiso is an Object");
}
}
更正Q?nbsp;
删掉不需要的instanceof操作?br />
class Dog extends UISO {
void method () {
Dog d;
System.out.println ("Dog is an UISO");
System.out.println ("UISO is an UISO");
}
}
七、避免不需要的造型操作
所有的c都是直接或者间接承自Object。同P所有的子类也都隐含?#8220;{于”其父cR那么,由子c造型至父cȝ操作是不必要的了?br />
例子Q?br />
class UNC {
String _id = "UNC";
}
class Dog extends UNC {
void method () {
Dog dog = new Dog ();
UNC animal = (UNC)dog; // not necessary.
Object o = (Object)dog; // not necessary.
}
}
更正Q?nbsp;
class Dog extends UNC {
void method () {
Dog dog = new Dog();
UNC animal = dog;
Object o = dog;
}
}
参考资料:
Nigel Warren, Philip Bishop: "Java in Practice - Design Styles and Idioms
for Effective Java". Addison-Wesley, 1999. pp.22-23
八、如果只是查扑֍个字W的话,用charAt()代替startsWith()
用一个字W作为参数调用startsWith()也会工作的很好,但从性能角度上来看,调用用String API无疑是错误的!
例子Q?br />
public class PCTS {
private void method(String s) {
if (s.startsWith("a")) { // violation
// ...
}
}
}
更正
?startsWith()' 替换?charAt()'.
public class PCTS {
private void method(String s) {
if ('a' == s.charAt(0)) {
// ...
}
}
}
参考资料:
Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
Techniques" Addison Wesley, ISBN: 0-201-70429-3
九、用移位操作来代替'a / b'操作
"/"是一个很“昂贵”的操作,使用UM操作会更快更有效?br />
例子Q?br />
public class SDIV {
public static final int NUM = 16;
public void calculate(int a) {
int div = a / 4; // should be replaced with "a >> 2".
int div2 = a / 8; // should be replaced with "a >> 3".
int temp = a / 3;
}
}
更正Q?br />
public class SDIV {
public static final int NUM = 16;
public void calculate(int a) {
int div = a >> 2;
int div2 = a >> 3;
int temp = a / 3; // 不能转换成位UL?br />
}
}
十、用移位操作代?a * b'
同上?br />
[i]但我个h认ؓQ除非是在一个非常大的@环内Q性能非常重要Q而且你很清楚你自己在做什么,方可使用q种Ҏ。否则提高性能所带来的程序晚L的降低是不合的?br />
例子Q?br />
public class SMUL {
public void calculate(int a) {
int mul = a * 4; // should be replaced with "a << 2".
int mul2 = 8 * a; // should be replaced with "a << 3".
int temp = a * 3;
}
}
更正Q?br />
package OPT;
public class SMUL {
public void calculate(int a) {
int mul = a << 2;
int mul2 = a << 3;
int temp = a * 3; // 不能转换
}
}
十一、在字符串相加的时候,使用 ' ' 代替 " "Q如果该字符串只有一个字W的?
例子Q?br />
public class STR {
public void method(String s) {
String string = s + "d" // violation.
string = "abc" + "d" // violation.
}
}
更正Q?br />
一个字W的字符串替换成' '
public class STR {
public void method(String s) {
String string = s + 'd'
string = "abc" + 'd'
}
}
十二、不要在循环中调用synchronized(同步)Ҏ
Ҏ的同步需要消耗相当大的资料,在一个@环中调用它绝对不是一个好L?br />
例子Q?br />
import java.util.Vector;
public class SYN {
public synchronized void method (Object o) {
}
private void test () {
for (int i = 0; i < vector.size(); i++) {
method (vector.elementAt(i)); // violation
}
}
private Vector vector = new Vector (5, 5);
}
更正Q?br />
不要在@环体中调用同步方法,如果必须同步的话Q推荐以下方式:
import java.util.Vector;
public class SYN {
public void method (Object o) {
}
private void test () {
synchronized{//在一个同步块中执行非同步Ҏ
for (int i = 0; i < vector.size(); i++) {
method (vector.elementAt(i));
}
}
}
private Vector vector = new Vector (5, 5);
}
十三、将try/catch块移出@?/font>
把try/catch块放入@环体内,会极大的影响性能Q如果编译JIT被关闭或者你所使用的是一个不带JIT的JVMQ性能会将下降21%之多!
例子Q?nbsp;
import java.io.FileInputStream;
public class TRY {
void method (FileInputStream fis) {
for (int i = 0; i < size; i++) {
try { // violation
_sum += fis.read();
} catch (Exception e) {}
}
}
private int _sum;
}
更正Q?nbsp;
try/catch块移出@?nbsp;
void method (FileInputStream fis) {
try {
for (int i = 0; i < size; i++) {
_sum += fis.read();
}
} catch (Exception e) {}
}
参考资料:
Peter Haggar: "Practical Java - Programming Language Guide".
Addison Wesley, 2000, pp.81 – 83
十四、对于boolean|避免不必要的{式判断
一个booleang一个true比较是一个恒{操?直接q回该boolean变量的?. U走对于boolean的不必要操作臛_会带?个好处:
1)代码执行的更?(生成的字节码了5个字?Q?br />
2)代码也会更加q净 ?br />
例子Q?br />
public class UEQ
{
boolean method (String string) {
return string.endsWith ("a") == true; // Violation
}
}
更正Q?br />
class UEQ_fixed
{
boolean method (String string) {
return string.endsWith ("a");
}
}
十五、对于常量字W串Q用'String' 代替 'StringBuffer'
帔R字符串ƈ不需要动态改变长度?br />
例子Q?br />
public class USC {
String method () {
StringBuffer s = new StringBuffer ("Hello");
String t = s + "World!";
return t;
}
}
更正Q?br />
把StringBuffer换成StringQ如果确定这个String不会再变的话Q这会减少q行开销提高性能?br />
十六、用'StringTokenizer' 代替 'indexOf()' ?substring()'
字符串的分析在很多应用中都是常见的。用indexOf()和substring()来分析字W串ҎDStringIndexOutOfBoundsException。而用StringTokenizercL分析字符串则会容易一些,效率也会高一些?br />
例子Q?br />
public class UST {
void parseString(String string) {
int index = 0;
while ((index = string.indexOf(".", index)) != -1) {
System.out.println (string.substring(index, string.length()));
}
}
}
参考资料:
Graig Larman, Rhett Guthrie: "Java 2 Performance and Idiom Guide"
Prentice Hall PTR, ISBN: 0-13-014260-3 pp. 282 – 283
十七、用条件操作符替代"if (cond) return; else return;" l构
条g操作W更加的?br />
例子Q?br />
public class IF {
public int method(boolean isDone) {
if (isDone) {
return 0;
} else {
return 10;
}
}
}
更正Q?br />
public class IF {
public int method(boolean isDone) {
return (isDone ? 0 : 10);
}
}
十八、用条件操作符代替"if (cond) a = b; else a = c;" l构
例子Q?br />
public class IFAS {
void method(boolean isTrue) {
if (isTrue) {
_value = 0;
} else {
_value = 1;
}
}
private int _value = 0;
}
更正Q?br />
public class IFAS {
void method(boolean isTrue) {
_value = (isTrue ? 0 : 1); // compact expression.
}
private int _value = 0;
}
十九、不要在循环体中实例化变?/font>
在@环体中实例化临时变量会增加内存消?br />
例子Q?nbsp;
import java.util.Vector;
public class LOOP {
void method (Vector v) {
for (int i=0;i < v.size();i++) {
Object o = new Object();
o = v.elementAt(i);
}
}
}
更正Q?nbsp;
在@环体外定义变量,q反复?nbsp;
import java.util.Vector;
public class LOOP {
void method (Vector v) {
Object o;
for (int i=0;i<v.size();i++) {
o = v.elementAt(i);
}
}
}
二十、确?StringBuffer的容?/font>
StringBuffer
的构造器会创Z个默认大?通常?6)的字W数l。在使用中,如果出q个大小Q就会重新分配内存,创徏一个更大的数组Qƈ原先的数组复制q来Q再
丢弃旧的数组。在大多数情况下Q你可以在创?StringBuffer的时候指定大,q样避免了在容量不够的时候自动增长,以提高性能?br />
例子Q?nbsp;
public class RSBC {
void method () {
StringBuffer buffer = new StringBuffer(); // violation
buffer.append ("hello");
}
}
更正Q?nbsp;
为StringBuffer提供寝大?nbsp;
public class RSBC {
void method () {
StringBuffer buffer = new StringBuffer(MAX);
buffer.append ("hello");
}
private final int MAX = 100;
}
参考资料:
Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
Techniques" Addison Wesley, ISBN: 0-201-70429-3 p.30 – 31
二十一、尽可能的用栈变量
如果一个变量需要经常访问,那么你就需要考虑q个变量的作用域了。static? local?q是实例变量Q访问静态变量和实例变量会比访问局部变量多耗费2-3个时钟周期?br />
例子Q?br />
public class USV {
void getSum (int[] values) {
for (int i=0; i < value.length; i++) {
_sum += value[i]; // violation.
}
}
void getSum2 (int[] values) {
for (int i=0; i < value.length; i++) {
_staticSum += value[i];
}
}
private int _sum;
private static int _staticSum;
}
更正Q?nbsp;
如果可能Q请使用局部变量作Zl常讉K的变量?br />
你可以按下面的方法来修改getSum()ҎQ?nbsp;
void getSum (int[] values) {
int sum = _sum; // temporary local variable.
for (int i=0; i < value.length; i++) {
sum += value[i];
}
_sum = sum;
}
参考资料:
Peter Haggar: "Practical Java - Programming Language Guide".
Addison Wesley, 2000, pp.122 – 125
二十二、不要L使用取反操作W?!)
取反操作W?!)降低E序的可L,所以不要L使用?br />
例子Q?br />
public class DUN {
boolean method (boolean a, boolean b) {
if (!a)
return !a;
else
return !b;
}
}
更正Q?br />
如果可能不要使用取反操作W?!)
二十三、与一个接?q行instanceof操作
Z接口的设计通常是g好事Q因为它允许有不同的实现Q而又保持灉|。只要可能,对一个对象进行instanceof操作Q以判断它是否某一接口要比是否某一个类要快?br />
例子Q?br />
public class INSOF {
private void method (Object o) {
if (o instanceof InterfaceBase) { } // better
if (o instanceof ClassBase) { } // worse.
}
}
class ClassBase {}
interface InterfaceBase {}
摘自Qhttp://www.51testing.com/?88979/spacelist-blog-page-2.html
]]>
解决Java内存泄漏
?
为Internet最行的编E语a之一,Java现正非常行.我们的网l应用程序就主要采用Java语言开?大体上分为客L、服务器和数据库三个
层次.在进入测试过E中,我们发现有一个程序模块系l内存和CPU资源消耗急剧增加,持箋增长到出?
java.lang.OutOfMemoryError为止.l过分析Java内存泄漏是破坏系l的主要因素.q里与大家分享我们在开发过E中遇到?
Java内存泄漏的检和处理解决q程.
~存一U用来快速查扑ַl执行过的操作结果的数据l构.因此,如果一个操作执
行需要比较多的资源ƈ会多ơ被使用,通常做法是把常用的输入数据的操作l果q行~存,以便在下ơ调用该操作时用缓存的数据.~存通常都是以动态方式实?
?如果~存讄不正而大量用缓存的话则会出现内存溢出的后果,因此需要将所使用的内存容量与索数据的速度加以q.
Javac装载器的用ؓ内存泄漏提供了许多可乘之?一般来说类装蝲?
都具有复杂结?因ؓc装载器不仅仅是只与"常规"对象引用有关,同时也和对象内部的引用有?比如数据变量,Ҏ和各U类.q意味着只要存在Ҏ据变
?Ҏ,各种cd对象的类装蝲?那么c装载器驻留在JVM?既然c装载器可以同很多的cd?同时也可以和静态数据变量关?那么相当多的内存?
可能发生泄漏.
q里我们简单介l我们在使用Optimizeit查的q程.通常在知道发生内存泄漏之?W一步是要弄清楚泄漏了什么数据和哪个cȝ对象引v了泄?
一旦知道确实发生了内存泄漏,需要更专业的工h查明Z么会
发生泄漏.JVM自己是不会告诉您?q些专业工具从JVM获得内存pȝ信息的方法基本上有两U:JVMTI和字节码技?byte code
instrumentation).Java虚拟机工h?Java Virtual Machine Tools
Interface,JVMTI)及其前nJava虚拟机监视程序接?Java Virtual Machine Profiling
Interface,JVMPI)是外部工具与JVM通信q从JVM攉信息的标准化接口.字节码技术是指用探器处理字节码以获得工具所需的信息的技
?
最?q一步研I单个对?看看它们是如何互相关联的.借助于Profiler工具,应用E序中的代码可以在分
配时q行动态添?以创建堆栈跟t?也有可以对系l中所有对象分配进行动态的堆栈跟踪.q些堆栈跟踪可以在工具中q行累积和分?Ҏ个被泄漏的实例对
?必然存在一条从某个牵引对象出发到达该对象的引用?处于堆栈I间的牵引对象在被从栈中弹出后就失去其牵引的能力,变ؓ非牵引对?因此,在长旉?
q行?被泄露的对象基本上都是被作ؓcȝ静态变量的牵引对象牵引.
]]>
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Plug-in
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
同时QJava2 SDK安装E序会把java.exeQjavaw.exeQjavareg.exeq??zmkey class="zoomino-searchword">可执行文?/zmkey>拯到winnt\system32目录下,׃winnt\system32被操作系l缺省的讄为最高优先权的PATH搜烦路径Q因此可保证用户在命令行M目录下可q行java.exe来启动JVM?
那么java.exe在启动时如何定其JRE所在的目录以及需要动?zmkey class="zoomino-searchword">加蝲的链接库呢?java.exe是通过下面方式来确定的Q?
假如存在../jre/bin/java.dll文gQ则查找../jre/lib/
jvm.cfg文gQ在该文件中Q第1个被列出的jvm.dllcd作ؓ~省|假如在java.exe命o行指定了jvm.dll的类型,则用指定类
型)。jvm.dllcd分ؓhotspotQclassicQserver三种。假如不存在../jre/lib/jvm.cfg文gQ则打印下面的错
误信息:
Error: could not open 'c:\jdk1.3\jre\lib\jvm.cfg'
如不?
?./jre/bin/java.dllQ当q行的是winnt\system32\java.exeQ,则注册表在此时发挥?
用,HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\
CurrentVersion键值所记录的实际上是winnt\system32\java.exe的版本|该版本值只保存丅R次两个版本P?
1.2Q?.3{?
同时java.exeE序内部本n也有一个标识自w的版本|?.2?.3{。java.exeҎ自己内部的版
本值和CurrentVersion值相比较Q假如发C个值相{,则将在HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft
\Java Runtime Environment\MainVersion.MicroVersion下获取JRE所在目录及
假如java.exe内部版本值和CurrentVersion不一_则报cM以下的错误:
Registry key 'Software\JavaSoft\Java Runtime Environment\CurrentVersion'
has value '1.2', but '1.3' is required.
意思是_注册表当前所记蝲的winnt\system32\java.exe版本?.2Q但是此时运行的java.exe版本?.3?
java.exe抱怨除非注册表?.3版的记蝲Q否则自己无法正定位JRE目录和jvm.dllQ因此提C?.3是需要的?
q里Q我
们不能简单的修改注册表的CurrentVersion值来辑ֈq个目的。一般地Q当在系l中装了两套版本的Java2
SDKQ如先装1.2而后又装?.3Q,后面安装的Java2
SDK会将自己带的java.exe和javaw.exe拯到winnt\system32目录下,从而覆盖先前版本的java.exe?
javaw.exeQƈ且在注册表中改写CurrentVersion?.3。所以徏议在安装Java2
SDK前,先卸载以前安装的版本。假如h为的修改CurrentVersionQ会使得不同版本的java.exe加蝲与己版本不符的java.dll?
jvm.dllQ将引v难以预料的后果!
非凡情况Q?
JBuilder自己带一套JDKQ在JBuilder安装完成后,JBuilder安装E序会修改CurrentVersion己所带JDK的版本,但不会覆盖winnt\system32下的java.exe和javaw.exe?
WebLogic自己带一套JDKQ在WebLogic安装完成后,WebLogic安装E序不会修改注册表,也不会覆盖winnt\system32下的java.exe和javaw.exe?
Oracle自己带一套JDKQ一般是比较低版本的Q例?.1.7仅仅带JDK
1.1.7Q,在Oracle安装完成后,Oracle安装E序不会修改注册表,也不会覆盖winnt\system32下的java.exe?
javaw.exe。但是,Oralce安装E序会修改系lPATH变量Q将自带的JRE的bin路径加入其中Q且|于最前面。随着Oracle安装版本
的不同,其自带JRE的JVM启动E序也不同。在W者机器上安装的Oracle 8.1.7Q其JREp在C:\Program
Files\Oracle下,q将C:\Program
Files\Oracle\jre\1.1.7\bin攑֜PATH变量最前,其JVM启动E序是jre.exe而非java.exe?
以上是Java2 SDK在Windows下安装时所做的动作Q这样会带来兼容性问题:
问题背景Q安装Java2 SDK后,安装了JBuilder6Q未修改MPATH变量
问题1
当在操作pȝ中安装了JDK 1.2Q其后安装了JBuilder6Q自带JDK 1.3.1Q,q时CurrentVersion?.3Q在命o行执行java -versionӞ提示Q?
Registry key 'Software\JavaSoft\Java Runtime Environment\CurrentVersion'
has value '1.3', but '1.2' is required.
解决ҎQ将JDK 1.2中java.exe所在\径加入到操作pȝPATH的首位,从而保证在命o行调用java时L执行JDK 1.2中的java.exeQ以使得java.exe可正定位JRE和jvm.dll?
问题2
当在操作pȝ中安装了JDK 1.3.0Q而后安装了JBuilder6Q自带JDK
1.3.1Q,q时CurrentVersion?.3Q但是此1.3是指向的是JBuilder6自带的JDK
1.3.1的JREQ而非指向先前JDK 1.3.0的JREQ当在命令行执行java -versionӞ此时执行的是JDK
1.3.0拯到winnt\system32的一个java.exe副本Q但打印的版本信息却是:
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)
D该问题的原因是java.exe只维护小数点?位的版本P而非2位?
解决ҎQ同问题1
问题3Q?
假如在操作系l中先安装了JDK 1.3.0Q而后安装了带有与安装JDKL版本相同的JBuilder6Q带JDK
1.3.1Q前两位相同Q,则问?实际上被隐蔽了,没有发生的机会;而问?的隐蔽性也很强Q不L发觉Q因Zh们往往会忽略JDK的第3个版本号?
如问?所叙,在命令行执行javaQ虽然是使用JDK
1.3.0的一个java.exe副本Qwinnt\system32目录下)Q而实际上却是使用JBuilder6下JDK
1.3.1的JRE及其目录l构Q其l果是当我们使用Java2的extension mechanismjar文g攑ֈJDK
1.3.0的jre\lib\ext目录下时Q发现达不到希望的效?– 在命令行用java启动E序Ӟ不会自动去JDK
1.3.0的jre\lib\ext目录下去搜烦jar文gQ它只会去JBuilder6下JDK
1.3.1的jre\lib\extL索jar文gQ而JBuilder6下的JDK 1.3.1q不存在jre\lib\extq么一个目录!
问题3极ؓ隐蔽Q除非完全对Java2 SDK的安装及class定位机制了解Q一般的开发者是难以发现问题所在的。有关Java2中class定位机制Q见?zmkey class="zoomino-searchword">Java2中的class定位机制》一文?
事实上,即仅仅在系l中存在一份JDK 1.3.0Q假如在命o行运行java的话Q用的JRE目录是C:\Program
Files\JavaSoft\JRE\1.3Q也是_即我们在c:\jdk1.3\jre\lib\ext下放|我们的extension
jarQ也得不到预期的l果。正的做法是放在C:\Program Files\JavaSoft\JRE\1.3\lib\ext目录下?
解决ҎQ同问题1
lg所叙,强烈?JDK_HOME%\bin目录攑֜Windows操作pȝ的PATH变量的首位,以避免潜在的问题?
而在UNIX下,则完全不存在cMWindows操作pȝ上的问题?
我们在命令下执行的java?bin/java
$which java
$/bin/java
?bin是到/usr/bin的链接,也就是说/bin/java实际上是/usr/bin/java
?usr/bin/java实际上链接到/usr/java/bin/javaQ?usr/java是到/usr/java1.2的链接(Solaris 7或更高系l内|JDK 1.2Q,所以我们实际上执行的java?
/usr/java1.2/bin/java
ҎUNIX上的情况Qjava在运行时实际上L可以?./jre/lib/sparc/libjava.so?./jre/lib/sparc
/libjvm.so来找到这2个文Ӟ前者类gWindows下的java.dllQ而后者类gWindows下的jvm.dll。所以java?
L可以定自己JRE的目录?
Windows和UNIX上用到的动态链接库Q实际上在Sun的文档中UCؓoptional
package's native code binariesQoptional pakage实际上即为extension mechanism
classesQ详见《Java2中的class定位机制》?
要更改UNIX上java的版本,更改/usr/java的链接是其中一个方法,具体可参见JDK在UNIX上的安装介绍?
补充Q(2002-12-23Q?
Windows如何定位Plug-in
Ҏ在PATH
不依靠HKEY_LOCAL_MACHINE\SOFTWARE
\JavaSoft\Java Development
Kit的CurrentVersion值和HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime
Environment的CurrentVersion值来定位应该使用哪个版本的Java Plug-in?br />
]]>
JVM的设计目标是提供一个基于抽象规格描q的计算机模型,释程序开发h员提很好的灵zL,同时也确保Java代码可在W合该规范的Mpȝ上运行。JVM对其实现的某些方面给Z具体的定义,特别是对Java
JVM寄存?br />
JVM栈结?br />
JVM片回收?br />
JVM存储?br />
2.1JVM指opȝ
JVM指opȝ同其他计机的指令系l极其相伹{Java指o也是?
操作码和操作C部分l成。操作码?位二q制敎ͼ操作数进紧随在操作码的后面,光度根据需要而不同。操作码用于指定一条指令操作的性质Q在q里我们?
用汇~符L形式q行说明Q,如iload表示从存储器中装入一个整敎ͼanewarray表示Z个新数组分配I间Qiand表示两个整数?
?Qret用于程控制Q表CZҎ一Ҏ的调用中q回。当长度大于8位时Q操作数被分Z个以上字节存放。JVM采用?big
endian"的编码方式来处理q种情况Q即高位bits存放在低字节中。这?Motorola及其他的RISC
CPU采用的编码方式是一致的Q而与Intel采用?little endian "的编码方式即低位bits存放在低位字节的Ҏ不同?br />
Java指opȝ是以Java语言的实Cؓ目的设计的,其中包含了用于调用方法和监视多先E系l的指o。Java?位操作码的长度得JVM最多有256U指令,目前已用了160多种操作码?br />
2.2JVM指opȝ
所有的CPU均包含用于保存系l状态和处理器所需信息的寄存器l。如果虚拟机定义较多的寄存器Q便可以从中得到更多的信息而不必对栈或内存q行讉KQ这
有利于提高运行速度。然而,如果虚拟Z的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,q反而会?
低虚拟机的效率。针对这U情况,JVM只设|了4个最为常用的寄存器。它们是Q?br />
pcE序计数?br />
optop操作数栈指?br />
frame当前执行环境指针
vars指向当前执行环境中第一?zmkey class="zoomino-searchword">局部变?/zmkey>的指?br />
所有寄存器均ؓ32位。pc用于记录E序的执行。optop,frame和vars用于记录指向Java栈区的指针?br />
2.3JVM栈结?br />
作ؓZ栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后Q便代码中一个类的每一个方法创Z个栈框架Q以保存该方法的状态信息。每个栈框架包括以下三类信息Q?br />
局部变?br />
执行环境
操作数栈
局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量?br />
执行环境用于保存解释器对Java字节码进行解释过E中所需的信息。它们是Q上ơ调用的Ҏ、局部变量指针和操作数栈的栈和栈底指针。执行环境是一?
执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法)Q首先要从frame寄存器中扑ֈ当前执行环境Q而后便从执行环境中找到操作数栈,
从栈弹Z个整数进行加法运,最后将l果压入栈顶?br />
操作数栈用于存储q算所需操作数及q算的结果?br />
2.4JVM片回收?br />
Javacȝ实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配I间的工作。解释器在ؓ一个实例分配完存储I间后,便开始记录对该实例所占用的内存区域的使用。一旦对象用完毕,便将其回收到堆中?br />
在Java语言中,除了new语句外没有其他方法ؓ一对象甌和释攑ֆ存。对内存q行释放和回收的工作是由Javaq行pȝ承担的。这允许Javaq行
pȝ的设计者自己决定碎片回收的Ҏ。在SUN公司开发的Java解释器和Hot
Java环境中,片回收用后台线E的方式来执行。这不但行系l提供了良好的性能Q而且使程序设计h员摆׃自己控制内存使用的风险?br />
2.5JVM存储?br />
JVM有两cd储区Q常量缓冲池和方法区。常量缓冲池用于存储cdU、方法和字段名称以及串常量。方法区则用于存储JavaҎ的字节码。对于这两种?
储区域具体实现方式在JVM规格中没有明规定。这使得Java应用E序的存储布局必须在运行过E中定Q依赖于具体q_的实现方式?br />
JVM是ؓJava字节码定义的一U独立于具体q_的规格描qͼ是Javaq_独立性的基础。目前的JVMq存在一些限制和不Q有待于q一步的完善Q但无论如何QJVM的思想是成功的?br />
Ҏ分析Q如果把Java原程序想象成我们的C++原程序,Java?zmkey class="zoomino-searchword">E序~译
]]>
]]>
boolean accept(File dir, String name);
}
的字W串Q那么就可以定义下面的类Q?/p>
private String afn;
public DirFilter(String afn){
}
public boolean accept(File dir, String name){
String f = new File(name).getName();
return f.indexOf(afn) != -1;
}
}
String[] list = file.list(new DirFilter(”wf”));
]]>
Java世界泰山北斗U大作《Thinking In Java》切入Java提?#8220;Everything is Object”。在Javaq个充满Object的世界中Qreference是一切谜题的ҎQ所有的故事都是从这里开始的?/p>
如果你和我一样在q入
Java世界之前曄迹于C/C++世界Q就一定不会对指针陌生。谈到指针,往日种U不堪回首的l历一下子涌上心头Q这里不是抱怨的地方Q让我们暂时?
记指针的痛苦Q回忆一下最初接触指针的甜蜜吧!q记得你看过的教U书中,如何讲解指针吗?留在我印象中的一U说法是Q指针就是地址Q如同门牌号码一P?
了地址Q你可以轻而易举找C个hӞ而不必费心力的大v捞针?br />
C++M历史舞台Qreference也随之而来Q容我问个小问题Q指针和reference区别何在Q我的答案来自于在C++世界享誉盛名的《More Effective C++》?/p>
当你指向你需要指向的某个东西Q而且l不会改指向其它东西Q或是当你实作一个运符而其语法需要无法有指针达成Q你应该选择reference。其它Q何时候,请采用指针?/p>
初学JavaQ鉴于reference的名Uͼ我毫不犹豫的它和C++中的reference{同h。不q,
我错了。在Java中,reference可以随心所Ʋ的赋值置I,Ҏ一下上面列出的差异Q就不难发现QJava的reference如果要与
C/C++对应Q它不过是一个穿着reference外衣的指针而已?br />
于是Q所有关于C中关于指针的理解方式Q可以照搬到Java中,而言之,reference是一个地址。我们可以把它想象成一个把手,抓住它,抓住了我们惌操纵的数据。如同掌握C的关键在于掌握指针,探烦Java的钥匙就是reference?/p>
我知道,太多的文字L令h犯困Q那来D代码吧Q?br />
public class ReferenceTricks {
public static void main(String[] args) {
ReferenceTricks r = new ReferenceTricks();
// reset integer
r.i = 0;
System.out.println("Before changeInteger:" + r.i);
changeInteger(r);
System.out.println("After changeInteger:" + r.i);
System.out.println();
// reset integer
r.i = 0;
System.out.println("Before changeReference:" + r.i);
changeReference(r);
System.out.println("After changeReference:" + r.i);
}
r = new ReferenceTricks();
r.i = 5;
System.out.println("In changeReference: " + r.i);
}
r.i = 5;
System.out.println("In changeInteger:" + r.i);
}
}
对不P我知道,把一个字D设成public是一U不好的~码习惯Q这里只是ؓ了说明问题?br />
如果你有兴趣自己q行一下这个程序,我等你!
In changeInteger:5
After changeInteger:5
In changeReference: 5
After changeReference:0
q里Q我们关注的是两个change——changeReference和changeInteger。从输出的内容中Q我们可以看出,两个Ҏ在调用前和调用中完全一P差异出现在调用后的结果?/p>
先让我们来分析一下changeInteger的行为?br />
前面说过
了,Java中的reference是一个地址Q它指向了一个内存空_q个I间存放着一个对象的相关信息。这里我们暂时不d心这个内存具体如何排
布,只要知道Q通过地址Q我们可以找到rq个对象的i字段Q然后我们给它赋?。既然这个字D늚内容得到了修改,从函Cq回之后Q它自然是改动后的l?
果了Q所以调用之后,r对象的i字段依然?。下囑ֱCZchangeInteger调用前后内存变化?/p>
---------->| i = 0 | ---------->| i = 5 |
|--------| |--------|
| Memory | | Memory |
| | | |
| | | |
+--------+ +--------+
q条语句的作用是分配一块新的内存,然后r指向它?br />
执行完这条语句,r׃再是原来的rQ但它依然是一个ReferenceTricks的对象,所以我们依然可以对q个r的i字段赋倹{到此ؓ止,一切都是那么自然?/p>
---------->| i = 0 | | i = 0 |
|--------| |--------|
| Memory | | Memory |
| | Reference |--------|
| | ---------->| i = 5 |
+--------+ +--------+
知道Ҏ参数如何传递吗Q?br />
记得刚开始学~程那会儿,老师教导Q所谓参敎ͼ有Ş式参数和实际参数之分Q参数列表中写的那些东西都叫形式参数Q在实际调用的时候,它们会被实际参数所替代?br />
~?
译程序不可能知道每次调用的实际参数都是什么,于是写编译器的高手就Z办法Q让实际参数按照一定顺序放C个大安可以扑־到的地方Q以此作为方法调?
的一U约定。所?#8220;没有规矩Q不成方?#8221;Q有了这个规矩,大家协作h容易多了。这个公共数据区Q现在编译器的选择通常?#8220;?#8221;Q而所谓的序是形式
参数声明的顺序?br />
昄Q程序运行的q程中,作ؓ实际参数的变量可能遍布于内存的各个位|,而ƈ不一定要老老实实的呆在栈里。ؓ了守“规矩”Q程序只好将变量复制一份到栈中Q也是通常所说的参数压入栈中?br />
打v_Q谜底就要揭晓了?br />
我刚才说什么来着Q将变量复制一份到栈中Q没错,“复制”Q?br />
q就是所谓的g递?br />
C语言的旷世经典《The C Programming Language》开的W一章中Q谈到实际参数时_“在C中,所有函数的实际参数都是?#8216;?#8217;?#8221;?br />
马上会有人站出来Q?#8220;错了Q还有传地址Q比如以指针传递就是传地址”?br />
不错Q传指针是传地址。在把指针视为地址的时候,是否考虑q这样一个问题,它也是一个变量。前面的讨论中说q了Q参C递必要把参数压入栈中,作ؓ地址的指针也不例外。所以,必须把这个指针也复制一份。函C对于指针操作实际上是对于q个指针副本的操作?br />
Java的reference{于C的指针。所以,在Java的方法调用中Qreference也要复制一份压入堆栈。在Ҏ中对reference的操作就是对q个reference副本的操作?br />
谜底揭晓
好,让我们回到最初的问题上?br />
在changeReference中对于reference的赋值实际上是对q个reference的副本进行赋|而对于reference的本没有生丝毫的影响?br />
回到调用点,本尊醒来Q它q不知道自己睡去的这D|间内发生q什么,所以只好当作什么都没发生过一般。就q样Q副本消׃Q在Ҏ中对它的修改也就烟消云散了?br />
也许你会问出q样的问题,“听了你的解释Q我反而对changeInteger感到qh了,既然是对于副本的操作Qؓ什么changeInteger可以q作正常Q?#8221;
呵呵Q很有趣的大脑短路现象?br />
好,那我q前面的说法解释一下changeInteger的运作?br />
所谓复Ӟ其结果必然是副本完全{同于本。reference复制的结果必然是两个reference指向同一块内存空间?br />
虽然在方法中对于副本的操作ƈ不会影响到本,但对内存I间的修改确实实实在在的?br />
回到调用点,虽然本尊依然不知道曾l发生过的一切,但它按照原来的方式访问内存的时候,取到的确是经q方法修改之后的内容?br />
于是Ҏ可以把自q影响扩展到方法之外?br />
多说几句
q?
个问题v源于我对C/C++中同样问题的思考。同C/C++相比Q在changeReference中对reference赋值可能ƈ不会造成什么很严重
的后果,而在C/C++中,q么做却会造成臭名昭著?#8220;内存泄漏”Q根本的原因在于Java拥有了可qGC功能。即便这P我仍不推荐用这U的手法Q?
毕竟GC已经很忙了,我们怎么好意思再ȝ人家?br />
在C/C++中,q个问题q可以l引生뀂既然在函数中对于指针直接赋D不通,那么如何在函C修改指针呢?{案很简单,指针的指针,也就是把原来的指针看作一个普通的数据Q把一个指向它的指针传到函C可以了?br />
同样的问题到了Java中就没有那么妙的解x案了Q因为Java中可没有reference的referenceq样的语法。可能的变通就是将referenceq行装成类。至于g|公道自在人心?/p>
]]>
]]>
1 JDK 1.4 及以下版本读取的Ҏ
JDK 1.4 及以下的版本中要想从控制C输入数据只有一U办法,即用System.in获得pȝ的输入流Q再桥接臛_W流从字W流中读入数据。示例代码如下:
import java.io.IOException;
import java.io.InputStreamReader;
public class Test1 {
public static void main(String[] args) {
String str = readString("误入字W串Q?);
System.out.println("readString Ҏ的输入:" + str);
}
/**
* 使用pȝ的输入流Q从控制Cd数据<br/>
* 用于所用的JDK版本
* @param prompt 提示信息
* @return 输入的字W串
*/
private static String readString(String prompt) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
try {
System.out.print(prompt);
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
从上面的代码D|看,q种控制台输入的Ҏ非常地麻烦,Z能读取整行的数据Q采用了BufferedReadercLq行处理Q而且在读取的q?
E中q需要捕获IOException。不q这?JDK 1.4
及以下版本中从控制台d数据唯一的办法。还有一U非控制台读入数据的办法Q就是采?Swing
中的JOptionPaneQ会弹出一个非常漂亮的输入对话框让使用者输入数据,但这是一U比较另cȝ做法Q不推荐使用?
import javax.swing.JOptionPane;
public class Test2 {
public static void main(String[] args) {
String str = readStringFromDialog("误入字W串Q?);
System.out.println("readStringFromDialog Ҏ的输入:" + str);
}
/**
* 使用JOptionPane的输入对话框Q输入字W串<br/>
* 用于所用的JDK版本
* @param prompt 提示信息
* @return 输入的字W串
*/
private static String readStringFromDialog(String prompt) {
return JOptionPane.showInputDialog(prompt);
}
}
上面的两U方法都有个共同的缺点——只能读取字W串Q若需要读取其他类型的数据需要手工进行{换?
2 JDK 5.0 d的方?
?JDK 5.0 开始,基本cd中增加了java.util.Scannerc,Ҏ它的 API
文档说明Q这个类是采用正则表辑ּq行基本cd和字W串分析的文本扫描器。用它的Scanner(InputStream
source)构造方法,可以传入pȝ的输入流System.in而从控制Cd数据。示例代码如下:
import java.util.Scanner;
public class Test3 {
public static void main(String[] args) {
String str = readString5("误入字W串Q?);
System.out.println("readString5 Ҏ的输入:" + str);
}
/**
* 使用扫描器类QScannerQ从控制Cd字符?lt;br/>
* 适用于JDK 5.0及以后的版本
* @param prompt 提示信息
* @return 输入的字W串
*/
private static String readString5(String prompt) {
Scanner scanner = new Scanner(System.in);
System.out.print(prompt);
return scanner.nextLine();
}
}
从代码量上来看,Test3比Test1了很多的代码,核心代码只有两行。其实ƈ不是Scanner控制台输入l简单化了,只是在其内部的实
C已经IOException处理了,而且采用InputStreamReader来一个字W一个字W进行扫描读取的Q嘿嘿,它本w就是个扫描器)Q?
只是Scanner做了更高层次的封装?
Scanner不仅可以从控制台中读取字W串Q还可以d除char之外的其他七U基本类型和两个大数字类型,q不需要显式地q行手工转换?
Scanner不单单只能扫描控制台中输入的字符Q它q可以让d的字W串匚w一定的正则表达式模式,如果不匹配时抛?
InputMismatchException异常?
使用System.in作ؓ它的构造参数时Q它只扫描了pȝ输入中的字W。它q有其他的构造,分别可以从文件或者是字符串中扫描分析字符串的Q具体的使用Ҏ可以参?API 文档说明?
3 JDK 6.0 d的方?
?JDK 6.0 开始,基本cd中增加了java.io.Consolec,用于获得与当?Java 虚拟机关联的Z字符的控制台讑֤。在U字W的控制台界面下Q可以更加方便地d数据。示例代码如下:
import java.io.Console;
import java.util.Scanner;
public class Test4 {
public static void main(String[] args) {
String str = readString6("误入字W串Q?);
System.out.println("readString6 Ҏ的输入:" + str);
}
/**
* 使用控制台类QConsoleQ从控制Cd字符?lt;br/>
* 适用于JDK 1.6或以后的版本
* @param prompt 提示信息
* @return 输入的字W串
*/
private static String readString6(String prompt) {
Console console = System.console();
if (console == null) {
throw new IllegalStateException("不能使用控制?);
}
return console.readLine(prompt);
}
}
在Test1和Test3中,输入数据前的提示信息需要用System.out.print();来输出,但是使用ZConsole的Test4c,可以在方法参C直接攑օ提示信息?
如果需要在控制C输入密码{敏感信息的话,像在览器或者是应用E序中那hC替代字W,?JDK 6.0
以前的做法是相当ȝ的(具体的做法可以参考《Java
~程语言中的口o屏蔽》一文)Q而用ConsolecȝreadPassword()Ҏ可以在控制台上不回显地输入密码,q将密码l果保存在char
数组中,Ҏ API 文档的徏议,在用后应立卛_数组清空Q以减少其在内存中占用的旉Q以便增强安全性?
但是QConsole也有一些缺点,ҎConsoleAPI 文档的说明:
虚拟机是否具有控制台取决于底层^収ͼq取决于调用虚拟机的方式。如果虚拟机从一个交互式命o行开始启动,且没有重定向标准输入和输出流Q那么其
控制台将存在Qƈ且通常q接到键盘ƈ从虚拟机启动的地ҎC。如果虚拟机是自动启动的Q例如,由后C业调度程序启动)Q那么它通常没有控制台?
通过上面的文档说明可以看出,在?IDE 的情况下Q是无法获取到Console实例的,原因在于?IDE
的环境下Q重新定向了标准输入和输出流Q也是就是将pȝ控制C的输入输出重定向C IDE 的控制台中。因此,?IDE
中不能用这个程序,而Test1和Test3没有这U限制?
4 ȝ
以上囊括?Java 中各U版本从控制Cd数据的方法,对它们的优~点q行了分析。下面给Z一些用徏议,可供参考:
JRE 1.4 或以下版本的情况下,没得选择只能采用Test1或者是非控制台d的Test2的方法?
JRE 5.0 的情况下Q徏议用基于Scanner的Test3的方法,更方便地q行数据d?
JRE 6.0 的情况,q且只在字符界面的控制台下运行时Q采用Test4的方法,如果需要读入像密码之类的敏感数据,Z安全性考虑也必M用Test4或者是自行实现。如果需要读入除字符串类型之外的其他数据cdQ徏议用基于Scanner的控制台输入?br />
摘自Qhttp://yutaozxy.javaeye.com/blog/372981
]]>
邂逅StringIndexOutOfBoundsException
java.lang.StringIndexOutOfBoundsException: String index out of range: 10
”q不能说明String有长度限?/p>
Thrown
by String methods to indicate that an index is either negative or
greater than the size of the string. For some methods such as the
charAt method?br />
上面的错误是因ؓ
String.length()<10;
而你又要取index>=10的字W从而抛Z面异?br />
String其实是没有限制的Q而是当String太大了,过JVM的自w的内存后会抛出
java.lang.OutOfMemoryError错误
public static void main(String args[])
{
String s="abbbbb";
System.out.println("JVM MAX MEMORY: "+Runtime.getRuntime().maxMemory()/1024/1024+"M");
System.out.println("JVM IS USING MEMORY:"+Runtime.getRuntime().totalMemory()/1024/1024+"M");
Runtime.getRuntime().traceMethodCalls(true);
while(true)
{
try{
s=s+s;
}catch(Exception e)
{
System.out.println(e);
}
catch(Error o)
{ String unit = null;
int sizeb = s.length();
int size = sizeb;
int time = 0;
while(size>1024)
{
size = size/1024;
time++;
}
switch(time)
{
case 0: unit = "byte";break;
case 1: unit = "k"; break;
case 2: unit = "M"; break;
default : unit = "byte";
}
System.out.println("String has used memory:"+size+unit);
System.out.println("JVM IS USING MEMORY:"+(float)Runtime.getRuntime().totalMemory()/1024/1024+"M");
System.out.println("MemoryError:"+o);
break;
}
}
}
}
然后我们用JVM的默认参数执行(我的机器内存?28MQ?br />
java testString
l果Q?br />
JVM MAX MEMORY: 128M
JVM IS USING MEMORY:1M
String has used memory:12M
JVM IS USING MEMORY:63.5625M
MemoryError:java.lang.OutOfMemoryError
开始JVM使用的内存是1MQ当String?2MQJVM使用?3M多时
JVM溢出?br />
然后Q我们用限制JVM内存大小的参数来执行,限制最大内?M
java -mx5m testString
l果Q?br />
JVM MAX MEMORY: 70M
JVM IS USING MEMORY:1M
String has used memory:768.0k
JVM IS USING MEMORY:5.9375M
MemoryError:java.lang.OutOfMemoryError
开始JVM使用的内存是1MQ当String?68kQJVM使用?M多时
JVM溢出?br />
大家q可以改?-mx参数Q来q一步做实验?br />
以上两个实验证明,String是没有长度限制的Q而是有JVM的内存限制了String的长度。同时说明,q不会抛ZQ何Exception而只会抛出Error.
OutMemoryError表明E序的设计很差,或者遇C出~程人员所预想的大扚w的数据。不哪U情况,都只有下面这几种解决办法。它们是Q?br />
设计人员重新设计E序Q不致ɽE序一ơ蝲入所有的数据?br />
数据可以分割成更的块?br />
可以为程序分配更多的内存?br />
为Java虚拟机提供更多的内存?br />
而上面的例子是ؓ虚拟机提供更多的内存
=======================================
其实应该用Stringq东西,特别?String?+=操作
不仅原来的String对象不能l箋使用Q主要是又要new出N多的新对象出来,再多的memory也要out~~
String用char array实现Q就肯定由长度限制的Q不能用memory来衡?br />
==================================
例如上面的程序改用StringBuffer实现Q就可以得到极大的改善?br />
下面是我改用StringBuffer做的试Q?br />
注意Q程序@环了2097150ơ!
是用String的程序的99864倍!
public class TestStringBuffer{
public static void main(String args[])
{
String s="abbbbb";
StringBuffer sb = new StringBuffer(s);
System.out.println("JVM IS USING MEMORY:"+
(Runtime.getRuntime().totalMemory()/1024/1024)+
"M");
Runtime.getRuntime().traceMethodCalls(true);
int count = 0;
while(true)
{
try{
sb.append(s);
count++;
}catch(Exception e)
{
System.out.println(e);
}
catch(Error o)
{
String unit = null;
int size = sb.length();
size *= 2;
int time = 0;
while(size>1024)
{
size = size/1024;
time++;
}
switch(time)
{
case 0: unit = "byte";break;
case 1: unit = "k"; break;
case 2: unit = "M"; break;
default : unit = "byte";
}
System.out.println("Loop times:"+count);
System.out.println("String has used memory:"+size+unit);
System.out.println("JVM IS USING MEMORY:"+
(float)Runtime.getRuntime().totalMemory()/1024/1024+
"M");
System.out.println("MemoryError:"+o);
break;
}
}
}
}
输出l果Q?br />
JVM IS USING MEMORY:1M
Loop times:2097150
String has used memory:23M
JVM IS USING MEMORY:63.75M
MemoryError:java.lang.OutOfMemoryError
=====================
?
另一斚w_如果你要处理的字W串辑ֈ癑օ甚至上GBQ用String对象Q根本没法工作,所以这个问题不需要太多讨论。看一下jdk的源?
ӞString的长度是String对象的一个成员countQ类型是intQ不是longQ也不是char。知道这些,我认为够?/p>
]]>
W二QAnonymous Inner Class (匿名内部c? 是否可以extends(l承)其它c,是否
可以implements(实现)interface(接口)?
W三QStatic Nested Class ?Inner Class的不同,说得多好(面试题有的很W?br />
l??br />
W四Q?amp;?amp;&的区别?br />
W五QHashMap和Hashtable的区别?br />
W六QCollection ?Collections的区别?br />
W七Q什么时候用assert?br />
W八QGC是什? Z么要有GC?
W九QString s = new String("xyz");创徏了几个String Object?
W十QMath.round(11.5){於多少? Math.round(-11.5){於多少?
W十一Qshort s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错
?
W十二,sleep() ?wait() 有什么区?
W十三,Java有没有goto?
W十四,数组有没有length()q个Ҏ? String有没有length()q个Ҏ?
W十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的cd
?
W十六,Set里的元素是不能重复的Q那么用什么方法来区分重复与否? 是用==q是
equals()? 它们有何区别?
W十七,l我一个你最常见到的runtime exception?br />
W十八,error和exception有什么区?
W十九,List, Set, Map是否l承自Collection接口?
W二十,abstract class和interface有什么区?
W二十一Qabstract?a target="_blank" >method是否可同时是static,是否可同时是nativeQ是否可同时
是synchronized?
W二十二Q接口是否可l承接口? 抽象cL否可实现(implements)接口? 抽象cL?br />
可承实体类(concrete class)?
W二十三Q启动一?a target="_blank" >U程是用run()q是start()?
W二十四Q构造器Constructor是否可被override?
W二十五Q是否可以承Stringc?
W二十六Q当一个线E进入一个对象的一个synchronizedҎ后,其它U程是否可进
入此对象的其它方?
W二十七Qtry {}里有一个return语句Q那么紧跟在q个try后的finally {}里的cod
e会不会被执行Q什么时候被执行Q在return前还是后?
W二十八Q编E题: 用最有效率的Ҏ出2乘以8{於?
W二十九Q两个对象值相?x.equals(y) == true)Q但却可有不同的hash codeQ这
句话对不?
W三十,当一个对象被当作参数传递到一个方法后Q此Ҏ可改变这个对象的属性,
q可q回变化后的l果Q那么这里到底是g递还是引用传?
W三十一Qswtich是否能作用在byte上,是否能作用在long上,是否能作用在String
?
W三十二Q编E题: 写一个Singleton出来?/p>
Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q?/p>
c,不能作ؓ父类被ѝ因此一个类不能既被声明?abstract的,又被声明为final?br />
。将变量或方法声明ؓfinalQ可以保证它们在使用中不被改变。被声明为final的变量必
d声明时给定初|而在以后的引用中只能dQ不可修攏V被声明为final的方法也?br />
样只能用,不能重蝲
finally—再异常处理时提?finally 块来执行M清除操作。如果抛Z个异常,
那么相匹配的 catch 子句׃执行Q然后控制就会进?finally 块(如果有的话)?/p>
中清除出M前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用
时对q个对象调用的。它是在 Object cM定义的,因此所有的c都l承了它。子c覆?br />
finalize() Ҏ以整?span class="t_tag" onclick="tagshow(event)" class="t_tag">pȝ资源或者执行其他清理工作。finalize() Ҏ是在垃圾攉
器删除对象之前对q个对象调用的?br />
W二QAnonymous Inner Class (匿名内部c? 是否可以extends(l承)其它c,是否
可以implements(实现)interface(接口)?
匿名的内部类是没有名字的内部cR不能extends(l承) 其它c,但一个内部类可以
作ؓ一个接口,由另一个内部类实现?br />
W三QStatic Nested Class ?Inner Class的不同,说得多好(面试题有的很W?br />
l??br />
Nested Class Q一般是C++的说法)QInner Class (一般是JAVA的说?。Java内部
cMC++嵌套cL大的不同在于是否有指向外部的引用上。具体可见http: //www.front
free.net/articles/services/view.asp?id=704&page=1
注: 静态内部类QInner ClassQ意味着1创徏一个static内部cȝ对象Q不需要一?br />
外部cd象,2不能从一个static内部cȝ一个对象访问一个外部类对象
Hashtablel承自Dictionaryc,而HashMap是Java1.2引进的Map interface的一个实
?/p>
insKey。因为containsҎҎ让h引v误解?/p>
多个U程讉KHashtableӞ不需要自׃ؓ它的Ҏ实现同步Q而HashMap
必Mؓ之提供外同步?br />
W四Q?amp;?amp;&的区别?br />
&是位q算W?amp;&是布逻辑q算W?br />
W五QHashMap和Hashtable的区别?br />
都属于Map接口的类Q实C惟一键映到特定的g?br />
HashMap cL有分cL者排序。它允许一?null 键和多个 null 倹{?
Hashtable cM?HashMapQ但是不允许 null 键和 null 倹{它也比 HashMap 慢,
因ؓ它是同步的?br />
Hashtablel承自Dictionaryc,而HashMap是Java1.2引进的Map interface的一个实
?/p>
insKey。因为containsҎҎ让h引v误解?/p>
多个U程讉KHashtableӞ不需要自׃ؓ它的Ҏ实现同步Q而HashMap
必Mؓ之提供外同步?/p>
W七Q什么时候用assert?br />
断言是一个包含布表辑ּ的语句,在执行这个语句时假定该表辑ּ?true。如果表
辑ּ计算?falseQ那么系l会报告一?AssertionError。它用于调试目的Q?
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两UŞ式:
assert Expression1 ;
assert Expression1 : Expression2 ;
Expression1 应该L产生一个布倹{?
Expression2 可以是得Z个值的L表达式。这个值用于生成显C更多调试信息的
String 消息?br />
断言在默认情况下是禁用的。要在编译时启用断言Q需要?source 1.4 标记Q?/p>
要在q行时启用断aQ可使用 -enableassertions 或?-ea 标记?
要在q行旉择用断言Q可使用 -da 或?-disableassertions 标记?
要系l类中启用断aQ可使用 -esa 或?-dsa 标记。还可以在包的基上启用或?br />
用断言?
可以在预计正常情况下不会到达的Q何位|上攄断言。断a可以用于验证传递给U?br />
有方法的参数。不q,断言不应该用于验证传递给公有Ҏ的参敎ͼ因ؓ不管是否启用?br />
断言Q公有方法都必须查其参数。不q,既可以在公有Ҏ中,也可以在非公有方法中
利用断言试后置条g。另外,断言不应该以M方式改变E序的状态?
W八QGC是什? Z么要有GC? (基础)?br />
GC是垃圾收集器。Java E序员不用担心内?span class="t_tag" >理Q因为垃圾收集器会自动进?span class="t_tag" >理?br />
要请求垃圾收集,可以调用下面的方法之一Q?
System.gc()
Runtime.getRuntime().gc()
W九QString s = new String("xyz");创徏了几个String Object?
两个对象Q一个是“xyx”,一个是指向“xyx”的引用对象s?br />
W十QMath.round(11.5){於多少? Math.round(-11.5){於多少?
Math.round(11.5)q回QlongQ?2QMath.round(-11.5)q回QlongQ?11;
W十一Qshort s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错
?
short s1 = 1; s1 = s1 + 1;有错Qs1是short型,s1+1?a target="_blank" >int?不能昑ּ转化为sho
rt型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确?br />
W十二,sleep() ?wait() 有什么区? 搞线E的最?br />
sleep()Ҏ是ɾU程停止一D|间的Ҏ。在sleep 旉间隔期满后,U程不一定立
x复执行。这是因为在那个时刻Q其它线E可能正在运行而且没有被调度ؓ攑ּ执行Q?br />
除非(a)“醒来”的线E具有更高的优先U?br />
(b)正在q行的线E因为其它原因而阻塞?br />
wait()是线E交互时Q如果线E对一个同步对象x 发出一个wait()调用Q该U程会暂
停执行,被调对象q入{待状态,直到被唤醒或{待旉到?br />
W十三,Java有没有goto?
Goto—java中的保留字,现在没有在java中用?br />
W十四,数组有没有length()q个Ҏ? String有没有length()q个ҎQ?br />
数组没有length()q个ҎQ有length的属性?br />
String有有length()q个Ҏ?br />
W十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的cd
?
Ҏ的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overridin
g是父cM子类之间多态性的一U表玎ͼ重蝲Overloading是一个类中多态性的一U表现?br />
如果在子cM定义某方法与其父cL相同的名U和参数Q我们说该方法被重写 (Overridi
ng)。子cȝ对象使用q个ҎӞ调用子cM的定义,对它而言Q父cM的定义如同被
“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参C数或有不?br />
的参数类型,则称为方法的重蝲(Overloading)。Overloaded的方法是可以改变q回值的c?br />
型?br />
W十六,Set里的元素是不能重复的Q那么用什么方法来区分重复与否? 是用==q是
equals()? 它们有何区别?
Set里的元素是不能重复的Q那么用iterator()Ҏ来区分重复与否。equals()是判?br />
两个Set是否相等?br />
equals()?=Ҏ军_引用值是否指向同一对象equals()在类中被覆盖Qؓ的是当两
个分ȝ对象的内容和cd盔R的话Q返回真倹{?br />
W十七,l我一个你最常见到的runtime exception?br />
ArithmeticException, ArrayStoreException, BufferOverflowException, BufferU
nderflowException, CannotRedoException, CannotUndoException, ClassCastExceptio
n, CMMException, ConcurrentModificationException, DOMException, EmptyStackExce
ption, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStat
eException, IllegalStateException,
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, N
egativeArraySizeException, NoSuchElementException, NullPointerException, Profi
leDataException, ProviderException, RasterFormatException, SecurityException,
SystemException, UndeclaredThrowableException, UnmodifiableSetException, Unsup
portedOperationException
W十八,error和exception有什么区?
error 表示恢复不是不可能但很困隄情况下的一U严重问题。比如说内存溢出。不
可能指望E序能处理这L情况?br />
exception 表示一U设计或实现问题。也是_它表C如果程序运行正常,从不?br />
发生的情c?br />
W十九,List, Set, Map是否l承自Collection接口?
ListQSet?br />
Map不是
W二十,abstract class和interface有什么区?
声明Ҏ的存在而不d现它的类被叫做抽象类Qabstract classQ,它用于要创徏
一个体现某些基本行为的c,qؓ该类声明ҎQ但不能在该cM实现该类的情c不?br />
创徏abstract cȝ实例。然而可以创Z个变量,其类型是一个抽象类Qƈ让它指向具体
子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract cȝ子类为它们父cM
的所有抽象方法提供实玎ͼ否则它们也是抽象cMؓ。取而代之,在子cM实现该方法。知
道其行ؓ的其它类可以在类中实现这些方法?br />
接口QinterfaceQ是抽象cȝ变体。在接口中,所有方法都是抽象的。多l承性可?br />
q实现这L接口而获得。接口中的所有方法都是抽象的Q没有一个有E序体。接口只?br />
以定义static final成员变量。接口的实现与子cȝ|除了该实现类不能从接口定义中
l承行ؓ。当cd现特D接口时Q它定义Q即程序体l予Q所有这U接口的Ҏ。然?br />
Q它可以在实C该接口的cȝM对象上调用接口的Ҏ。由于有抽象c,它允怋?br />
接口名作为引用变量的cd。通常的动态联~将生效。引用可以{换到接口cd或从接口
cd转换Qinstanceof q算W可以用来决定某对象的类是否实现了接口?br />
W二十一Qabstract的method是否可同时是static,是否可同时是nativeQ是否可同时
是synchronized?
都不?br />
W二十二Q接口是否可l承接口? 抽象cL否可实现(implements)接口? 抽象cL?br />
可承实体类(concrete class)?
接口可以l承接口。抽象类可以实现(implements)接口Q抽象类是否可承实体类Q?br />
但前提是实体cdL明确的构造函数?br />
W二十三Q启动一个线E是用run()q是start()?
启动一个线E是调用start()ҎQɾU程所代表的虚拟处理机处于可运行状态,q意
味着它可以由JVM调度q执行。这q不意味着U程׃立即q行。run()Ҏ可以产生必须
退出的标志来停止一个线E?br />
W二十四Q构造器Constructor是否可被override?
构造器Constructor不能被承,因此不能重写OverridingQ但可以被重载Overloadi
ng?br />
W二十五Q是否可以承Stringc?
StringcLfinalcL不可以ѝ?br />
W二十六Q当一个线E进入一个对象的一个synchronizedҎ后,其它U程是否可进
入此对象的其它方?
不能Q一个对象的一个synchronizedҎ只能׃个线E访问?br />
W二十七Qtry {}里有一个return语句Q那么紧跟在q个try后的finally {}里的cod
e会不会被执行Q什么时候被执行Q在return前还是后?
会执行,在return前执行?br />
W二十八Q编E题: 用最有效率的Ҏ出2乘以8{於?
有C背景的程序员特别喜欢问这U问题?br />
2 << 3
W二十九Q两个对象值相?x.equals(y) == true)Q但却可有不同的hash codeQ这
句话对不?
不对Q有相同的hash code?br />
W三十,当一个对象被当作参数传递到一个方法后Q此Ҏ可改变这个对象的属性,
q可q回变化后的l果Q那么这里到底是g递还是引用传?
是g递。Java ~程语言只由g递参数。当一个对象实例作Z个参数被传递到?br />
法中Ӟ参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变Q但对象
的引用是永远不会改变的?br />
W三十一Qswtich是否能作用在byte上,是否能作用在long上,是否能作用在String
?
switchQexpr1Q中Qexpr1是一个整数表辑ּ。因此传递给 switch ?case 语句?br />
参数应该?int?short?char 或?byte。long,string 都不能作用于swtich?br />
W三十二Q编E题: 写一个Singleton出来?br />
Singleton模式主要作用是保证在Java应用E序中,一个类Class只有一个实例存在?/p>
W一UŞ? 定义一个类Q它的构造函Cؓprivate的,它有一个static的private?br />
该类变量Q在cd始化时实例话Q通过一个public的getInstanceҎ获取对它的引?l?br />
而调用其中的Ҏ?br />
public class Singleton {
private Singleton(){}
//在自己内部定义自׃个实例,是不是很奇怪?
//注意q是private 只供内部调用
private static Singleton instance = new Singleton();
//q里提供了一个供外部讉K本class的静态方法,可以直接讉K
public static Singleton getInstance() {
return instance;
}
}
W二UŞ?
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//q个Ҏ比上面有所改进Q不用每ơ都q行生成对象Q只是第一?
//使用时生成实例,提高了效率!
if (instance==null)
instanceQnew Singleton();
return instance; }
}
其他形式:
定义一个类Q它的构造函Cؓprivate的,所有方法ؓstatic的?br />
一般认为第一UŞ式要更加安全
]]>
作ؓJAVAE序员,写代码难免出现bugQ我们来看看java 10大常见异?
NO.1 java.lang.NullPointerException
q个异常大家肯定都经帔R刎ͼ异常的解释是 "E序遇上了空指针
"Q简单地说就是调用了未经初始化的对象或者是不存在的对象Q这个错误经常出现在创徏囄Q调用数l这些操作中Q比如图片未l初始化Q或者图片创建时的\
径错误等{。对数组操作中出现空指针Q很多情况下是一些刚开始学习编E的朋友常犯的错误,x数组的初始化和数l元素的初始化淆v来了。数l的初始化是
Ҏl分配需要的I间Q而初始化后的数组Q其中的元素q没有实例化Q依然是I的Q所以还需要对每个元素都进行初始化Q如果要调用的话Q?
NO.2 java.lang.ClassNotFoundException
q个异常是很多原本在JB{开发环境中开发的E序员,把JB下的E序包放在WTk下编译经常出现的问题Q异常的解释?"指定的类不存?
"Q这里主要考虑一下类的名U和路径是否正确卛_Q如果是在JB下做的程序包Q一般都是默认加上Package的,所以{到WTK下后要注意把
Package的\径加上?
NO.3 java.lang.ArithmeticException
q个异常的解释是 "数学q算异常 "Q比如程序中出现了除以零q样的运就会出q样的异常,对这U异常,大家p好好查一下自q序中涉及到数学运的地方Q公式是不是有不妥了?
NO.4 java.lang.ArrayIndexOutOfBoundsException
q个异常怿很多朋友也经帔R到过Q异常的解释?"数组下标界
"Q现在程序中大多都有Ҏl的操作Q因此在调用数组的时候一定要认真查,看自p用的下标是不是超Z数组的范_一般来_昄Q即直接用常数当?
标)调用不太ҎL错,但隐式(即用变量表示下标Q调用就l常出错了,q有一U情况,是程序中定义的数l的长度是通过某些特定Ҏ军_的,不是事先
声明的,q个时候,最好先查看一下数l的lengthQ以免出现这个异常?
NO.5 java.lang.IllegalArgumentException
q个异常的解释是 "Ҏ的参数错?
"Q很多J2ME的类库中的方法在一些情况下都会引发q样的错误,比如音量调节Ҏ中的音量参数如果写成负数׃出现q个异常Q再比如
g.setColor(int red,int green,int
blue)q个Ҏ中的三个|如果有超q2Q5的也会出现这个异常,因此一旦发现这个异常,我们要做的,是赶紧L查一下方法调用中的参C递是不是
出现了错误?
NO.6 java.lang.IllegalAccessException
q个异常的解释是 "没有讉K权限 "Q当应用E序要调用一个类Q但当前的方法即没有对该cȝ讉K权限便会出现q个异常。对E序中用了Package的情况下要注意这个异常?
NO.7 java.lang.IncompatibleClassChangeError
不兼容的cd化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时Q抛异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新~译而直接运行的情况下,Ҏ引发该错误?
NO.8 java.lang.InstantiationError
实例化错误。当一个应用试N过Java的new操作W构造一个抽象类或者接口时抛出该异?
NO.9 java.lang.LinkageError
链接错误。该错误及其所有子cLC某个类依赖于另外一些类Q在该类~译之后Q被依赖的类改变了其cd义而没有重新编译所有的c,q而引发错误的情况?
NO.10 java.lang.StackOverflowError
堆栈溢出错误。当一个应用递归调用的层ơ太p导致堆栈溢出时抛出该错误?
]]>
Return of the Puzzlers: Schlock and Awe
Joshua Bloch, Google, Inc.; Neal Gafter, Microsoft
http://developers.sun.com/learning/javaoneonline/sessions/2009/pdf/TS-5186.pdf
1.Life's Persistent Questions
public class SimpleQuestion {
static boolean yesOrNo(String s) {
s = s.toLowerCase();
if (s.equals("yes") || s.equals("y") || s.equals("t")) {
s = "true";
}
return Boolean.getBoolean(s);
}
public static void main(String[] args) {
System.out.println(yesOrNo("true") + " " + yesOrNo("Yes"));
}
}
问题Q程序打C么?
如果熟悉Boolean.getBooleanQ)q个Ҏ的话Q应该不会出错。方法的功能参考文档?
2.Instruments of Tortue
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public class InstrumentedHashSet<E> extends HashSet<E> {
private int addCount = 0;
@Override
public boolean add(E e){
addCount++;
return super.add(e);
}
@Override
public boolean addAll(Collection<? extends E> c){
addCount += c.size();
return super.addAll(c);
}
public static void main(String[] args) {
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Accordion","Banjo","Kazoo"));
System.out.println(s.addCount);
}
}
问题Q打印结果是什么?
q个看第一遍可能会出错Q不q也容易理解?
3.Iterator Titillator
import java.util.Iterator;
import java.util.NoSuchElementException;
public abstract class AbstractIterator<T> implements Iterator<T> {
T next = nextElement();
public boolean hasNext() {
return next != null;
}
public T next() {
if (next == null) {
throw new NoSuchElementException();
}
T result = next;
next = nextElement();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
protected abstract T nextElement();
private static Iterator<Character> test(final String s) {
return new AbstractIterator<Character>() {
private int cursor = 0;
protected Character nextElement() {
return cursor == s.length() ? null : s.charAt(cursor++);
}
};
}
public static void main(String[] args) {
for (Iterator<Character> i = test("OPS"); i.hasNext();) {
System.out.print(i.next());
}
}
}
问题Q输出结果是什么?
理解如何正确的设计Iterator?
4.Search for the One
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Searching {
public static void main(String[] args) {
String[] strings = { "0", "1", "2", "3", "4", "5"};
List<Integer> integers = new ArrayList<Integer>();
for(String s : strings){
integers.add(Integer.valueOf(s));
}
System.out.println(Collections.binarySearch(integers, 1,cmp));
}
static Comparator<Integer> cmp = new Comparator<Integer>(){
public int compare(Integer i,Integer j){
return i<j?-1:(i==j?0:1);
}
};
}
问题Q打印结果是什么?
如果看过《Java Puzzlers》这本书的话应该Ҏ发现问题?
5.Cogito Ergo Sum
import java.util.LinkedHashMap;
import java.util.Map;
public enum RomanNumeral {
I(1), V(5), X(10), L(50), C(100), D(500), M(1000);
private static Map<Integer, RomanNumeral> map = new LinkedHashMap<Integer, RomanNumeral>();
public final int val;
RomanNumeral(int val) {
this.val = val;
storeInMap();
}
private void storeInMap() {
map.put(val, this);
}
public static RomanNumeral fromInt(int val) {
return map.get(val);
}
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < 1000; i++) {
if (fromInt(i) != null) {
sum += i;
}
}
System.out.println(sum);
}
}
问题Q打印结果是什么?
如果理解java加蝲cd创徏对象的顺序的话这个问题容易理解?
6.Thread Friendly
public class ThreadFriendly {
ThreadLocal<Value> threadLocalPart = new ThreadLocal<Value>();
class Value{
final int i;
Value(int i){
this.i = i;
}
}
ThreadFriendly setThreadVal(int i){
threadLocalPart.set(new Value(i));
return this;
}
int getThreadVal(){
return threadLocalPart.get().i;
}
public static void main(String[] args) {
int sum = 0;
for(int i = -500000;i<=500000;i++){
sum+= new ThreadFriendly().setThreadVal(i).getThreadVal();
}
System.out.println(sum);
}
}
问题Q打印结果是什么?
理解内部cdThreadLocal?
7.When Words Collide
public class PrintWords {
public static void main(String[] args) {
System.out.println(
Words.FIRST + " " + Words.SECOND + " " + Words.THIRD
);
}
}
public class Words{
public static final String FIRST = "the";
public static final String SECOND = null;
public static final String THIRD = "set";
}
~译PrintWords.java文g?
修改Words.java文g?
public class Words{
public static final String FIRST = "physics";
public static final String SECOND = "chemistry";
public static final String THIRD = "biology";
}
问题Q再ơ编译运行PrintWords.javaQ打印结果是什么?
需要了解常量折叠现象,理解什么是帔R?
]]>
( 一 )以字节ؓ导向?stream------InputStream/OutputStream
InputStream ?OutputStream 是两?abstact c,对于字节为导向的 stream 都扩展这两个鸡肋Q基c?^_^ Q?;
1?InputStream
1.1
ByteArrayInputStream -- 把内存中的一个缓冲区作ؓ InputStream 使用 .
construct---
(A)ByteArrayInputStream(byte[]) 创徏一个新字节数组输入( ByteArrayInputStream Q,它从指定字节数组中读取数据( 使用 byte 作ؓ其缓冲区数组Q?
(B)---ByteArrayInputStream(byte[], int, int) 创徏一个新字节数组输入,它从指定字节数组中读取数据?
---mark:: 该字节数l未被复制?
1.2
StringBufferInputStream -- 把一?String 对象作ؓ InputStream .
construct---
StringBufferInputStream(String) 据指定串创徏一个读取数据的输入串?
注释Q不推荐使用 StringBufferInputStream Ҏ?此类不能字W正的转换为字节?
?JDK 1.1 版中的类|从一个串创徏一个流的最x法是采用 StringReader cR?
1.3
FileInputStream -- 把一个文件作?InputStream Q实现对文g的读取操?
construct---
(A)FileInputStream(File name) 创徏一个输入文件流Q从指定?File 对象d数据?
(B)FileInputStream(FileDescriptor) 创徏一个输入文件流Q从指定的文件描q器d数据?
(C)-FileInputStream(String name) 创徏一个输入文件流Q从指定名称的文件读取数据?
method ---- read() 从当前输入流中读取一字节数据?
read(byte[]) 当前输入流?b.length 个字节数据读C个字节数l中?
read(byte[], int, int) 输入流?len 个字节数据读入一个字节数l中?
1.4
PipedInputStream Q实C pipe 的概念,主要在线E中使用 . 道输入是指一个通讯道的接收端?
一个线E通过道输出发送数据,而另一个线E通过道输入读取数据,q样可实C个线E间的通讯?
construct---
PipedInputStream() 创徏一个管道输入流Q它q未与一个管道输出流q接?
PipedInputStream(PipedOutputStream) 创徏一个管道输入流 , 它已q接C个管道输出流?
1.5
SequenceInputStream Q把多个 InputStream 合ƈZ?InputStream . “序列输入?#8221;cd许应用程序把几个输入连l地合ƈhQ?
q且使它们像单个输入一样出现。每个输入流依次被读取,直到到达该流的末?
然后“序列输入?#8221;cd闭这个流q自动地切换C一个输入流?
construct---
SequenceInputStream(Enumeration) 创徏一个新的序列输入流Qƈ用指定的输入的枚D值初始化它?
SequenceInputStream(InputStream, InputStream) 创徏一个新的序列输入流Q初始化为首?读输入流 s1, 然后读输入流 s2 ?
2?OutputSteam
2.1
ByteArrayOutputStream Q?把信息存入内存中的一个缓冲区?. 该类实现一个以字节数组形式写入数据的输出流?
当数据写入缓冲区Ӟ它自动扩大。用 toByteArray() ?toString() 能检索数据?
constructor
(A)--- ByteArrayOutputStream() 创徏一个新的字节数l输出流?
(B)--- ByteArrayOutputStream() 创徏一个新的字节数l输出流?
(C)--- ByteArrayOutputStream(int) 创徏一个新的字节数l输出流Qƈ带有指定大小字节的缓冲区定w?
toString(String) Ҏ指定字符~码缓冲区内容转换为字W串Qƈ字节{换ؓ字符?
write(byte[], int, int) 指定字节数l中从偏U量 off 开始的 len 个字节写入该字节数组输出?
write(int) 指定字节写入该字节数组输出?
writeTo(OutputStream) ?out.write(buf, 0, count) 调用输出的写方法将该字节数l输出流的全部内容写入指定的输出参数?
2.2
FileOutputStream: 文g输出是?File ?FileDescriptor 输出数据的一个输出流?
constructor
(A)FileOutputStream(File name) 创徏一个文件输出流Q向指定?File 对象输出数据?
(B)FileOutputStream(FileDescriptor) 创徏一个文件输出流Q向指定的文件描q器输出数据?
(C)FileOutputStream(String name) 创徏一个文件输出流Q向指定名称的文件输出数据?
(D)FileOutputStream(String, boolean) 用指定系l的文g名,创徏一个输出文件?
2.3
PipedOutputStream: 道输出是指一个通讯道的发送端?一个线E通过道输出发送数据,
而另一个线E通过道输入读取数据,q样可实C个线E间的通讯?
constructor
(A)PipedOutputStream() 创徏一个管道输出流Q它q未与一个管道输入流q接?
(B)PipedOutputStream(PipedInputStream) 创徏一个管道输出流Q它已连接到一个管道输入流?
( ?)以字Wؓ导向?stream Reader/Writer
?Unicode 字符为导向的 stream Q表CZ Unicode 字符为单位从 stream 中读取或往 stream 中写入信息?
Reader/Writer ?abstact c?
?Unicode 字符为导向的 stream 包括下面几种cdQ?
1. Reader
1.1
CharArrayReader Q与 ByteArrayInputStream 对应此类实现一个可用作字符输入的字符~冲?
constructor
CharArrayReader(char[]) 用指定字W数l创Z?CharArrayReader ?
CharArrayReader(char[], int, int) 用指定字W数l创Z?CharArrayReader
1.2
StringReader Q??StringBufferInputStream 对应其源Z个字W串的字W流?
StringReader(String) 创徏一新的串读取者?/p>
1.3
FileReader Q??FileInputStream 对应
1.4
PipedReader Q与 PipedInputStream 对应
2. Writer
2.1 CharArrayWrite Q??ByteArrayOutputStream 对应
2.2 StringWrite Q无与之对应的以字节为导向的 stream
2.3 FileWrite Q??FileOutputStream 对应
2.4 PipedWrite Q与 PipedOutputStream 对应
3、两U不同导向的 stream 之间的{?nbsp;
3.1
InputStreamReader ?OutputStreamReader Q?
把一个以字节为导向的 stream 转换成一个以字符为导向的 stream ?
InputStreamReader cL从字节流到字W流的桥梁:它读入字节,q根据指定的~码方式Q将之{换ؓ字符?
使用的编码方式可能由名称指定Q或q_可接受的~省~码方式?
InputStreamReader ?read() Ҏ之一的每ơ调用,可能促从基本字节输入流中读取一个或多个字节?
Z辑ֈ更高效率Q考虑?BufferedReader 装 InputStreamReader Q?
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
例如Q?// 实现从键盘输入一个整?
InputStreamReader(InputStream) 用缺省的字符~码方式Q创Z?InputStreamReader ?
InputStreamReader(InputStream, String) 用已命名的字W编码方式,创徏一?InputStreamReader ?
OutputStreamWriter 多个字W写入到一个输出流Q根据指定的字符~码多个字W{换ؓ字节?
每个 OutputStreamWriter 合ƈ它自q CharToByteConverter, 因而是从字W流到字节流的桥梁?/p>
Q三QJava IO 的一般用原?Q?nbsp;
一、按数据来源Q去向)分类Q?
1 、是文gQ?FileInputStream, FileOutputStream, ( 字节?)FileReader, FileWriter( 字符 )
2 、是 byte[] Q?ByteArrayInputStream, ByteArrayOutputStream( 字节?)
3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符?)
4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节?)StringReader, StringWriter( 字符?)
5 、网l数据流Q?InputStream, OutputStream,( 字节?) Reader, Writer( 字符?)
二、按是否格式化输出分Q?
1 、要格式化输出: PrintStream, PrintWriter
三、按是否要缓冲分Q?
1 、要~冲Q?BufferedInputStream, BufferedOutputStream,( 字节?) BufferedReader, BufferedWriter( 字符?)
四、按数据格式分:
1 、二q制格式Q只要不能确定是U文本的Q?: InputStream, OutputStream 及其所有带 Stream l束的子c?
2 、纯文本格式Q含U英文与汉字或其他编码方式)Q?Reader, Writer 及其所有带 Reader, Writer 的子c?
五、按输入输出分:
1 、输入: Reader, InputStream cd的子c?
2 、输出: Writer, OutputStream cd的子c?
六、特D需要:
1 、从 Stream ?Reader,Writer 的{换类Q?InputStreamReader, OutputStreamWriter
2 、对象输入输出: ObjectInputStream, ObjectOutputStream
3 、进E间通信Q?PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合q输入: SequenceInputStream
5 、更Ҏ的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
军_使用哪个cM及它的构造进E的一般准则如下(不考虑Ҏ需要)Q?
首先Q考虑最原始的数据格式是什么: 原则?
W二Q是输入q是输出Q原则五
W三Q是否需要{换流Q原则六W?1 ?
W四Q数据来源(dQ是什么:原则一
W五Q是否要~冲Q原则三 Q特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特D的输入或输出方法)
W六Q是否要格式化输出:原则?
出处Qhttp://blog.csdn.net/sqw131/archive/2009/03/25/4025047.aspx
Java 的serialization提供了一U持久化对象实例的机制。当持久化对象时Q可能有一个特D的对象数据成员Q我们不想用serialization? 制来保存它。ؓ了在一个特定对象的一个域上关闭serializationQ可以在q个域前加上关键字transient?/p>
transient是Java语言的关键字Q用来表CZ个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的g包括在串行化的表CZQ然而非transient型的变量是被包括q去的?/p>
首先Q让我们看一些Java serialization的代码:
public class LoggingInfo implements java.io.Serializable
{
private Date loggingDate = new Date();
private String uid;
private transient String pwd;
LoggingInfo(String user, String password)
{
uid = user;
pwd = password;
}
public String toString()
{
String password=null;
if(pwd == null)
{
password = "NOT SET";
}
else
{
password = pwd;
}
return "logon info: \n " + "user: " + uid +
"\n logging date : " + loggingDate.toString() +
"\n password: " + password;
}
}
现在我们创徏一个这个类的实例,q且串行?serialize)?,然后这个串行化对象写入盘?br />
LoggingInfo logInfo = new LoggingInfo("MIKE", "MECHANICS");
System.out.println(logInfo.toString());
try
{
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("logInfo.out"));
o.writeObject(logInfo);
o.close();
}
catch(Exception e) {//deal with exception}
To read the object back, we can write
try
{
ObjectInputStream in =new ObjectInputStream(new FileInputStream("logInfo.out"));
LoggingInfo logInfo = (LoggingInfo)in.readObject();
System.out.println(logInfo.toString());
}
catch(Exception e) {//deal with exception}
如果我们q行q段代码Q我们会注意C盘中读?read——back (de-serializing))的对象打印password?NOT SET"。这是当我们定义pwd域ؓtransientӞ所期望的正结果?br />
现在Q让我们来看一下粗心对待transient域可能引L潜在问题。假设我们修改了cd义,提供ltransient域一个默认|
代码如下Q?br />
public class GuestLoggingInfo implements java.io.Serializable
{
private Date loggingDate = new Date();
private String uid;
private transient String pwd;
GuestLoggingInfo()
{
uid = "guest";
pwd = "guest";
}
public String toString()
{
//same as above
}
}
?
在,如果我们串行化GuestLoggingInfo的一个实例,它写入盘Qƈ且再它从磁盘中dQ我们仍然看到读回的对象打印password
?"NOT
SET"。当从磁盘中d某个cȝ实例Ӟ实际上ƈ不会执行q个cȝ构造函敎ͼ而是载入了一个该cd象的持久化状态,q将q个状态赋值给该类的另一个对
象?/p>
摘自Q?a >http://www.devx.com/tips/Tip/13726
使用java与本地已~译的代码交互,通常会失^台可UL性。但是,有些情况下这样做是可以接受的Q甚x必须的,比如Q用一些旧的库Q与g、操作系l进行交互,或者ؓ了提?span style="text-decoration: underline;">E序的性能。JNI标准臛_保证本地代码能工作在MJava 虚拟机实C?/font>
JNIQJava Native InterfaceQ的书写步骤
·~写带有native声明的方法的javac?br />
·使用javac命o~译所~写的javac?br />
·使用javah ?jni javacd生成扩展名ؓh的头文g
·使用C/C++Q或者其他编E想语言Q实现本地方?br />
·C/C++~写的文件生成动态连接库
1) ~写javaE序Q?br />
q里以HelloWorldZ?br />
代码1Q?br />
class HelloWorld {
public native void displayHelloWorld();
static {
System.loadLibrary("hello");
}
public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
}
声明nativeҎQ如果你惛_一个方法做Z个本地方法的话,那么你就必须声明Ҏ法ؓnative的,q且不能实现。其中方法的参数和返回值在后面讲述?br />
Load
动态库QSystem.loadLibrary("hello");加蝲动态库Q我们可以这L解:我们的方法displayHelloWorld()?
有实玎ͼ但是我们在下面就直接使用了,所以必d使用之前对它q行初始化)q里一般是以static块进行加载的。同旉要注意的?
System.loadLibrary();的参?#8220;hello”是动态库的名字?br />
main()Ҏ
2) ~译没有什么好说的?br />
javac HelloWorld.java
3) 生成扩展名ؓh的头文g
javah ?jni HelloWorld
头文件的内容Q?br />
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: displayHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Q这
里我们可以这L解:q个h文g相当于我们在java里面的接口,q里声明了一个Java_HelloWorld_displayHelloWorld
(JNIEnv *,
jobject);ҎQ然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++E序的时候所使用的方法名必须和这里的一_?br />
4) ~写本地Ҏ
实现和由javah命o生成的头文g里面声明的方法名相同的方法?br />
代码2Q?br />
1 #include
2 #include "HelloWorld.h"
3 #include
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
printf("Hello world!\n");
return;
}
?
意代?中的W?行,需要将jni.hQ该文g可以?JAVA_HOME%/include文g夹下面找刎ͼ文g引入Q因为在E序中的JNIEnv?
jobject{类型都是在该头文g中定义的Q另外在W?行需要将HelloWorld.h头文件引入(我是q么理解的:相当于我们在~写javaE序?
时候,实现一个接口的话需要声明才可以Q这里就是将HelloWorld.h头文仉面声明的Ҏ加以实现。当然不一定是q样Q。然后保存ؓ
HelloWorldImpl.c?ok了?br />
5) 生成动态库
q里以在Windows中ؓ例,需要生成dll文g。在保存HelloWorldImpl.c文g夹下面,使用VC的编译器cl成?br />
cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll
?
意:生成的dll文g名在选项-Fe后面配置Q这里是helloQ因为在HelloWorld.java文g中我们loadLibary的时候用的名字
是hello。当然这里修改之后那里也需要修攏V另外需要将-I%java_home%\include
-I%java_home%\include\win32参数加上Q因为在W四步里面编写本地方法的时候引入了jni.h文g?br />
6) q行E序
java HelloWorldok?/font>
JNIQJava Native InterfaceQ调用中考虑的问?/strong>
在首ơ用JNI的时候有些疑问,后来在用中一一解决Q下面就是这些问题的备忘Q?/font>
1?java和c是如何互通的Q?br />
其实不能互通的原因主要是数据类型的问题Qjni解决了这个问题,例如那个c文g中的jstring数据cd是java传入的String对象Q经qjni函数的{化就能成为c的char*?br />
对应数据cd关系如下表:
Java cd 本地ccd 说明
boolean jboolean 无符P8 ?br />
byte jbyte 无符P8 ?br />
char jchar 无符P16 ?br />
short jshort 有符P16 ?br />
int jint 有符P32 ?br />
long jlong 有符P64 ?br />
float jfloat 32 ?br />
double jdouble 64 ?br />
void void N/A
2. 如何java传入的String参数转换为c的char*Q然后?
java
传入的String参数Q在c文g中被jni转换为jstring的数据类型,在c文g中声明char* testQ然后test =
(char*)(*env)->GetStringUTFChars(env, jstring,
NULL);注意Qtest使用完后Q通知虚拟机^台相关代码无需再访问:(*env)->ReleaseStringUTFChars(env,
jstring, test);
3. c中获取的一个char*的buffer传递给javaQ?br />
q个char*如果是一般的字符串的话,作ؓstring传回d可以了。如果是含有’\0’的bufferQ最好作为bytearray传出Q因为可以制定copy的lengthQ如果copy到stringQ可能到’\0’截断了?br />
有两U方式传递得到的数据Q?br />
一U是在jni中直接new一个byte数组Q然后调用函?*env)->SetByteArrayRegion(env,
bytearray, 0, len, buffer);buffer的值copy到bytearray中,函数直接return
bytearray可以了?br />
一U是return错误P数据作ؓ参数传出Q但是java的基本数据类型是传|对象是传递的引用Q所以将q个需要传出的byte数组用某个类包一下,如下Q?br />
class RetObj
{
public byte[] bytearray;
}
q个对象作ؓ函数的参数retobj传出Q通过如下函数retobj中的byte数组赋g于传出。代码如下:
jclass cls;
jfieldID fid;
jbyteArray bytearray;
bytearray = (*env)->NewByteArray(env,len);
(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);
cls = (*env)->GetObjectClass(env, retobj);
fid = (*env)->GetFieldID(env, cls, "retbytes", "[B"]);
(*env)->SetObjectField(env, retobj, fid, bytearray);
4. 不知道占用多空间的bufferQ如何传递出dQ?br /> 在jni的c文g中new出空_传递出厅Rjava的数据不初始化,指向传递出ȝI间卛_?/font>
转自Qhttp://blog.csdn.net/lion_6/archive/2008/03/17/2190442.aspx
W号?/font> | 指数?/font> | 数部分 | 指数偏移?/font> | |
---|---|---|---|---|
单精度QҎ | 1 位[31] | 8?[30-23] | 23?[22-00] | 127 |
双精度QҎ | 1 位[63] | 11 位[62-52] | 52 位[51-00] | 1023 |
我们以单_ֺ点数来说明Q?br />
W号位,表述点数的正或者负
指数实际也有正负的,但是没有单独的符号位Q而是采用了一个偏UL表示
在计机的世界里Q进位都是二q制的,指数表示的也?的Nơ幂
q个数据格式当中的,指数?位,可表辄范围??55
而对应的实际的指数是Q?27刎ͼ128
q里Ҏ说明Q-127和+128q两个数据在IEEE当中是保留的用作多种用途的
Q?27表示的数字是0
128和其他位数组合表C多U意义,最典型的就是NAN状?br />
数部分Qƈ不是一个QҎ的实际的数
实际的小数在q个数前面q保留了一?
拿QҎ1.0来说
W号位是0Q?实际指数?Q对应这里的指数是127了,也就?x7f
而小数部分就?.0了, 1是暗含的不存储,实际的小数部分就??br />
因此l合h的数据就是,0x3f80000
可以用一个类来表C:
class FloatType
{
public:
union {
DWORD m_dwInt;
float m_fFloat;
struct {
int m_nFra: 23;
int m_nExp : 8;
bool m_bSign : 1;
};
};
-----------------------------
-----------------------------
Java
语言的一个优点就是取消了指针的概念,但也D了许多程序员在编E中常常忽略了对象与引用的区别,本文会试图澄清这一概念。ƈ且由于Java不能通过?
的赋值来解决对象复制的问题,在开发过E中Q也常常要要应用cloneQ)Ҏ来复制对象。本文会让你了解什么是影子clone与深度cloneQ认识它
们的区别、优点及~点? 看到q个标题Q是不是有点困惑QJava语言明确说明取消了指针,因ؓ指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常? 杂难以理解,滥用指针写成的代码不亚于使用早已臭名昭著?GOTO"语句。Java攑ּ指针的概늻Ҏ极其明智的。但q只是在Java语言中没有明? 的指针定义,实质上每一个new语句q回的都是一个指针的引用Q只不过在大多时候Java中不用关心如何操作这?指针"Q更不用象在操作CQ+的指针那 栯战心惊。唯一要多多关心的是在l函C递对象的时候。如下例E: package reference; class Obj{ String str = "init value"; public String toString(){ return str; } } public class ObjRef{ Obj aObj = new Obj(); int aInt = 11; public void changeObj(Obj inObj){ inObj.str = "changed value"; } public void changePri(int inInt){ inInt = 22; } public static void main(String[] args) { ObjRef oRef = new ObjRef(); System.out.println("Before call changeObj() method: " + oRef.aObj); oRef.changeObj(oRef.aObj); System.out.println("After call changeObj() method: " + oRef.aObj); System.out.println("==================Print Primtive================="); System.out.println("Before call changePri() method: " + oRef.aInt); oRef.changePri(oRef.aInt); System.out.println("After call changePri() method: " + oRef.aInt); } } /* RUN RESULT Before call changeObj() method: init value After call changeObj() method: changed value ==================Print Primtive================= Before call changePri() method: 11 After call changePri() method: 11 * */ q段代码的主要部分调用了两个很相q的ҎQchangeObj()和changePri()。唯一不同的是它们一个把对象作ؓ输入参数Q另一个把 Java中的基本cdint作ؓ输入参数。ƈ且在q两个函C内部都对输入的参数进行了改动。看gLҎQ程序输出的l果却不太一栗? changeObj()Ҏ真正的把输入的参数改变了Q而changePri()Ҏ对输入的参数没有M的改变? 从这个例子知道Java对对象和基本的数据类型的处理是不一L。和C语言一P当把Java的基本数据类型(如intQcharQdouble{)作ؓ 入口参数传给函数体的时候,传入的参数在函数体内部变成了局部变量,q个局部变量是输入参数的一个拷贝,所有的函数体内部的操作都是针对q个拯的操作, 函数执行l束后,q个局部变量也完成了它的使命Q它影响不到作ؓ输入参数的变量。这U方式的参数传递被UCؓ"g?。而在Java中用对象的作为入? 参数的传递则~省?引用传?Q也是说仅仅传递了对象的一?引用"Q这?引用"的概念同C语言中的指针引用是一L。当函数体内部对输入变量改变 Ӟ实质上就是在对这个对象的直接操作? 除了在函C值的时候是"引用传?Q在M?Q?向对象变量赋值的时候都?引用传?。如Q? package reference; class PassObj { String str = "init value"; } public class ObjPassvalue { public static void main(String[] args) { PassObj objA = new PassObj(); PassObj objB = objA; objA.str = "changed in objA"; System.out.println("Print objB.str value: " + objB.str); |
3 | JAVA中的指针,引用及对象的clone | |
|
|
|
|
|
|
|
|
|
|
4 | JAVA中的指针,引用及对象的clone | |
|
|
|
|
|
|
|
|
|
|
5 | JAVA中的指针,引用及对象的clone | |
|
|