对StringBuffer对象的重用是此处的关键。通常你会编写如下的代码作为调试消息: debugMsg("Name:" + name + " Age:" + age); 如前文中所讨论过的,String类型的创建对性能产生不利的影响。如果像TestLogger.java中所示的那样重写,那么获得的性能提升将会是明显的。 日志记录的级别现在可以使用Logger类中定义的setLogLevel方法在运行时定制。在系统属性的帮助下完成这项工作是一个好主意。你必须定义自己的属性;在本例中它被命名为“app.loglevel”。如果所讨论的问题是一个应用程序,那么你可以对JVM使用-D开关设置“app.loglevel”属性[注3]。例如: java –D app.loglevel=3 myApp 另一方面,如果你的程序是一个applet,可以使用<PARAM>标签进行设置: <PARAM NAME="app.loglevel" VALUE="2"> 于是,为了设置日志记录级别,你所要做的一切就是获取属性值并对结果调用SetLogLevel方法: String strLevel = System.getProperty("app.loglevel"); If(strLevel != null) { int level = Integer.parseInt(strLevel); Logger.getInstance().setLogLevel(level); } 这种方法的好处在于: l 减少对象创建,也就是说,对象被重用 l 一个定义良好的API,可以鼓励所有的开发人员遵从一样的标准 l 可扩展性——单独的开发人员可以对这种事先进行调整以适应其自己的需要 l 通过使用标准的API减少了维护的开销 l 可在运行时定制的日志记录级别 通过自定义集合实现更好的性能 当需要存储一系列普通对象的时候,最简单的方法通常是使用java.util.Vector。这个类在其被使用的很多情况中的效率较低,其低效率主要有两个原因。第一个原因在于Vector是线程安全的;因此,它的很多方法是同步的。当你总是知道应用程序是单线程的时候,这种同步造成了不必要的开销。Vector效率不高的第二个原因是从中检索对象时所进行的类型转换(casting)数量,如果在Vector中所存储的对象具有相同的类型,就不需要类型转换。这样,为了获得更好的性能,我们需要类型确定的、单线程的集合。 StringVector.java(程序清单6)是一个String类型集合的示例实现。请记住这个类可用于所有类型的对象。 清单6:StringVector.java——String类型集合的示例实现 /* Copyright ? 2000 Stepping Stone Software Ltd, John Keyes */ public class StringVector { private String [] data; private int count; public StringVector() { this(10); // 缺省尺寸为10 } public StringVector(int initialSize) { data = new String[initialSize]; } public void add(String str) { // 忽略null字符串 if(str == null) { return; } ensureCapacity(count + 1); data[count++] = str; } private void ensureCapacity(int minCapacity) { int oldCapacity = data.length; if (minCapacity > oldCapacity) { String oldData[] = data; int newCapacity = oldCapacity * 2; data = new String[newCapacity]; System.arraycopy(oldData, 0, data, 0, count); } } public void remove(String str) { if(str == null) { return; // 忽略null字符串} for(int I = 0; I < count; I++) { // 查找匹配 if(data[I].equals(str)) { System.arraycopy(data,I+1,data,I,count-1); // 复制数据 data[--count] = null; return; } } } public final String getStringAt(int index) { if(index < 0) { return null; } else if(index > count) { return null; // index is > # strings } else { return data[index]; // index is good } } // not shown: size(), toStringArray() } 以前你可能在某处见过这样的代码: … Vector strings = new Vector(); strings.add("One"); strings.add("Two"); String second = (String)strings.elementAt(1); … 现在可以将其替换为: … StringVector strings = new StringVector(); strings.add("One"); strings.add("Two"); String second = strings.getStringAt(1); … 其结果是得到改善的性能。TestCollection.java(程序清单7)明显体现了这种性能的差异。StringVector类的add方法的执行时间只有Vector类的add方法的70%左右。而getStringAt方法的执行时间只有Vector类的elementAt方法的25%。 清单7:TestCollection.java——显著地体现了性能的差异 /* Copyright ? 2000 Stepping Stone Software Ltd, John Keyes */ import java.util.Vector; public class TestCollection { public static void main(String args []) { TestCollection collect = new TestCollection(); if(args.length == 0) { System.out.println( "Usage: java TestCollection [ vector | stringvector ]"); System.exit(1); } if(args[0].equals("vector")) { Vector store = new Vector(); long start = System.currentTimeMillis(); for(int I = 0; I < 1000000; I++) { store.addElement("string"); } long finish = System.currentTimeMillis(); System.out.println((finish-start)); start = System.currentTimeMillis(); for(int I = 0; I < 1000000; I++) { String result = (String)store.elementAt(I); } finish = System.currentTimeMillis(); System.out.println((finish-start)); } else if(args[0].equals("stringvector")) { StringVector store = new StringVector(); long start = System.currentTimeMillis(); for(int I = 0; I < 1000000; I++) { store.add("string"); } long finish = System.currentTimeMillis(); System.out.println((finish-start)); start = System.currentTimeMillis(); for(int I = 0; I < 1000000; I++) { String result = store.getStringAt(I); } finish = System.currentTimeMillis(); System.out.println((finish-start)); } } } 可以对这种技术进行修改以使其能够适应你正在从事的应用程序的要求。例如,你可以创建InterVerctor、EmployeeVector等等。 结束语 本文决不是关于Java程序性能的“圣经”。其目的是让你知道可以通过对你的Java代码做一些细小的改动来提升其性能。 相关资源 TowerJ: http://www.towerj.com/ Jrockit: http://www.jrockit.com/ Java虚拟机说明: http://java.sun.com/docs/books/vmspec 注释 [1] 如http://java.sun.com/docs/books/vmspec/2nd-edition.htm/Concepts.doc.htm#19124 所讲述的:载入一个含有String常量的类或接口可能会创建一个新的String对象表示这个常量。本文假定会创建新的String来表示常量。 [2] 例3执行10万次平均用时578毫秒,例4执行10万次平均用时265毫秒(在我的计算机上测量) [3] –D开关被大多数JVM所使用,Microsoft的Jview解释器使用/d:开关。 关于作者 John Keyes是Stepping Stone软件有限公司的资深开发人员。他以前曾在IONA Technologies公司工作。可以通过johnkeyes@yahoo.com与他联系。
 
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |