摸清java的本性,编写高效的代码

Posted on 2009-06-06 09:38 thui 阅读(599) 评论(1)  编辑  收藏 所属分类: java技术

 

java 语言是一门强大的语言,java的jdk为我们定义了很多的数据结构,方便了程序员的编码,避免了重复造车,但是正是因为java语言本身为我们做了很多事情,使我们无法很少关心底层的东西,造成有时候我们写的代码虽然可以完成功能,但是却不是最优的,可能很耗资源。为此石头边学习边研究,讨论如何才能写出高效的代码。
首先要说的是java数据类型,我们知道java 语言是一门强大的语言,java的jdk为我们定义了很多的数据结构,方便了程序员的编码,避免了重复造车,但是正是因为java语言本身为我们做了很多事情,使我们无法很少关心底层的东西,造成有时候我们写的代码虽然可以完成功能,但是却不是最优的,可能很耗资源。为此石头边学习边研究,讨论如何才能写出高效的代码。
首先要说的是java数据类型,我们知道java的数据类型有两种:基本类型和引用类型,像int、byte、char、long等都属于java的基本类型,它们不是对象,而所谓的引用类型通俗的说是指必须通过new方法才能得到的数据类型,说白了就是对象类型,那么基本类型和应用类型有什么区别呢?这个就需要探索java虚拟机内部是如何存储两种数据类型的,java的基本数据类型是存储在栈上,而引用类型是存储在堆上的,见下图:
java的数据类型有两种:基本类型和引用类型,像int、byte、char、long等都属于java的基本类型,它们不是对象,而所谓的引用类型通俗的说是指必须通过new方法才能得到的数据类型,说白了就是对象类型,那么基本类型和应用类型有什么区别呢?这个就需要探索java虚拟机内部是如何存储两种数据类型的,java的基本数据类型是存储在栈上,而引用类型是存储在堆上的,见下图:


java 语言是一门强大的语言,java的jdk为我们定义了很多的数据结构,方便了程序员的编码,避免了重复造车,但是正是因为java语言本身为我们做了很多事情,使我们无法很少关心底层的东西,造成有时候我们写的代码虽然可以完成功能,但是却不是最优的,可能很耗资源。为此石头边学习边研究,讨论如何才能写出高效的代码。
首先要说的是java数据类型,我们知道java 语言是一门强大的语言,java的jdk为我们定义了很多的数据结构,方便了程序员的编码,避免了重复造车,但是正是因为java语言本身为我们做了很多事情,使我们无法很少关心底层的东西,造成有时候我们写的代码虽然可以完成功能,但是却不是最优的,可能很耗资源。为此石头边学习边研究,讨论如何才能写出高效的代码。
首先要说的是java数据类型,我们知道java的数据类型有两种:基本类型和引用类型,像int、byte、char、long等都属于java的基本类型,它们不是对象,而所谓的引用类型通俗的说是指必须通过new方法才能得到的数据类型,说白了就是对象类型,那么基本类型和应用类型有什么区别呢?这个就需要探索java虚拟机内部是如何存储两种数据类型的,java的基本数据类型是存储在栈上,而引用类型是存储在堆上的,见下图:
java的数据类型有两种:基本类型和引用类型,像int、byte、char、long等都属于java的基本类型,它们不是对象,而所谓的引用类型通俗的说是指必须通过new方法才能得到的数据类型,说白了就是对象类型,那么基本类型和应用类型有什么区别呢?这个就需要探索java虚拟机内部是如何存储两种数据类型的,java的基本数据类型是存储在栈上,而引用类型是存储在堆上的,见下图:
如图所示,StringBuffer是一个引用类型,它是存储在堆上,str只是这个对象的一个引用,在C++语言里引用即是指针,指针即是对象的内存地址,str本身是一个存储在栈上的基本类型。123是一个int类型,也是存储在栈上的,很多同学要问了,栈和堆到底有什么不同?这里石头给大家简单的解释下,我们不是常说函数调用需要压栈出栈吗?栈是线程私有的;而堆是全局的,所有线程共享的,栈的空间很小,所以用来存储基本数据类型,堆很大,用来存储对象这样的大东西,由于堆是全局的共享的,可见堆是昂贵的,因为各个线程都要在它上面申请内存以存放对象,必然要求堆做好互斥和加锁,这些消耗是很大的。所以我们在编写代码时必须考虑到这一点。石头曾经做过一个题目,给你一个数字字母混合的字符串,写出一个程序从中去除字母,保留数字。这个程序有很多种方法,但是归纳起来有两种,一种是构造一个StringBuffer来把串中的数字连接;一种是用char数组来保存,经过测试后一种的效率高出前一种很多倍,为什么呢?就是因为第一种方法使用了对象StringBuffer,哪怕按照编程规范上说的优化方法,构造StringBuffer时指定长度后性能提高也不大,第二种方法的优势在于char数组时基本类型,不需要在堆上进行内存的操作,节约了时间。
上面谈了java基本数据类型,下面谈谈java的内存泄漏,内存泄漏到底是什么意思呢?有时候我们运行程序会出一个outofmemory的异常,这就是内存泄漏,这个异常是说内存不够了,举个bt的例子:
Vector v=new Vector();
for(int i=0;i<999999;i++)
{
v.add(new Date());
}
这段代码运行肯定会抛出outofmemory的异常,像上面的bt代码是故意制造内存泄漏,但是现实中我们编写代码时自己往往不会注意,运行久了便会出现内存溢出的错误,这种错误发生通常会发生在高速缓存,比如Vector、Map。
典型的算法如下所示:
1.检查结果是否在高速缓存中,存在则返回结果;
2.如果结果不在,那么计算结果;
3.将结果放入高速缓存,以备将来的操作调用。
这个算法的问题(或者说潜在的内存泄漏)在最后一步。如果操作是分别多次输入,那么存入高速缓存的内容将会非常大。很明显这个方法不可取。

为了避免这种潜在的致命错误设计,程序就必须确定高速缓存在他所使用的内存中有一个上界。因此,更好的算法是:
1.检查结果是否在高速缓存中,存在则返回结果;
2.如果结果不在,那么计算结果;
3.如果高速缓存所占空间过大,移除缓存中旧的结果;
4.将结果放入高速缓存,以备将来的操作调用。

所以我们编写代码时定义Vector、等缓存时一定记得指定一个初始化大小。刚才Vector的代码如果象下面这样写就不会出错了。
Vector v=new Vector(100);
public void add(Object obj)
{
if(v.size()<100)
{
v.add(obj);
}
}
当高速缓存不再使用时要记得把它设置为null,举个例子:
Vector v=new Vector();
for(int i=0;i<999999;i++)
{
Object o=new Object();
v.add(o);
o=null;
}
这段代码现new出对象o,然后加到vector中,最后又把对象设置为null,但是只是把对象的引用即指针置为null,Vector里对象还是在的,当不用vector时,要把vector设置为null才行

Feedback

# re: 摸清java的本性,编写高效的代码  回复  更多评论   

2012-06-04 09:29 by sss
垃圾

只有注册用户登录后才能发表评论。


网站导航:
 

posts - 11, comments - 8, trackbacks - 0, articles - 4

Copyright © thui