javaGrowing

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  92 随笔 :: 33 文章 :: 49 评论 :: 0 Trackbacks

#

用Java解决国际化问题


首都经贸大学信息学院 尹海琴
01-7-18 上午 09:11:22


如果应用系统是面向多种语言的,编程时就不得不设法解决国际化问题,包括操作界面的风格问题、提示和帮助语言的版本问题、界面定制个性化问题等。
由于Java语言具有平台无关、可移植性好等优点,并且提供了强大的类库,所以Java语言可以辅助我们解决上述问题。Java语言本身采用双字节字符编 码,采用大汉字字符集,这就为解决国际化问题提供了很多方便。从设计角度来说,只要把程序中与语言和文化有关的部分分离出来,加上特殊处理,就可以部分解 决国际化问题。在界面风格的定制方面,我们把可以参数化的元素,如字体、颜色等,存储在数据库里,以便为用户提供友好的界面;如果某些部分包含无法参数化 的元素,那么我们可能不得不分别设计,通过有针对性的编码来解决具体问题。
Java类包
在用Java解决国际化问题的过程中,可能利用到的主要的类都是由java.util包提供的。该类包中相关的类有Locale、 ResourceBundle、ListResourceBundle、PropertyResourceBundle等,其继承关系如下图所示。
其中各类提供的主要功能如下:
Locale:该类包含对主要地理区域的地域化特征的封装。其特定对象表示某一特定的地理、政治或文化区域。通过设定Locale,我们可以为特定的国家 或地区提供符合当地文化习惯的字体、符号、图标和表达格式。例如,我们可以通过获得特定Locale下的Calendar类的实例,显示符合特定表达格式 的日期。
ResourceBundle:该类是一个抽象类,需要通过静态方法ResourceBundle.getBundle()指定具体实现类或属性文件的基 本名称。基本名称会协同指定的或默认的Locale类,决定具体调用的类或属性文件的唯一名称。例如:指定基本类或属性文件名称为TestBundle, 而指定的Locale是CHINESE,那么最适合匹配的类名称为TestBundle_zh_CN.class,而最佳匹配属性文件名称为 TestBundle_zh_CN.properties。按照Java Doc和相关文档的要求,如果该类或属性文件没有找到,系统会查找近似匹配(主文件名依次为TestBundle_zh和TestBundle的类或属性 文件)。该类提供的getKeys()方法用于获得所有成员的键名,并提供handleGetObject方法获得指定键的对应元素。
ListResourceBundle:该类继承ResourceBundle类,主要是增加了一些便于操作的成分,但还是抽象类。如果希望使用类的方式实现具体的ResourceBundle,一般情况下最好继承这个类。
PropertyResourceBundle:该类也继承ResourceBundle类,可以实例化。该类的行为特征如同java.util.properties类,可以从输入流中获得具体属性对。
如果涉及日期和时间显示等问题时,可以利用java.text包以及java.util包中的TimeZone、SimpleTimeZone和Calendar等类进行辅助处理。
参数化解决方法
在具体应用时,可以把具体国家或地区特征中可以参数化的部分放在经过特殊命名的属性文件中,在确定具体的Locale后,通过PropertyResourceBundle类读取相应的属性文件,实现国际化特征。
使用PropertyResourceBundle类获得当地版本的国际化信息,部分代码如下:
  ……
  public static final String BASE_PROP_FILE =
“DISP”;
  public static final String SUFFIX =
“.properties”;
  locale = Locale.getDefault();
  String propFile = BASE_PROP_FILE + “_” + locale.toString()+ SUFFIX;
  ResourceBundle rb;
  try {
   File file = new File(propFile);
   if (file.exists()) {
   is = new FileInputStream(file);
   rb = new PropertyResourceBundle(is);
   if (rb == null) System.out.println(“No Resource”);
   }
  } catch (IOException ioe) {
   System.out.println(“Error open file named ” + propFile);
  }
  Enumeration e = rb.getKeys();
  while (e.hasMoreElements()){
   key = (String)e.nextElement();
   value = (String)rb.handleGetObject(key);
   System.out.println(“KEY: ” + key +
“\t\t Value: ” + value);
  }
  ……
  DISP_zh_TW.properties文件的具体内容如下:
  Key1=\u53ef\u4ee5
  Key2=\u64a4\u9500
等号后面是利用native2ascii程序转化后的繁体汉字,如果不进行转化,系统可能显示乱码。
处理提示和帮助
对于提示语言和帮助文件部分,可以把语言映射放在属性文件或者ListResourceBundle类的子类中。下面程序是一个Servlet,它通过接受客户端的选择,把特定语言和字符版本的信息返回到客户端。
  ……
  public class ProcessServlet extends HttpServlet
  { //默认语言为中文
   public static final String DEFAULT_LANGUAGE = “zh”;
   //默认字符集为简体中文
   public static final String DEFAULT_COUNTRY = “CN”;
   public void service(HttpServletRequest req,
HttpServletResponse res) throws IOException, ServletException {
   HttpSession session = req.getSession(true);
   // 从客户端收到的指定语言和字符的参数应当与Sun公司相关规定一致
   String lang = req.getParameter
(“language”);
   String country = req.getParameter
(“country”);
   if (lang == null)
    {
//如果没有收到参数,就试图从Session里获得
   lang = (String) session.getAttribute
(“language”);
   country = (String) session.getAttribute
(“country”)
   } else {
   session.setAttribute(“language”, lang);
   session.setAttribute(“country”, country);
   }
   if (lang == null)
    {
//如果无法从上述手段得到语言和字符信息,就使用默认值
   lang = DEFAULT_LANGUAGE;
   country = DEFAULT_COUNTRY
   session.setAttribute(“language”, lang);
    session.setAttribute(“country”, country);
   }
   Locale locale = null;
   ResourceBundle bundle = null;
   try {
   locale = new Locale(lang, country);
   } catch (Exception e) {
   System.out.println(“No locale with” +
country + “_” + lang);
   locale = Locale.getDefault();
   }
   try {
   bundle = ResourceBundle.getBundle(
“DisplayList”, locale);
   } catch( MissingResourceException e) {
   System.out.println( “No resources available for locale ” + locale);
   bundle = ResourceBundle.getBundle
(“DisplayList”, Locale.US);
   }
   res.setContentType(“text/html”);
   PrintWriter out = res.getWriter();
   out.println(“<html>”);
   out.println(“<head>”);
   String title = bundle.getString(“title”);
  String welcome =bundle.getString
(“welcome”);
   String notice = bundle.getString(“notice”);
   out.println(“<title>”+ title +
“</title>”);
   out.println(“</head>”);
   out.println(“<body bgcolor=\”
white\“>”);
   out.println(“<h3>” + welcome +
“</h3>”);
   out.println(“<br>”);
   out.println(“<b>” + notice +
“</b>”);
   out.println(“</body>”);
   out.println(“</html>”);
   }
  }
上述Servlet使用的属性文件(DisplayList_zh_CN.
properties)内容如下:
title=中文版
welcome=这是简体中文版面
notice=简体中文测试成功
注意:该文件直接采用了中文,而不是经过转化的Unicode编码,这是由于大多数Web服务器不需要上述转化。
在实际使用中,如果Web服务器支持Servlet 2.3规范(如jakarta-tomcate 4.0),那么上面提到的Servlet应当稍加改变,以作为其他Servlet的处理器使用。另外,如果把ResourceBundle的特定版本存放 在无状态会话Bean中,就可以在一定程度上提高程序效率。
小 结
笔者在实际测试中发现了如下问题,其中部分问题得到了解决:
1. 对于显示字符出现乱码的问题,如果是通过属性文件实现国际化解决方案,那么可能是直接在属性文件中写入了非标准ASCII文字。解决方法是利用JDK提供 的工具native2ascii.exe扫描所有属性文件,用扫描结果覆盖原有文件内容。如果我们是利用类文件实现转换方案,那么需要重新编译相关类文 件,并在编译时指定编码集。例如,编译使用国标码的类文件,采用的编译命令如下:
javac -encoding GB2312 your_java_file
2. 虽然Sun宣称,在ResourceBundle类的实例化过程中,该类会查找与指定的基础类绝对匹配和尽量与指定的Locale属性相匹配的类。例如: 如果我们指定ResourceBundle基础类为TestBundle,而Locale中指定使用zh_CN(中国大陆地区简体中文),那么如果系统找 不到TestBundle_zh_CN,系统应当顺次查找TestBundle_zh、TestBundle。但是笔者在系统开发过程中发现,该匹配没有 产生任何实际效果。
笔者的测试平台是Windows 2000 Server,没有配置任何Service Pack,使用的JDK版本是1.3.0版本。笔者试图通过查看JDK目录下src.jar中附带的源码找到引起问题的原因,但是发现有关的操作被封装在 sun.misc包中,而src.jar文件没有提供该包中任何类的源码。本文把这个问题提出来,希望与有关开发人员一起探讨。
posted @ 2005-12-14 10:57 javaGrowing 阅读(385) | 评论 (0)编辑 收藏

     摘要: 侯捷观点 Java反射机制   摘要 Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fie...  阅读全文
posted @ 2005-12-09 16:58 javaGrowing 阅读(933) | 评论 (1)编辑 收藏

认识.NET的集合 - 开发者 - ZDNet China


认识.NET的集合

作者: BUILDER.COM
Wednesday, May 15 2002 11:06 AM

 集合(collection)提供了一种结构化组织任意对象的方式,而且我们早就知道集合在日常编程工作中的重要性。.NET类库提供了丰富的集合数据类型,其种类之繁多甚至使许多人看得眼都花了,这些集合对象都具有各自的专用场合。不管怎么说,更多的选择也就意味着更高的灵活性,但同时也意味着更高的复杂性。因此,对集合各个类型的用途和使用条件具有适度的了解是完全必要的。下面就请随我进行一场.NET集合之旅吧!

.NET集合定义


从.NET的角度看,所谓的集合可以定义为一种对象,这种对象实现一个或者多个System.Collections.ICollectionSystem.Collections.IDictionarySystem.Collections.IList接口。这一定义把System.Collections名称空间中的“内置”集合划分成了三种类别:

  • 有序集合:仅仅实现ICollection接口的集合,在通常情况下,其数据项目的插入顺序控制着从集合中取出对象的的顺序。System.Collections.Stack和 System.Collections.Queue类都是ICollection集合的典型例子。
  • 索引集合:实现Ilist的集合,其内容能经由从零开始的数字检索取出,就象数组一样。System.Collections.ArrayList对象是索引集合的一个例子。
  • 键式集合:实现 IDictionary 接口的集合,其中包含了能被某些类型的键值检索的项目。IDictionary集合的内容通常按键值方式存储,可以用枚举的方式排序检索。 System.Collections.HashTable类实现了IDictionary 接口。

正如你看到的那样,给定集合的功能在很大程度上受到特定接口或其实现接口的控制。如果你对面向对象编程缺乏了解,那么你可能对上面说的这些话感到难以理解。不过你至少应该知道,以接口这种方式构造对象的功能不但造就了具有整套类似方法的对象族,而且还能让这些对象在必要的情况下可以当作同类,以OOP(面向对象编程)的术语来说,这就是大名鼎鼎的多态性技术。

System.Collections概述

System.Collections名称空间包含了在你的应用程序中可以用到的6种内建通用集合。另一些更为专业化的集合则归属于System.Collections.Specialized,在某些情况下你会发现这些专用集合也是非常有用的。加上一些异常(exception)类,这些专业化集合在功能上和内建集合是类似的。现在就让我们审视一下通用集合以及少量的不太富于专业化的集合。

堆栈和队列

System.Collections.Stack 和 System.Collections.Queue 类,两者仅仅实现了ICollection 接口,按照存储项目加到集合的顺序保存System.Object类型的项目。对象只能按其加入顺序从集合中检索:堆栈是后进先出,而队列则是先进先出。通常情况下,你在以下场合可以考虑采用以上这些集合:

  • 接收和处理集合内项目时顺序比较重要。
  • 你能在处理项目之后丢弃它。
  • 你不需要访问集合中的任意项目。

ArrayList

System.Collections.ArrayList类,仅仅实现 Ilist,最适合描述为一种正常数组和集合的混合类型。ArrayList按照项目被加入集合的顺序存储项目。每个项目都被分配一个索引标识符而且能由关联它们的索引数字以任何顺序被检索。当新项目加入集合时会扩大ArrayList从而令其相比普通数组更具灵活性。然而,ArrayList负载比传统数组更大而且没有实现严格的类型化,也就可以接受任何转换为System.Object的对象(换句话说,对什么东西都来者不拒)。

SortedList

System.Collections.SortedList,它实现了IDictionary和ICollection接口,是最基本的排序集合,与Vb6下的Collection对象非常类似。SortedList存储对象并按照关联的键值对这些存储对象排序。它们也是同时支持索引数字和键对象检索的唯一内建的.NET集合。

HashTable

强有力的System.Collections.HashTable集合实现了IDictionary 和 Icollection,能用来存储多种类型的对象连同关联的唯一字符串键值。在HashTable集合中的项目按照源自其键值的哈希代码所确定的顺序存储。集合内每个对象的键值都必须唯一,而其哈希代码则不一定唯一。


什么是哈希代码?
哈希代码实质上就是从一快数据中消除所有冗余部分之后的结果,它主要起到对数据辅助分类或排序的作用。

当某个项目加入集合时,HashTable即调用键值的GetHashCode方法,由于所有的类都是从System.Objec继承的,所以调用该方法即可确定该类的哈希代码并且按该代码排序存储。你可以强迫使用定制的哈希函数,方法有二,一是重载类的GetHashCode方法,二是向HashTable构造器传递实现了System.Collections.IHashcodeProvider接口的对象,在这种情况下,该对象将用于为所有加入集合的键值产生哈希代码。

从性能的角度看,因为键值搜索仅限于具有同样哈希代码的键值,所以HashTable能够很快地从集合中检索任意一个元素,从而减少了必须通过检查以发现匹配的键值的数量。然而,因为插入到集合中的每个对象-键值对都必须产生相应的哈希代码,所以项目插入的代价就有点高了。因此,HashTable主要运用在按照任意键值反复检索大量相对静态的数据这一场合下。

ListDictionary 和 HybridDictionary

ListDictionary 和 HybridDictionary 类归属于System.Collections.Specialized。它们都在按照唯一键值的原则来组织项目,而且都实现了 IDictionary 和 ICollection 。ListDictionary在内部以链表的方式存储项目,建议用在不会增长超过10个项目的集合中。HybridDictionary采用一个内部链表(实际上就是ListDictionary)作为小集合,当集合变得足够大(超过10个项目)以至于链表实现效率降低时就会转换为HashTable。

StringCollection 和 StringDictionary

System.Collections.Specialized.StringCollection 和 System.Collections.Specialized.StringDictionary 都对存储字符串的集合进行了优化。 StringCollection实现了 IList 和 ICollection 而且实质上就是ArrayList,只不过实现了强烈的类型化仅仅接受字符串而已。StringCollection最理想的应用场合是经常更新或增加的少量数据,而StringDictionary则最适用于不经常增加项目到诸如HashTable之类集合中的大量数据。

NameValueCollection

System.Collections.Specialized.NameValueCollection最有趣的地方在于它能包含关联同一键值的多个项目,这正是它与其他内建集合的差别所在。除此以外,它在功能上类似HashTable,按照源自每一项目键值的哈希代码对项目排序从而也具有类同的优缺点。

存在的问题

如果说由 .NET 类库所提供的内建集合也存在问题的话,那多半是它们几乎都在内部把项目存储为System.Object.类型。从最大灵活性的角度看那是一个好想法,但同时也给采用这些通用集合的程序员提出了一些问题。首先,只要你把一个新项目加到集合中去,运行时就必须实施类型转换操作(创建值类型的索引以便可以当作对象引用)。这是一种低效的操作而且在处理大型集合时会产生相当可观的性能问题。其次,只要你访问通用集合中的一个项目,该项目都将作为System.Object类型被返回,这就意味着你不得不把它转换为真实的类型才能对其进行有意义的操作。

责任编辑:炒饭

posted @ 2005-12-09 11:32 javaGrowing 阅读(352) | 评论 (0)编辑 收藏

数组与其它容器的区别体现在三个方面:效率,类型识别以及可以持有primitives.

数组是java提供的,是能随机存储和访问reference序列的诸多方法中,最高效的一种。数组是线形序列,所以它可以快速访问其中的元素,但速度是有代价的,当你创建了一个数组之后它的容量就固定了,而且在其生命周期里不能改变。也许你会提议先创建一个数组,等到快不够用的时候,再创建一个新的,然后将旧数组里的reference 全部导到新的里面。其实ArrayList 就是这么做的。但是这种灵活性所带来的开销,使得ArrayList 的效率比       起数组有了明显下降。      

在我们写程序的时候往往不知道要用多少对象,或者要用一种更复杂方式来存储对象情况。为此,Java 提供了“容器类(container class)”。其基本类型有List, Set Map。有了这些工具,你就能解决很多问题了。它们还有一些别的特性。比方说Set 所持有的对象,个个都不同,Map则是一个“关联性数组(associative array)”,它能在两个对象之间建立联系。此外,与数组不同,它们还能自动调整大小,所以你可以往里面放任意数量的对象。这样写程序的时候,就不用操心要开多大的空间了。

 

Java2 的容器类要解决“怎样持有对象”,而它把这个问题分成两类:

1. Collection: 通常是一组有一定规律的独立元素。List 必须按照特定的顺序持有这些元素,而Set 则不能保存重复的元素。(bag没有这个限制,但是Java的容器类库没有实现它,因为List 已经提供这种功能了。)

2. Map: 一组以“键——值”(key-value)形式出现的pair。初看上去,它应该是一个pairCollection,但是真这么去做的话,它就会变得很滑稽,所以还是把这个概念独立列出来为好。退一步说,真的要用到Map 的某个子集的时候,创建一个Collection 也是很方便的。Map可以返回“键(key)的”Set,值的Collection,或者pairSet。和数组一样,Map 不需要什么修改,就能很容易地扩展成多维。你只要直接把Map 的值设成Map 就可以了(然后它的值再是Map,以此类推)。我们先来看看容器的一般特性,然后深入细节,最后再看什么会有这么多版本,以及如何进行选择。

 

List 会老老实实地持有你所输入的所有对象,既不做排序也不做编辑。Set 则每个对象只接受一次,而且还要用它自己的规则对元素进行重新排序(一般情况下,你关心的只是Set 包没包括某个对象,而不是它到底排在哪里——如果是那样,你最好还是用List)。而Map 也不接收重复的pair,至于是不是重复,要由key来决定。此外,它也有它自己的内部排序规则,不会受输入顺序影响。如果插入顺序是很重要的,那你就只能使用LinkedHashSet LinkedHashMap 了。

test.bmp

第一眼看到这张图的时候,你会觉得很震撼。不过你马上就会知道,实际上只有三种容器组件——Map,List 和Set,而每种又有两到三个实现。最常用的几个容器已经用粗黑线框了起来。看到这里,这张图就不再那么令人望而生畏了。
用点号框起来的是interface,用虚线框起来的是abstract 类,实线
则表示普通的(“实体concrete”)类。点线的箭头表示类实现了这个interface(或者,abstract 类表示部分实现了这个interface)。实线
箭头表示这个类可以制造箭头所指的那个类的对象。比如,Collection
能制造Iterator,而List 还能制造ListIterator(也能制造Iterator,因为List 是继承自Collection 的)。
与存放对象有关的接口包括Collection,List,Set 和Map。在理想情况下,绝大多数代码应该只同这些接口打交道,只是在创建容器的时候才要精确地指明它的确切类型。所以你可以这样创建一个List。
List x = new LinkedList( );

当然,你也可以选择让x 成为LinkedList(而不是泛型的List),这样x 就带上了准确的类型信息interface 的优雅 (同时也是它的本意)就在于,你想修改具体的实现的时候,只要改一下创建的声明就可以了,就
像这样:
List x = new ArrayList( );
无需惊动其它代码(用迭代器也能获得一些这种泛型性)。这个类系里面有很多以“Abstract”开头的类,初看起来这可能会让人有点不明白。实际上它们只是一些部分实现某个接口的办成品。假如你要编一个你自己的Set,不要从Set 接口开始挨个实现它的方法;相反你最好继承AbstractSet,这样就能把编程的工作量压缩到最低了。但是,实际上容器类库的功能已经够强的了,我们要求的事情它几乎都能做
到。所以对我们来说,你完全可以忽略以“Abstract”开头的类。

List 的功能
正如你从ArrayList 那里所看到的,List 的基本用法是相当简单的。虽然绝大多数时候,你只是用add( )加对象,用get( )取对象,用iterator( )获取这个序列的Iterator,但List 还有一些别的很有用的
方法。
实际上有两种List:擅长对元素进行随机访问的,较常用的ArrayList,和更强大的LinkedList。LinkedList 不是为快速的随机访问而设计的,但是它却有一组更加通用的方法。

List (接口) List 的最重要的特征就是有序;它会确保以一定的顺序保存元素。List 在Collection 的基础上添加了大量方法,使之能在序列中间插入和删除元素。(只对LinkedList 推荐使用。)List 可以制造ListIterator 对象,你除了能用它在List 的中间插入和删除元素之外,还能用它沿两个方向遍历List。
ArrayList*一个用数组实现的List。能进行快速的随机访问, 但是往列表中间插入和删除元素的时候比较慢。ListIterator 只能用在反向遍历ArrayList 的场 合,不要用它来插入和删除元素,因为相比LinkedList,在ArrayList 里面用ListIterator 的系统开销比较高。
LinkedList对顺序访问进行了优化。在List 中间插入和删除元 素的代价也不高。随机访问的速度相对较慢。(用ArrayList 吧。)此外它还有addFirst( ), addLast( ),getFirst( ),getLast( ), removeFirst( )和removeLast( )等方法(这些 方法,接口和基类均未定义),你能把它当成栈(stack),队列(queue)或双向队列(deque)来用。 下面这段程序把各种操作都集中到方法里面:List 都能作的事(basicTest( )),用Iterator 在列表中移动(iterMotion( )),修改 列表的元素(iterManipulation( )),查看List 的操作结果(testVisual( )),以及LinkedList 所独有的方法。
Set 的功能
Set 的接口就是Collection 的,所以不像那两个List,它没有额外的
功能。实际上Set 确确实实就是一个Collection——只不过行为方式不
同罢了。(这是继承和多态性的完美运用:表达不同地行为。)Set 会拒绝
持有多个具有相同值的对象的实例(对象的“值”又是由什么决定的呢?
这个问题比较复杂,我们以后会讲的)。
Set (接口)加入Set 的每个元素必须是唯一的;否则, Set 是不会把它加进去的。要想加进Set, Object 必须定义equals( ),这样才能标明对象的唯一性。Set 的接口和Collection 的
一模一样。Set 的接口不保证它会用哪种顺序来存储元素。
HashSet* 为优化查询速度而设计的Set。要放进HashSet 里面的Object 还得定义hashCode( )。
TreeSet 是一个有序的Set,其底层是一棵树。这样你 就能从Set 里面提取一个有序序列了。
LinkedHashSet(JDK 1.4) 一个在内部使用链表的Set,既有HashSet 的查询速度,又能保存元素被加进去的顺序(插入顺序)。用Iterator 遍历Set 的时候, 它是按插入顺序进行访问的。
Map 的功能
ArrayList 能让你用数字在一个对象序列里面进行选择,所以从某种意义上讲,它是将数字和对象关联起来。但是,如果你想根据其他条件在一个对象序列里面进行选择的话,那又该怎么做呢?从概念上讲,它看上去像是一个ArrayList,但它不用数字,而是用另一个对象来查找对象!这是一种至关重要的编程技巧。这一概念在Java 中表现为Map。put(Object key, Object value)方法会往Map 里面加一个值,并且把这个值同键(你查找时所用的对象)联系起来。给出键之后,get(Object key)就会返回与之相关联的值。
你也可以用containsKey( ) 和 containsValue( )测试Map 是否包含有某个键或值。
Java 标准类库里有好几种Map:HashMap,TreeMap, LinkedHashMap,WeakHashMap,IdentityHashMap。
它们都实现了Map 的基本接口,但是在行为方式方面有着明显的差异。这些差异体现在,效率,持有和表示对象pair 的顺序,持有对象的时间长短,以及如何决定键的相等性。性能是Map 所要面对的一个大问题。如果你知道get( )是怎么工作的,你就会发觉(比方说)在ArrayList 里面找对象会是相当慢的。而这
正是HashMap 的强项。它不是慢慢地一个个地找这个键,而是用了一种被称为hash code的特殊值来进行查找的。散列(hash)是一种算法,它会从目标对象当中提取一些信息,然后生成一个表示这个对象的“相对
独特”的int。hashCode( )是Object 根类的方法,因此所有Java对象都能生成hash code。HashMap 则利用对象的hashCode( )来进行快速的查找。这样性能就有了急剧的提高。

Map (接口)维持键-值的关联(即pairs),这样就能用键来找值了。
HashMap* 基于hash表的实现。(用它来代替Hashtable。)提供时间恒定的插入与查询。在构造函数中可以设置 hash表的capacity 和load factor。可以通过构造 函数来调节其性能。
LinkedHashMap(JDK 1.4) 很像HashMap,但是用Iterator 进行 遍历的时候,它会按插入顺序或最先使用 的顺序(least-recently-used (LRU) order)进行访问。除了用Iterator 外, 其他情况下,只是比HashMap 稍慢一 点。用Iterator 的情况下,由于是使用 链表来保存内部顺序,因此速度会更快。
TreeMap 基于红黑树数据结构的实现。当你查看键 或pair 时,会发现它们是按顺序 (根据Comparable 或Comparator,我们过 一会讲)排列的。TreeMap 的特点是,你 所得到的是一个有序的Map。TreeMap 是Map 中唯一有subMap( )方法的实 现。这个方法能让你获取这个树中的一部 分。
WeakHashMap 一个weak key的Map,是为某些特殊问 题而设计的。它能让Map 释放其所持有的 对象。如果某个对象除了在Map 当中充当 键之外,在其它地方都没有其reference 的话,那它将被当作垃圾回收。
IdentityHashMap(JDK 1.4) 一个用==,而不是equals( )来比较键 的hash map。不是为我们平常使用而设 计的,是用来解决特殊问题的。 散列是往Map 里存数据的常用算法。有时你会需要知道散列算法的工作 细节,所以我们会稍后再讲。
posted @ 2005-12-09 11:09 javaGrowing 阅读(2719) | 评论 (1)编辑 收藏

"^\d+$"  //非负整数(正整数 + 0)

"^[0-9]*[1-9][0-9]*$"  //正整数

"^((-\d+)|(0+))$"  //非正整数(负整数 + 0)

"^-[0-9]*[1-9][0-9]*$"  //负整数

"^-?\d+$"    //整数

"^\d+(\.\d+)?$"  //非负浮点数(正浮点数 + 0)

"^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$"  //正浮点数

"^((-\d+(\.\d+)?)|(0+(\.0+)?))$"  //非正浮点数(负浮点数 + 0)

"^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$"  //负浮点数

"^(-?\d+)(\.\d+)?$"  //浮点数

"^[A-Za-z]+$"  //由26个英文字母组成的字符串

"^[A-Z]+$"  //由26个英文字母的大写组成的字符串

"^[a-z]+$"  //由26个英文字母的小写组成的字符串

"^[A-Za-z0-9]+$"  //由数字和26个英文字母组成的字符串

"^\w+$"  //由数字、26个英文字母或者下划线组成的字符串

"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$"    //email地址

"^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$"  //url

/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/ // 年-月-日

/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年

"^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$" //Emil

"(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)?" //电话号码

"^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$" //IP地址

匹配中文字符的正则表达式: [\u4e00-\u9fa5]

匹配双字节字符(包括汉字在内):[^\x00-\xff]

匹配空行的正则表达式:\n[\s| ]*\r

匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/

匹配首尾空格的正则表达式:(^\s*)|(\s*$)

匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

匹配网址URL的正则表达式:^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$

匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

匹配国内电话号码:(\d{3}-|\d{4}-)?(\d{8}|\d{7})?

匹配腾讯QQ号:^[1-9]*[1-9][0-9]*$

下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。

^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的Multiline 属性,^ 也匹配 ’\n’ 或 ’\r’ 之后的位置。

$ 匹配输入字符串的结束位置。如果设置了 RegExp 对象的Multiline 属性,$ 也匹配 ’\n’ 或 ’\r’ 之前的位置。

* 匹配前面的子表达式零次或多次。

+ 匹配前面的子表达式一次或多次。+ 等价于 {1,}。

? 匹配前面的子表达式零次或一次。? 等价于 {0,1}。

{n} n 是一个非负整数,匹配确定的n 次。

{n,} n 是一个非负整数,至少匹配n 次。

{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗号和两个数之间不能有空格。

? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。

. 匹配除 "\n" 之外的任何单个字符。要匹配包括 ’\n’ 在内的任何字符,请使用象 ’[.\n]’ 的模式。

(pattern) 匹配pattern 并获取这一匹配。

(?:pattern) 匹配pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。

(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。

(?!pattern) 负向预查,与(?=pattern)作用相反

x|y 匹配 x 或 y。

[xyz] 字符集合。

[^xyz] 负值字符集合。

[a-z] 字符范围,匹配指定范围内的任意字符。

[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。

\b 匹配一个单词边界,也就是指单词和空格间的位置。

\B 匹配非单词边界。

\cx 匹配由x指明的控制字符。

\d 匹配一个数字字符。等价于 [0-9]。

\D 匹配一个非数字字符。等价于 [^0-9]。

\f 匹配一个换页符。等价于 \x0c 和 \cL。

\n 匹配一个换行符。等价于 \x0a 和 \cJ。

\r 匹配一个回车符。等价于 \x0d 和 \cM。

\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。

\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

\t 匹配一个制表符。等价于 \x09 和 \cI。

\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

\w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。

\W 匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。

\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。

\num 匹配 num,其中num是一个正整数。对所获取的匹配的引用。

\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。

\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。

\un 匹配 n,其中 n 是一个用四个十六进制数字表示的Unicode字符。

匹配中文字符的正则表达式: [u4e00-u9fa5]

匹配双字节字符(包括汉字在内):[^x00-xff]

应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

String.prototype.len=function(){return this.replace([^x00-xff]/g,"aa").length;}

匹配空行的正则表达式:n[s| ]*r

匹配HTML标记的正则表达式:/<(.*)>.*|<(.*) />/

匹配首尾空格的正则表达式:(^s*)|(s*$)

应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现,如下:

String.prototype.trim = function()

{ return this.replace(/(^s*)|(s*$)/g, "");

} 利用正则表达式分解和转换IP地址:

下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的Javascript程序:

function IP2V(ip)

{ re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正则表达式 if(re.test(ip)) { return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1 } else { throw new Error("Not a valid IP address!") } }

不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:

var ip="10.100.20.168"

ip=ip.split(".")

alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))

匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*

匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?

利用正则表达式去除字串中重复的字符的算法程序:

var s="abacabefgeeii" var s1=s.replace(/(.).*1/g,"$1") var re=new RegExp("["+s1+"]","g") var s2=s.replace(re,"") alert(s1+s2) //结果为:abcefgi

我原来在CSDN上发贴寻求一个表达式来实现去除重复字符的方法,最终没有找到,这是我能想到的最简单的实现方法。思路是使用后向引用取出包括重复的字符,再以重复的字符建立第二个表达式,取到不重复的字符,两者串连。这个方法对于字符顺序有要求的字符串可能不适用。

得用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1

s="http://www.9499.net/page1.htm" s=s.replace(/(.*/){0,}([^.]+).*/ig,"$2") alert(s) 利用正则表达式限制网页表单里的文本框输入内容:

用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^u4E00-u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^u4E00-u9FA5]/g,''))"

用 正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^uFF00-uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^uFF00-uFFFF]/g,''))"

用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))"

用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))"

posted @ 2005-12-08 13:53 javaGrowing 阅读(473) | 评论 (0)编辑 收藏

仅列出标题
共19页: First 上一页 11 12 13 14 15 16 17 18 19 下一页