跟我学Java入门到精通培训教程—— Java2 对应用系统中的国际化相关技术的支持及应用实例(第2部分)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.1Java2 对应用系统中的国际化相关技术的支持及应用实例(第2部分)1.1.1利用资源字串解决程序中的显示的文字语言种类
1、ListResourceBundle类的主要作用
java.util.ListResourceBundle类可以用来载入任意的非字符串的資源对象,从而可以应用ListResourceBundle 类来提供不同语言环境下的资源。
2、ListResourceBundle类的应用要求
1)该类的类名应该以“类名_语言_国家”格式来命名;
2)该类要继承java.util.ListResourceBundle类并且要重写getContents()方法并返回资源
key-value数组(在类中将我們的区域化资源存储成一个static final 的二维Object 数
组,然后將資源的属性名称,以及資源的值存储在Object数组中,并重写getContents() 方法,传回此二维数组)。
3、各种语言的資源类的定义示例
(1)下面的类主要是为英文提供
public class JavaWord_en_US extends java.util.ListResourceBundle {
static final Object[][] contents = {
{ " window_title", "Java Window Explorer" },
{ "KeyName2", "Value2" }
};
public Object[][] getContents() {
return contents;
}
}
(2)而下面的类主要是为中文(中国台湾地区)提供
public class JavaWord_zh_TW extends java.util.ListResourceBundle {
static final Object[][] contents = {
{ "名称1", "对应的值1" },
{ "名称2", "对应的值2" },
};
public Object[][] getContents(){
return contents;
}
}
由于区域化資源是存儲在类中的,且是使用Object 数组來存儲,这表示我們現在可以存儲各种各样的区域化对象,而不只是字符串,例如我們可以存儲区域化的「語音」以及「图形」等等。
ResourceBundle 提供一个getObject() 方法让我們可以取得非字串的資源。
且因为这些.java 会被编译成.class ,因此我们可以直接在ListResourceBundle 中写入中文,最后这些中文会以Unicode 的编码方式儲存在.class 中,不再需要使用象使用属性文件那样采用native2ascii 來做编码转换。
4、利用ListResourceBundle类实现资源类的应用例
(1)实现的基本思路
主要的实现方法是从ListResourceBundle类来继承并在该子类中必须提供重载getContents 方法和一个对象数组,数组里面包含了资源的Keys和相应的Values。
(2)程序例的主要功能
显示一个有一个按钮和一个菜单的Dialog窗体,在改变其国家和语言等种类时,可以显示出不同的界面。
(3)应用代码ListResourceBundleDemo.java(在Java国际化Examp目录下)
package com.px1987.javaapplication.i18n;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ListResourceBundleDemo extends JFrame implements ActionListener{
JMenuItem menuExit=null;
ResourceBundle res=null;
Font font=null;
public ListResourceBundleDemo(){
super();
this.setSize(200,200);
Locale currentLocale=Locale.getDefault();
res = ResourceBundle.getBundle("com.px1987.javaapplication.i18n.Res", currentLocale);
JMenuBar menuBar=new JMenuBar();
this.setJMenuBar(menuBar);
JMenu menuFile=new JMenu();
menuExit=new JMenuItem();
menuExit.addActionListener(this);
menuFile.setText(res.getString("FileMenuText"));
menuExit.setText(res.getString("FileExitMenuText"));
font = new Font(res.getString("FontName"),Font.PLAIN,12);
menuFile.setFont(font);
menuExit.setFont(font);
menuFile.add(menuExit);
menuBar.add(menuFile);
}
public static void main(String args[]) throws Exception{
ListResourceBundleDemo demoFrame=new ListResourceBundleDemo();
demoFrame.show();
}
public void actionPerformed(ActionEvent parm1) {
if(parm1.getSource()==this.menuExit){
JDialog dialog=new JDialog();
JButton btOK=new JButton();
btOK.setText(res.getString("OKText"));
dialog.setTitle(res.getString("DialogTitle"));
btOK.setFont(font);
dialog.getContentPane().setLayout(new FlowLayout());
dialog.getContentPane().add(btOK);
dialog.setSize(200,100);
dialog.setModal(true);
dialog.show();
}
}
}
(4)英文资源类代码Res_en_US.java
package com.px1987.javaapplication.i18n;
import java.util.*;
/* Res_en_US和Res_zh_CN必须定义为public类,否则无法访问它*/
public class Res_en_US extends java.util.ListResourceBundle{ public static final Object[][] contents = new String[][] {
{ "OKText", "OK" },
{ "FontName", "Dialoginput" },
{ "FileMenuText", "File"},
{ "FileExitMenuText", "Open A Dialog"},
{ "DialogTitle", "Demo Dialog" }
};
public Object[][] getContents() {
return contents;
}
}
(5)中文Res_zh_CN.java
package com.px1987.javaapplication.i18n;
import java.util.*;
/* Res_en_US和Res_zh_CN必须定义为public类,否则无法访问他*/
public class Res_zh_CN extends java.util.ListResourceBundle{ public static final Object[][] contents = new String[][]{
{ "OKText", "确定" },
{ "FontName", "宋体" },
{ "FileMenuText", "文件"},
{ "FileExitMenuText", "打开对话框"},
{ "DialogTitle", "演示对话框" }
};
public Object[][] getContents(){
return contents;
}
}
(6)所应该要注意的问题
如果我们同时在程序中有資源类文件以及資源属性Messages.properties文件,当我們使用ResourceBundle.getBundle("Messages") 时,ResourceBundle 类会首先采用資源类Messages.java 中所提供的資源,传回ListResourceBundle 对象,而不是PropertyResourceBundle 对象。
5、JDK中所提供的Unicode编码转换工具native2ascii
(1)主要的功能
从指定文件中将本地字符串转换为Unicode编码的符号,并存储在输出文件中。
因为ResourceBundle 在存取属性文件时,都是采用Unicode Latin-1的编码方式读取,因此我們的属性文件,就必須使用Unicode Latin-1 编码方式来存储。
(2)用法示例
native2ascii [选项] [输入文件[输出文件]]
6、利用NumberFormat可以实现本地化格式的数字和货币的表示
(1)应用的背景
本地化不只是针对「字串」,其他如数字、货币的显示,以及日期时间的显示等等,都需针对不同地区的习惯,在输出時做区域化的格式转换。
如数字123456.78 在英文是如此表示,可是德文卻是表示成123.456,78。
就日期来说英文表示为October 10,1999 ,而我們卻习惯使用1999年10月10日。
这些资料我們可以经由java.text 包中所提供的类,來帮助我們格式化我們的输出。
(2)应用实例
1)例一
long myNumber=12345678;
String myString = NumberFormat.getInstance().format(myNumber);
System.out.println(myString); //将输出为:12,345,678
2)例二
long myNumber=12345678;
String myString = NumberFormat.getInstance(Locale.FRENCH).format(myNumber);
System.out.println(myString); //将输出为:12?345?678
3)例三
import java.text.*;
public class NumberFormatDemo{
public static void main(String[] args) {
double amount = 69935678.35;
NumberFormat nf = NumberFormat.getNumberInstance();
NumberFormat cf = NumberFormat.getCurrencyInstance();
String num = nf.format(amount);
String cur = cf.format(amount);
System.out.println(num);
System.out.println(cur);
}
}
(3)应用要点
使用这种方式,在显示数字或货币前,先做格式化转换,而不是直接將其转换为字串显示,將可使程序在不同区域显示的信息更合适。
7、Java中的日历、日期和时间的格式化
(1)概述
Java 语言的Calendar(日历),Date(日期), 和DateFormat(日期格式)组成了Java标准的一个基本但是非常重要的国际化技术的一部分。
日期是商业逻辑计算一个关键的部分,所有的开发者都应该能够计算未来的日期, 定制日期的显示格式, 并将文本数据解析成日期对象
在JDK中有java.util.Date 、抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat ;抽象类java.util.Calendar 和它的一个具体子类,java.util.GregorianCalendar来实现其功能。
(2)日期和时间的区域化格式化技术
日期和时间的区域化格式方式与数字的区域化方式大同小异,他們是使用java.text.DateFormat 类来做区域的格式化。
比较特別的是针对日期和时间的显示,我們又可以设定 5种不同的长度来显示时间、日期,这5种长度分別是:
1)DEFAULT(預設)
2)FULL(完整)
3)LONG(長格式)
4)MEDIUM(一般格式)
5)SHORT(短格式)。
(3)程序示例
下面的程序例分別显示 zh_TW 和 en_US 区域的各种长度格式显示日期以及時間。
利用方法DateFormat.getDateInstance()、DateFormat.getDateTimeInstance()让我们得以用几种不同的方法获得标准的日期格式化(内建的格式化)过程.
import java.text.*;
import java.util.Locale;
import java.util.Date;
public class DateFormatSample {
public static void main(String[] args) {
int[] styles = {
DateFormat.DEFAULT,
DateFormat.SHORT,
DateFormat.MEDIUM,
DateFormat.LONG,
DateFormat.FULL
};
Locale[] locales = { new Locale("en", "US"),new Locale("zh", "TW")
};
Date currentDate = new Date();
String result;
DateFormat formatter;
Locale loc;
System.out.println("---显示日期 ---");
for(int i=0; i<2; i++){
for(int j=0; j<5; j++)
{
formatter = DateFormat.getDateInstance(styles[j], locales[i]);
result = formatter.format(currentDate); //对日期进行格式化 System.out.println(result);
}
}
System.out.println("---显示时间 ---");
for(int i=0; i<2; i++)
{
for(int j=0; j<5; j++)
{
formatter = DateFormat.getTimeInstance(styles[j], locales[i]);
result = formatter.format(currentDate); //对时间进行格式化
System.out.println(result);
}
}
System.out.println("--- 显示日期时间 ---");
for(int i=0; i<2; i++)
{
for(int j=0; j<5; j++)
{
formatter = DateFormat.getDateTimeInstance(styles[j], styles[j],
locales[i]);
result = formatter.format(currentDate);
System.out.println(result);
}
}
}
}
(4)示例程序的执行结果
注意我们在对 getDateTimeInstance的每次调用中都传递了两个值,第一个参数是日期风格, 而第二个参数是时间风格。
它们都是基本数据类型int(整型),考虑到可读性, 我们使用了DateFormat 类提供的常量: SHORT, MEDIUM, LONG, 和 FULL。
8、Date 日期的编程
(1)相关应用技术概述
Date 类从Java 开发包(JDK) 1.0 就开始进化, 当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了,这种改进旨在更好的处理日期数据的国际化格式。
Date 类实际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林尼治标准时间)1970年, 1 月 1日00:00:00这一刻之前或者是之后经历的毫秒数.
(2)创建一个日期对象
让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单例子. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间.
import java.util.Date;
public class DateExample{
public static void main(String[] args){
Date date = new Date();
System.out.println(date.getTime()); //显示出从1970年1月1日开始经历的毫秒数了
}
}
(3)示例程序的执行结果
在这个例子中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受任何参数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期。
那么, 现在我们已经知道了如何获取从1970年1月1日开始经历的毫秒数了,我们如何才能以一种用户明白的格式来显示这个日期呢? 这可以通过java.text.SimpleDateFormat类和它的抽象基类 java.text.DateFormat来实现。
(4)日期数据的定制格式
假如我们希望定制日期数据的格式, 比方星期六-9月-29日-2001年。
下面的例子展示了如何完成这个工作。
利用抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat可以实现。
import java.text.SimpleDateFormat ;
import java.util.Date ;
public class DateFormatExample{
public static void main(String[] args){
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
Date date = new Date();
System.out.println(bartDateFormat.format(date));
}
}
只要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy", 我们就能够指明自己想要的格式. 你应该可以看见, 格式字符串中的ASCII 字符告诉格式化函数下面显示日期数据的哪一个部分. EEEE是星期, MMMM是月, dd是日, yyyy是年。
字符的个数决定了日期是如何格式化的,传递"EE-MM-dd-yy"会显示 Sat-09-29-01。
对于其它的时间格式,我们可以通过查看Sun 公司的Web 站点获取日期格式化选项的完整的指示。
9、利用SimpleDateFormat类实现将文本数据解析成日期对象
(1)应用要求
假设有一个文本字符串包含了一个格式化了的日期对象, 而我们希望解析这个字符串并从文本日期数据创建一个日期对象。
我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类, 但是这一次, 我们使用格式化解析而不是生成一个文本日期数据。
(2)实现的程序代码示例
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatDemo{
public static void main(String[] args) {
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("MM-dd-yyyy");
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
Date date;
String dateStringToParse = "9-29-2001";
try{
date = bartDateFormat.parse(dateStringToParse);
System.out.println(date.getTime());
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
try{
date = df.parse("20050124101921");
df.applyPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(date));
}
catch (Exception e){
System.out.println(e.toString());
}
}
}
(3)示例程序的执行结果
将显示出从1970年1月1日开始到2001年9月29日经历的毫秒数了
10、Java中的日期时间的各种操作示例
(1)获得当前时间
Calendar cal = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mDateTime=formatter.format(cal.getTime());
System.out.println(mDateTime);
(2)获得1年前日期
java.util.Date myDate=new java.util.Date();
long myTime=(myDate.getTime()/1000)-60*60*24*365;
myDate.setTime(myTime*1000);
String mDate=formatter.format(myDate);
System.out.println(mDate);
(3)获得明天日期
myDate=new java.util.Date();
myTime=(myDate.getTime()/1000)+60*60*24;
myDate.setTime(myTime*1000);
mDate=formatter.format(myDate);
System.out.println(mDate);
(4)获得两个时间之间的天数
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date= myFormatter.parse("2003-05-1");
java.util.Date mydate= myFormatter.parse("1899-12-30");
long day=(date.getTime()-mydate.getTime())/(24*60*60*1000);
System.out.println(day);
(5)获得加半小时后的时间
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
java.util.Date date1 = format.parse("2002-02-28 23:16:00");
long Time=(date1.getTime()/1000)+60*30;
date1.setTime(Time*1000);
String mydate1=formatter.format(date1);
System.out.println(mydate1);
(6)根据年月周获得求日期
SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");
java.util.Date date2= formatter2.parse("2003-05 5 星期五");
SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");
String mydate2=formatter3.format(date2);
System.out.println(mydate2);
(7)求是星期几
mydate= myFormatter.parse("2001-1-1");
SimpleDateFormat formatter4 = new SimpleDateFormat("E");
String mydate3=formatter4.format(mydate);
System.out.println(mydate3);
11、java.util.Canlendar类及应用实例
(1)相关的应用技术概述
自JDK1.1引入的Calendar类是另一种不同类型的日期处理类。
想象它是一个挂在墙壁上的典型日历,有许多日期和页数可以翻阅。
另外,我们如何才能设置和获取日期数据的特定部分呢, 比如说小时, 日, 或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类。
Calendar类的基础即有变量域的观念。
每个类元素都是域,并且这些域在Calendar类中表现为静态变量。
这些变量域,可以通过get/set类方法来获得或者设置域值。
(2)Calendar类中的变量域读写
下面为获得默认的Calendar实例,并对它设置时间的功能实现代码示例:
Calendar cal = Calendar.getInstance();
intyear = cal.get(Calendar.YEAR);
cal.set(Calendar.MONTH,Calendar.NOVEMBER);
还有一个隐藏在最通用的Calendar的子类中的功能性方法--isLeapYear(判断是否为闰年)方法。
Calendar cal = Calendar.getInstance();
booleanleapYear = ( (GregorianCalendar)cal ).isLeapYear(2002); // 这个值是false 尽管它是一个实例方法,isLeapYear方法的行为表现像静态方法,需要提供年份的参数传值给日历。
通过接管日期修改的功能,java.util.Calendar类看上去更像是Date类的复杂版本。
但是它还提供额外的功能,更不用说它的国际化支持。
(3)Calendar类的应用示例
假设你想要设置、获取和操纵一个日期对象的各个部分, 比方一个月的一天或者是一个星
期的一天.。
为了演示这个过程, 我们将使用具体的子类java.util.GregorianCalendar类,考虑下面的例子, 它计算得到下面的第十个星期五是13号。
import java.util.GregorianCalendar;
import java.util.Date;
import java.text.DateFormat;
public class CalendarDateExample{
public static void main(String[] args) {
DateFormat dateFormat =DateFormat.getDateInstance(DateFormat.FULL);
GregorianCalendar cal = new GregorianCalendar(); // Create our Gregorian Calendar.
cal.setTime(new Date()); // 将时间和日期设置为系统时间和日期
System.out.println("系统时间和日期" + dateFormat.format(cal.getTime())); //显示出现在的时间和日期
cal.set(GregorianCalendar.DAY_OF_WEEK,GregorianCalendar.FRIDAY); // 将现在设置为周五,然后再显示出修改后的时间和日期
System.out.println("将现在的时间设置为周五后:" + dateFormat.format(cal.getTime()));
int friday13Counter = 0;
while (friday13Counter <= 10) {
// 从下一个周五开始,搜索每年中日期为13号并且是周五的某一天,然后显示出该日期
cal.add(GregorianCalendar.DAY_OF_MONTH, 7);
if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13) {
friday13Counter++;
System.out.println(dateFormat.format(cal.getTime()));
}
}
}
}
(4)示例程序的执行结果
在这个例子中我们作了有趣的函数调用:
cal.set(GregorianCalendar.DAY_OF_WEEK,GregorianCalendar.FRIDAY);
和:
cal.add(GregorianCalendar.DAY_OF_MONTH, 7);
set 方法能够让我们通过简单的设置星期中的哪一天这个域来将我们的时间调整为星期五。
注意到这里我们使用了常量DAY_OF_WEEK 和FRIDAY来增强代码的可读性,add 方法让我们能够在日期上加上数值,润年的所有复杂的计算都由这个方法自动处理。
12、应用java.util.Timer实现定时服务的应用实例
在应用开发中,经常需要一些周期性的操作,比如每5分钟检查一下新邮件等。
对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。
比如下面的代码每5分钟检查一遍是否有新邮件:
private java.util.Timer timer;
timer = new Timer(true);
timer.schedule( new java.util.TimerTask(){
public void run(){
/**
在此检查是否有新邮件,代码省略
*/
}
}, 0, 5*60*1000);
使用这几行代码之后,Timer本身会每隔5分钟调用一遍检查是否有新邮件的功能方法,不需要自己启动线程。
Timer本身也是多线程同步的,多个线程可以共用一个Timer,不需要外部的同步代码。