前言:
此刻姐妹们对“java系统类库”大概比较注重,姐妹们都需要剖析一些“java系统类库”的相关内容。那么小编在网摘上汇集了一些有关“java系统类库””的相关资讯,希望大家能喜欢,各位老铁们快快来了解一下吧!第十一章、JAVA的常用类库
11-1、JAVA常用类库——StringBuffer类
StringBuffer是使用缓冲区的,本身也是操作字符串的,但是与String类不同,String类的内容一旦声明之后则不可改变,改变的只是其内存地址的指向,而StringBuffer中的内容是可以改变的。
对于StringBuffer而言,本身是一个具体的操作类,所以不能像String那样采用直接赋值的方式进行对象的实例化,必须通过构造方法完成。
StringBuffer连接字符操作:
当一个字符串的内容需要被经常改变时就要使用StringBuffer,在StringBuffer中使用append()方法完成字符串的连接操作:
11-1-1、实例操作一:字符串连接操作(append)
在StringBuffer中提供了一系列的append()方法,下面观察具体使用(这些方法最终都会返回StringBuffer类的实例化对象)。
public class StringBufferDemo01{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ") ; // 向StringBuffer中添加内容
buf.append("World").append("!!!") ; // 可以连续调用append()方法
buf.append("\n") ; // 添加一个转义字符
buf.append("数字 = ").append(1).append("\n") ; // 添加数字
buf.append("字符 = ").append('C').append("\n"); // 添加字符
buf.append("布尔 = ").append(true) ; // 添加布尔值
System.out.println(buf) ; // 直接输出对象,调用toString()
}
};
继续验证StringBuffer的内容是可以修改的,通过引用传递的方式完成。
public class StringBufferDemo02{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ") ;
fun(buf) ; // 传递StringBuffer内容
System.out.println(buf) ; // 打印内容
}
public static void fun(StringBuffer s){ // 接收StringBuffer引用
s.append("MLDN ").append("LiXingHua") ; // 修改StringBuffer的内容
}
};
StringBuffer类的常用方法
方法定义
类型
描述
1
public StringBuffer( )
构造
StringBuffer的构造方法
2
public StringBuffer append(char c)
方法
在StringBuffer中提供了大量的追加操作(与String中使用“+”类似),可以向StringBuffer中追加内容,此方法可以添加任何的数据类型
3
public StringBuffer append(String str)
方法
4
public StringBuffer append(StringBuffer sb)
方法
5
public int indexOf(String str)
方法
查找指定字符串是否存在
6
public int indexOf(String str,int fromIndex)
方法
从指定位置开始查找指定字符串是否存在
7
public StringBuffer insert(int offset,String str)
方法
在指定位置处加上指定字符串
8
public StringBuffer reverse()
方法
将内容反转保存
9
public StringBuffer replace(ing start,int end,String str)
方法
指定内容替换
10
public int length()
方法
求出内容长度
11
public StringBuffer delete(int start,int end)
方法
删除指定范围的字符串
12
public String substring(int start)
方法
字符串截取,指定开始点
13
public String substring(int start,int end)
方法
截取指定范围的字符串
14
public String toString( )
方法
Object类继承的方法,用于将内容变为String类型
11-1-2、实例操作二:在任意位置处为StringBuffer添加内容
可以直接使用insert()方法添加内容:public StringBuffer insert(int offset,Boolean b)
public class StringBufferDemo03{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("World!!") ; // 添加内容
buf.insert(0,"Hello ") ; // 在第一个内容之前添加内容
System.out.println(buf) ;
buf.insert(buf.length(),"MLDN~") ; // 在最后添加内容
System.out.println(buf) ;
}
};
在StringBuffer中与String类非常类似的是都可以使用length()获得字符串长度。
11-1-3、实例操作三:字符串的反转操作
直接使用reverse()方法就可以完成反转的功能:public StringBuffer reverse()
public class StringBufferDemo04{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("World!!") ; // 添加内容
buf.insert(0,"Hello ") ; // 在第一个内容之前添加内容
String str = buf.reverse().toString() ; // 将内容反转后变为String类型
System.out.println(str) ; // 将内容输出
}
};
11-1-4、实例操作四:替换指定范围的内容
在StringBuffer类中也存在replace()方法,使用此方法就可以对指定范围的内容进行替换:
public StringBuffer replace(int end,String str)
public class StringBufferDemo05{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ").append("World!!") ; // 向StringBuffer添加内容
buf.replace(6,11,"LiXingHua") ; // 将world的内容替换
System.out.println("内容替换之后的结果:" + buf) ; // 输出内容
}
};
11-1-5、实例操作五:字符串截取
通过substring()方法直接从StringBuffer中指定范围截取内容:public String substring(int start,int end)
public class StringBufferDemo06{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ").append("World!!") ; // 向StringBuffer添加内容
buf.replace(6,11,"LiXingHua") ; // 将world的内容替换
String str = buf.substring(6,15) ; // 截取指定范围的内容
System.out.println("内容替换之后的结果:" + str) ; // 输出内容
}
};
11-1-6、实例操作六:删除指定范围内的内容
通过delete()方法直接从StringBuffer中删除指定范围内的内容:public String delete(int start,int end)
public class StringBufferDemo07{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ").append("World!!") ; // 向StringBuffer添加内容
buf.replace(6,11,"LiXingHua") ; // 将world的内容替换
String str = buf.delete(6,15).toString() ; // 删除指定范围中的内容
System.out.println("删除之后的结果:" + str) ; // 输出内容
}
};
11-1-7、实例操作七:查找指定的内容是否存在
在String类中可以使用indexOf()方法进行查找,而在StringBuffer中也可以继续使用此方法,此方法如果找到内容则返回位置,否则返回-1。
public class StringBufferDemo08{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ; // 声明StringBuffer对象
buf.append("Hello ").append("World!!") ; // 向StringBuffer添加内容
if(buf.indexOf("Hello")==-1){
System.out.println("没有查找到指定的内容") ;
}else{ // 不为01表示查找到内容
System.out.println("可以查找到指定的内容"+buf.indexOf("Hello")) ;
}
}
};
11-1-8、StringBuffer的应用
先看以下代码操作:
public class StringBufferDemo09{
public static void main(String args[]){
String str1 = "LiXingHua" ;
for(int i=0;i<100;i++){
str1 += i ; // 不断修改String的内存引用,性能低
}
System.out.println(str1) ;
}
};
以上的操作代码因为要频繁修改字符串中的内容,所以使用String根本是不合理的,最好的做法是使用StringBuffer。
public class StringBufferDemo10{
public static void main(String args[]){
StringBuffer buf = new StringBuffer() ;
buf.append("LiXingHua") ;
for(int i=0;i<100;i++){
buf.append(i); // StringBuffer可以修改,性能高
}
System.out.println(buf) ;
}
};
从以上示例中可以看出,凡是需要频繁修改字符串内容的时候,都要使用StringBuffer类完成,而且在StringBuffer类中也提供了一些方法是String类中所没有的,包括:delete()、insert()等等。这些方法需要的时候直接通过DOC文档进行查找。
11-2、JAVA常用类库——Runtime类
Runtime运行时,是一个封装了JVM进程的类。每一个JAVA程序实际上都是启动了一个JVM进程,那么每一个JVM进程都是对应这一个Runtime实例,此实例是由JVM为其实例化的。
本类的定义中根本就没有构造方法,本类的构造方法被私有化了。则在此类中肯定有一个方法可以返回本类的实例化对象。
public static Runtime getRuntime()
直接使用此静态方法就可以取得Runtime类的实例。
实例化Runtime对象:
·Runtime run = Runtime.getRuntime();
Runtime类的常用方法
方法定义
类型
描述
1
Public static Runtime getRuntime()
普通
取得Runtime类的实例
2
Public long freeMemory()
普通
返回JAVA虚拟机中的空闲内存量
3
Public long maxMemory()
普通
返回JVM的最大内存量
4
Public void gc()
普通
运行垃圾回收器,释放空间
5
Public Process exec(String command) throws IOException
普通
执行本机命令
一旦取得实例之后,以上的方法就可以进行操作了。
11-2-1、得到JVM信息
每一个Runtime对象都是由JVM进行实例化,所以,可以直接通过此类取得一些信息。
public class RuntimeDemo01{
public static void main(String args[]){
Runtime run = Runtime.getRuntime(); // 通过Runtime类的静态方法进行实例化操作
System.out.println("JVM最大内存量:" + run.maxMemory()) ; // 观察最大的内存,根据机器的不同,环境也会有所不同
System.out.println("JVM空闲内存量:" + run.freeMemory()) ; // 取得程序运行的空闲内存
String str = "Hello " + "World" + "!!!"
+"\t" + "Welcome " + "To " + "MLDN" + "~" ;
System.out.println(str) ;
for(int x=0;x<1000;x++){
str += x ; // 循环修改内容,会产生多个垃圾
}
System.out.println("操作String之后的,JVM空闲内存量:" + run.freeMemory()) ;
run.gc() ; // 进行垃圾收集,释放空间
System.out.println("垃圾回收之后的,JVM空闲内存量:" + run.freeMemory()) ;
}
};
11-2-2、Runtime与Process类
除了观察内存使用量之外,也可以直接使用Runtime类运行本机的可执行程序。
·public Process exec(String command) throws IOException
public class RuntimeDemo02{
public static void main(String args[]){
Runtime run = Runtime.getRuntime() ; // 取得Runtime类的实例化对象
try{
run.exec("notepad.exe") ; // 调用本机程序,此方法需要异常处理
}catch(Exception e){
e.printStackTrace() ; // 打印异常信息
// System.out.println(e) ;
}
}
};
以上的程序只是打开了一个记事本,现在要求一个记事本程序在运行5秒之后自动进行关闭,如果要想实现此功能,就必须操作进程,因为每一个记事本打开都是会存在一个进程的。exec()方法的返回值是Procese,表示一个进程的操作类,可以通过destroy()方法销毁一个进程。
public class RuntimeDemo03{
public static void main(String args[]){
Runtime run = Runtime.getRuntime() ; // 取得Runtime类的实例化对象
Process p = null ; // 定义进程变量
try{
p = run.exec("notepad.exe") ; // 调用本机程序,此方法需要异常处理
}catch(Exception e){
e.printStackTrace() ; // 打印异常信息
// System.out.println(e) ;
}
try{
Thread.sleep(5000) ; // 让此线程存活5秒
}catch(Exception e){
}
p.destroy() ; // 结束此进程
}
};
11-3、JAVA常用类库——国际化程序
所谓国际化程序是指一个程序可以同时适应多门语言,即:如果现在程序者是中国人,则会以中文显示文字,如果现在程序的使用者是英国人,则会以英语显示的文字,也就是说可以通过国际化操作,让一个程序适应各个国家的语言要求。
程序根据不同的语言环境找到不同的资源文件,之后从资源文件中取出内容,资源文件中的内容都是以keyvalue的形式保存的,所以在读取的时候通过其key找到对应的value即可。
11-3-1、国际化实现的支持类
如果要想实现Java程序的国际化操作必须通过以下的三个类完成:
·java.util.Locale : 用于表示一个国家语言类
·java.util.ResourceBundle : 用于访问资源文件
·java.text.MessageFormat :格式化资源文件的占位字符串
Locale类
Locale表示的是本地,实际上使用的是一个ISO编码的封装类。对于各个国家来说都存在一个唯一的编码,那么这种编码就称为ISO编码,使用Locale可以指定好一个具体的国家编码。
例如:中国的编码:zh-CN
英语-美国的编码:en-US
法语的编码:fr-FR
ResourceBundle类
此类是专门完成属性文件读取操作的,读取的时候直接指定文件名称即可(此文件名称一般不需要指定后缀,后缀统一为*.properties),可以根据Locale所指定的区域码来自动选择所需要的资源文件。
public static final ResourceBundle getBundle(String baseName),此方法就是指定要操作的资源文件,此方法找到的是默认的操作系统的语言Locale对象。
public static final ResourceBundle getBundle(String baseName,Locale locale),此方法也是指定操作的资源文件,并传入Locale对象。
public final String getString(String key)根据key取得对应的value
下面通过一道程序来观察资源文件的使用,以及如何使用ResourceBundle读取资源文件。
资源文件命名的时候最好采用单词首字母大写的方式完成。
Message.properties:
info=Hello
其中info是程序中需要的内容,而Hello是此info所指向的具体内容。
从资源文件中读取数据:
import java.util.ResourceBundle ;
public class InterDemo01{
public static void main(String args[]){
ResourceBundle rb = ResourceBundle.getBundle("Message") ; // 找到资源文件,不用编写后缀
System.out.println("内容:" + rb.getString("info")) ; // 从资源文件中取得内容
}
};
MessageFormat类
11-3-2、JAVA国际化程序实现
大概了解了ResourceBundle类和资源文件之后,下面就结合Locale类一起完成国际化程序的开发。
开发要求:
可以根据不同的国家输出不同国家的你好:
·中文:你好!
·英语:Hello!
·法语:Bonjour!
分别定义不同的资源文件,此时需要定义出三个资源文件,同时在定义资源文件的时候需要指定好此资源文件对应的语言编码:
·中文:Message_zh_CN.properties
·英文:Message_en_US.properties
·法文:Message_fr_FR.properties
import java.util.ResourceBundle ;
import java.util.Locale ;
public class InterDemo02{
public static void main(String args[]){
Locale zhLoc = new Locale("zh","CN") ; // 表示中国地区
Locale enLoc = new Locale("en","US") ; // 表示美国地区
Locale frLoc = new Locale("fr","FR") ; // 表示法国地区
// 找到中文的属性文件,需要指定中文的Locale对象
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc) ;
// 找到英文的属性文件,需要指定英文的Locale对象
ResourceBundle enrb = ResourceBundle.getBundle("Message",enLoc) ;
// 找到法文的属性文件,需要指定法文的Locale对象
ResourceBundle frrb = ResourceBundle.getBundle("Message",frLoc) ;
// 依次读取各个属性文件的内容,通过键值读取,此时的键值名称统一为info
System.out.println("中文:" + zhrb.getString("info")) ;
System.out.println("英语:" + enrb.getString("info")) ;
System.out.println("法语:" + frrb.getString("info")) ;
}
};
以上信息确实读取出来了,但是在程序开发中有一点特别需要注意,对于中文的资源文件,虽然现在可以直接通过中文读取,但是这样做是不合理的,应该将其进行Unicode编码,转换为JAVA认识的16进制,这样可以避免一些系统所带来的乱码问题,此工具为JDK自行提供。
只要是中文,就必须进行转码操作。
11-3-3、处理动态文本
之前的资源文件中的所有内容实际上都是固定的,而如果现在有些内容是动态的,那么此时就必须在资源文件中进行一些动态文本的配置,设置占位符。这些符号中的内容暂时不固定,而是在程序执行的时候由程序进行设置的,而要想实现这样的功能,则必须使用MessageFormat类。此类是在java.text包中定义的。
在Format类中还存在数字格式的Format(NumberFormat)、日期格式化的Format(DateFormat)。
占位符使用(数字)的形式表示,如果现在表示第一个内容“{0}”、第二个内容“{1}”……,依次类推。
在MessageFormat类中主要使用format()方法,此方法定义如下:
public static String format(String pattern,Object… arguments)
使用:
import java.util.ResourceBundle ;
import java.util.Locale ;
import java.text.* ;
public class InterDemo03{
public static void main(String args[]){
Locale zhLoc = new Locale("zh","CN") ; // 表示中国地区
Locale enLoc = new Locale("en","US") ; // 表示美国地区
Locale frLoc = new Locale("fr","FR") ; // 表示法国地区
// 找到中文的属性文件,需要指定中文的Locale对象
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc) ;
// 找到英文的属性文件,需要指定英文的Locale对象
ResourceBundle enrb = ResourceBundle.getBundle("Message",enLoc) ;
// 找到法文的属性文件,需要指定法文的Locale对象
ResourceBundle frrb = ResourceBundle.getBundle("Message",frLoc) ;
// 依次读取各个属性文件的内容,通过键值读取,此时的键值名称统一为info
String str1 = zhrb.getString("info") ;
String str2 = enrb.getString("info") ;
String str3 = frrb.getString("info") ;
System.out.println("中文:" + MessageFormat.format(str1,"李兴华")) ;
System.out.println("英语:" + MessageFormat.format(str2,"LiXingHua")) ;
System.out.println("法语:" + MessageFormat.format(str3,"LiXingHua")) ;
}
};
处理动态文本。
设置多个占位符:
11-3-4、JAVA新特性——可变参数
在JDK1.5之后JAVA增加了新特性的操作,可以向方法中传递可变的参数,以前的定义的方法,实际上里面的参数都是固定个数的,在JDK1.5之后为了解决操作的麻烦,增加了此特性。
测试参数传递:
public class InterDemo04{
public static void main(String args[]){
System.out.print("第一次运行:") ;
fun("LXH","Li","李兴华") ; // 传入三个参数
System.out.print("\n第二次运行:") ;
fun("MLDN") ; // 传入一个参数
}
public static void fun(Object...args){ // 固定语法,输入任意多个数据,使用数组表示
for(int i=0;i<args.length;i++){
System.out.print(args[i] + "、") ;
}
}
};
直接传入一个数组:
public class InterDemo05{
public static void main(String args[]){
System.out.print("第一次运行:") ;
Object[] arg1 = {"LXH","Li","李兴华"} ;
fun(arg1) ; // 传入三个参数
System.out.print("\n第二次运行:") ;
Object[] arg2 = {"MLDN"} ;
fun(arg2) ; // 传入一个参数
System.out.print("\n第三次运行:") ;
Object[] arg3 = {} ; // 没有参数传入
fun(arg3) ;
}
public static void fun(Object...args){ // 固定语法,输入任意多个数据,使用数组表示
for(int i=0;i<args.length;i++){
System.out.print(args[i] + "、") ;
}
}
};
11-3-5、使用一个类代替资源文件
所有的要显示的内容实际上都应该放在资源文件之中,但是在JAVA中为了照顾部分习惯使用类的用户,所以也可以直接使用一个类来存放所有的资源文件内容,但是,此类在操作的时候就必须有一个明显的注意点:必须继承ListResourceBundle
编写类文件Message_zh_CN.class,继承java.util包中的ListResourceBundle方法,并覆写getContents()方法:
import java.util.ListResourceBundle ;
public class Message_zh_CN extends ListResourceBundle{
private final Object data[][] = {
{"info","中文,你好,{0}!"}
} ;
public Object[][] getContents(){ // 覆写的方法
return data ;
}
};
编写主类文件,导入java.util包即可完成操作:
import java.util.ResourceBundle ;
import java.util.Locale ;
import java.text.* ;
public class InterDemo06{
public static void main(String args[]){
Locale zhLoc = new Locale("zh","CN") ; // 表示中国地区
// 找到中文的属性文件,需要指定中文的Locale对象
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc) ;
String str1 = zhrb.getString("info") ;
System.out.println("中文:" + MessageFormat.format(str1,"李兴华")) ;
}
};
不管是资源类还是资源文件,找的时候都是Message,那么如果现在多种资源文件一起出来,那么最终找的是哪一个呢?
此时就需要区分优先级: 执行级别
·Message_zh_CN.class 高
·Message_zh_CN.properties
·Message.properties 低
国际化程序实现的思路:程序与显示相分离,根据不同的Locale指定的区域找到不同的资源文件并根据其key取得对应的value。
在实际的开发中,包括struts,都经常使用资源文件的方式保存所有的信息内容,其基本原理就是依靠了ResourceBundle类取得资源文件中的内容。
11-4、JAVA常用类库——System类
System类是一些与系统相关的属性和方法的集合,而且在System类中所有的属性都是静态的,要想引用这些属性和方法,直接使用System类调用即可。
方法定义
类型
描述
1
public static void exit(int status)
普通
系统退出,如果status为非 0就表示退出
2
public static void gc( )
普通
运行垃圾收集机制,调用的是Runtime类中的gc方法
3
public static long currentTimeMillis( )
普通
返回以毫秒为单位的当前时间
4
public static void arraycopy(object src,int srcPos,object dest,int destPos,int length)
普通
数组拷贝操作
5
public static Properties getProperties( )
普通
取得当前的系统全部属性
6
public static String getProperty(String key)
普通
根据键值取得属性的具体内容
11-4-1、System类的基本应用
System类中除了可以进行内容的输出外,还可以通过方法取得一个操作的计算时间。
public class SystemDemo01{
public static void main(String args[]){
long startTime = System.currentTimeMillis() ; // 取得开始计算之前的时间
int sum = 0 ; // 声明变量
for(int i=0;i<30000000;i++){ // 执行累加操作
sum += i ;
}
long endTime = System.currentTimeMillis() ; // 取得计算之后的时间
// 结束时间减去开始时间
System.out.println("计算所花费的时间:" + (endTime-startTime) +"毫秒") ;
}
};
获取系统全部属性:
public class SystemDemo02{
public static void main(String args[]){
System.getProperties().list(System.out) ; // 列出系统的全部属性
}
};
如果只需要取得几个固定的属性,则可以通过以下取得:
public class SystemDemo03{
public static void main(String args[]){
System.out.println("系统版本:" + System.getProperty("os.name")
+ System.getProperty("os.version")
+ System.getProperty("os.arch")) ;
System.out.println("系统用户:" + System.getProperty("user.name")) ;
System.out.println("当前用户目录:" + System.getProperty("user.home")) ;
System.out.println("当前用户工作目录:" + System.getProperty("user.dir")) ;
}
};
11-4-2、垃圾回收
一个对象如果不使用,则肯定要等待进行垃圾收集,垃圾收集可以自动调用也可以手工调用,手工调用的时候就是调用其所长System.gc( )或者Runtime.getRuntime( ).gc( )。但是,如果一个对象在回收之前需要做一些收尾的工作,则就必须覆写Object类中的:protected void finalize( ) throws Throwable。在对象被回收之前进行调用,以处理对象回收前的若干操作,例如释放资源等等。
class Person{
private String name ;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age;
}
public String toString(){ // 覆写toString()方法
return "姓名:" + this.name + ",年龄:" + this.age ;
}
public void finalize() throws Throwable{ // 对象释放空间时默认调用此方法
System.out.println("对象被释放 --> " + this) ;
}
};
public class SystemDemo04{
public static void main(String args[]){
Person per = new Person("张三",30) ;
per = null ; // 断开引用
System.gc() ; // 强制性释放空间
System.out.println("对象被释放 --> " + per) ;
}
};
输出结果:
F:\网页\李兴华\031104_【第11章:Java常用类库】_System类\代码>java SystemDemo04
对象被释放 --> 姓名:张三,年龄:30
对象被释放 --> null
只有强制性调用gc()的时候才可以发现对象被回收,如果不调用,则系统也会在一定时间内自行动进行回收。
11-5、JAVA常用类库——日期操作类(Date、Calendar)
Date类是一个较为常用的类,但是其操作的日期格式会有一些不符合于个人的要求,而如果要想进一步取得一些自己需要的时间,则可以使用Calendar类。
11-5-1、Date类
在java.util包中定义了Date类,Date类本身使用非常简单,直接输出其实例化对象即可。
import java.util.Date ;
public class DateDemo01{
public static void main(String args[]){
Date date = new Date() ; // 直接实例化Date对象
System.out.println("当前日期为:" + date) ;
}
};
输出结果:
F:\网页\李兴华\031105_【第11章:Java常用类库】_日期操作类(Date、Calendar)\代码
>java DateDemo01
当前日期为:Fri Sep 13 17:15:18 CST 2013
以上显示的日期格式如果不合适,可以使用Calendar类。
11-5-2、Calendar类
使用此类可以直接将日期精确到毫秒。
public abstract class Calendar extends Object
Calendar类是一个抽象类,既然是一个抽象类则肯定无法直接使用,此时就要利用对象多态性的概念,通过向上的转型关系实例化本类对象。Calendar类的子类是GregorianCalendar类。
通过Calendar类取得一个完整的日期。使用其子类:
import java.util.* ;
public class DateDemo02{
public static void main(String args[]){
Calendar calendar = new GregorianCalendar(); // 实例化Calendar类对象
System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
System.out.println("MONTH: " + (calendar.get(Calendar.MONTH) + 1));
System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
}
};
通过此类可以方便的取得一个完整的日期,但是在取得月份的时候需要增加1。
如果执照此种方式取得,则也会很麻烦,最好的做法是将Date进行一些相关的格式化操作。
11-5-3、DateFormat类
此类是一个日期的格式化类,专门格式化日期的操作,因为java.util.Date类本身就已经包含了完整的日期,所以只需要将些日期按照一些好的格式格式化一下显示就可以。
此类是定义在java.text包中的。
public abstract class DateFormat extends Format
但是从定义上可以发现,此类是一个抽象类,按照以往的思路,直接使用其子类实例化即可,但是DateFormat类本身的内部提供了可以直接为其实例化的操作。
·得到日期的DateFormat对象:public static final DateFormat getDateInstance()
·得到日期时间的DateFormat对象:public static final DateFormat getDateTimeInstance()
直接使用DateFormat类完成Date类的转换功能:
·public final String format(Date date)
import java.text.DateFormat ;
import java.util.Date ;
public class DateDemo03{
public static void main(String args[]){
DateFormat df1 = null ; // 声明一个DateFormat
DateFormat df2 = null ; // 声明一个DateFormat
df1 = DateFormat.getDateInstance() ; // 得到日期的DateFormat对象
df2 = DateFormat.getDateTimeInstance() ; // 得到日期时间的DateFormat对象
System.out.println("DATE:" + df1.format(new Date())) ; // 按照日期格式化
System.out.println("DATETIME:" + df2.format(new Date())) ; // 按照日期时间格式化
}
};
通过此类可以直接将Date类的显示进行合理的格式化操作,此时采用的是默认的格式化操作,也可以通过Locale对象指定要显示的区域。例如指定的区域是中国:
import java.text.DateFormat ;
import java.util.Date ;
import java.util.Locale ;
public class DateDemo04{
public static void main(String args[]){
DateFormat df1 = null ; // 声明一个DateFormat
DateFormat df2 = null ; // 声明一个DateFormat
df1 = DateFormat.getDateInstance(DateFormat.YEAR_FIELD,new Locale("zh","CN")) ; // 得到日期的DateFormat对象
df2 = DateFormat.getDateTimeInstance(DateFormat.YEAR_FIELD,DateFormat.ERA_FIELD,new Locale("zh","CN")) ; // 得到日期时间的DateFormat对象
System.out.println("DATE:" + df1.format(new Date())) ; // 按照日期格式化
System.out.println("DATETIME:" + df2.format(new Date())) ; // 按照日期时间格式化
}
};
11-5-4、SimpleDateFormat类
此类的功能是完成日期的显示格式化,例如,在开发中,可能会将一种日期格式变为另外一种日期格式,如下所示:
·原始日期:2008-10-19 10:11:30:345
·转换后日期:2008年10月19日10时11分30秒345毫秒
但是以上的两个日期中日期的数字是完全一样的,唯一不同的是日期的显示格式不同,所以要想实现这样的转换功能就必须依靠SimpleDateFormat类。
如果要想实现转换,则必须首先准备好一个模板,通过此模板进行日期数字的提取工作。
No
标记
描述
1
y
表示年,年份是四位数字,所以需要使用“yyyy”表示年。
2
M
表示月。月份是两位数字,所以需要使用“MM”表示月。
3
d
表示日,日是两位数字,所以需要使用“dd”表示日。
4
H
表示时,两位数字表示。
5
m
表示分,两位数字“mm”
6
s
表示秒,两位数字“ss”
7
S
表示毫秒,三位数字“SSS”
在SimpleDateFormat类使用的时候,必须注意的是在构造对象时要传入匹配的模板。
·构造方法:public SimpleDateFormat(String pattern)
·转换:public Date parse(String source) throws ParseException 此时取得的是全部的时间数
·格式化:public final String format(Date date) 将时间重新格式化成字符串显示
import java.text.* ;
import java.util.* ;
public class DateDemo05{
public static void main(String args[]){
Calendar cd=new GregorianCalendar(); //实例化日期对象
String strDate = cd.get(Calendar.YEAR)+"-"+(cd.get(Calendar.MONTH)+1)+"-"+cd.get(Calendar.DAY_OF_MONTH)+
" "+cd.get(Calendar.HOUR_OF_DAY)+":"+cd.get(Calendar.MINUTE)+":"
+cd.get(Calendar.SECOND)+":"+cd.get(Calendar.MILLISECOND) ; //获取系统当前日期
// 准备第一个模板,从字符串中提取出日期数字
String pat1 = "yyyy-MM-dd HH:mm:ss:SSS" ;
// 准备第二个模板,将提取后的日期数字变为指定的格式
String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒" ;
SimpleDateFormat sdf1 = new SimpleDateFormat(pat1) ; // 实例化模板对象
SimpleDateFormat sdf2 = new SimpleDateFormat(pat2) ; // 实例化模板对象
Date d = null ;
try{
d = sdf1.parse(strDate) ; // 将给定的字符串中的日期提取出来
}catch(Exception e){ // 如果提供的字符串格式有错误,则进行异常处理
e.printStackTrace() ; // 打印异常信息
}
System.out.println(sdf2.format(d)) ; // 将日期变为新的格式
}
};
11-5-5、取得日期
开发中经常需要取得日期,而且每次取得日期的时候代码都会重复,所以既然是重复的代码就可以将其定义成一个类,以方便重复调用,但是在操作的时候有点特别需要注意:
·如果月份是小于10,则应该在当前月份前加“0”,但系统肯定会将数字“0”忽略。
基于Calendar类操作
除了取出日期之外,取得时间戳也是一种比较常见的操作,例如:以下的日期:
· 2009-01-16 11:25:34.943
· 时间戳:20090116112534943
import java.util.* ; // 导入需要的工具包
class DateTime{ // 以后直接通过此类就可以取得日期时间
private Calendar calendar = null ; // 声明一个Calendar对象,取得时间
public DateTime(){ // 构造方法中直接实例化对象
this.calendar = new GregorianCalendar() ;
}
public String getDate(){ // 得到的是一个日期:格式为:yyyy-MM-dd HH:mm:ss.SSS
// 考虑到程序要频繁修改字符串,所以使用StringBuffer提升性能
StringBuffer buf = new StringBuffer() ;
buf.append(calendar.get(Calendar.YEAR)).append("-") ; // 增加年
buf.append(this.addZero(calendar.get(Calendar.MONTH)+1,2)).append("-") ; // 增加月
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH),2)).append(" ") ; // 取得日
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY),2)).append(":") ; // 取得时
buf.append(this.addZero(calendar.get(Calendar.MINUTE),2)).append(":") ;
buf.append(this.addZero(calendar.get(Calendar.SECOND),2)).append(".") ;
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND),3)) ;
return buf.toString() ;
}
public String getDateComplete(){ // 得到的是一个日期:格式为:yyyy年MM月dd日 HH时mm分ss秒SSS毫秒
// 考虑到程序要频繁修改字符串,所以使用StringBuffer提升性能
StringBuffer buf = new StringBuffer() ;
buf.append(calendar.get(Calendar.YEAR)).append("年") ; // 增加年
buf.append(this.addZero(calendar.get(Calendar.MONTH)+1,2)).append("月") ; // 增加月
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH),2)).append("日") ; // 取得日
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY),2)).append("时") ; // 取得时
buf.append(this.addZero(calendar.get(Calendar.MINUTE),2)).append("分") ; // 取得分
buf.append(this.addZero(calendar.get(Calendar.SECOND),2)).append("秒") ; // 取得秒
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND),3)).append("毫秒") ; // 取得毫秒
return buf.toString() ;
}
public String getTimeStamp(){ // 得到的是一个时间戳
// 考虑到程序要频繁修改字符串,所以使用StringBuffer提升性能
StringBuffer buf = new StringBuffer() ;
buf.append(calendar.get(Calendar.YEAR)) ; // 增加年
buf.append(this.addZero(calendar.get(Calendar.MONTH)+1,2)) ; // 增加月
buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH),2)) ; // 取得日
buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY),2)) ; // 取得时
buf.append(this.addZero(calendar.get(Calendar.MINUTE),2)) ; // 取得分
buf.append(this.addZero(calendar.get(Calendar.SECOND),2)); // 取得秒
buf.append(this.addZero(calendar.get(Calendar.MILLISECOND),3)) ; // 取得毫秒
return buf.toString() ;
}
// 考虑到日期中存在前导0,所以在此处加上补零的方法
private String addZero(int num,int len){
StringBuffer s = new StringBuffer() ;
s.append(num) ;
while(s.length()<len){ // 如果长度不足,则继续补0
s.insert(0,"0") ; // 在第一个位置处补0
}
return s.toString() ;
}
};
public class DateDemo06{
public static void main(String args[]){
DateTime dt = new DateTime() ;
System.out.println("系统日期:"+dt.getDate()) ;
System.out.println("中文日期:"+dt.getDateComplete()) ;
System.out.println("时间戳:"+dt.getTimeStamp()) ;
}
};
以上的程序已经取得了日期时间、中文的日期时间、时间戳,但是所有的操作都比较麻烦,因为每一个地方还需要进行补零操作,所以,在直接使用Calendar类的时候虽然可以方便的将时间取得精确到毫秒,但是在对于取得完整日期的时候却不这么好使了。
基于SimpleDateFormat类操作
Java.util.Date已经就是一个完整的日期了,SimpleDateFormat类中存在一个方法,可以针对于Date重新格式化,那么如果现在将一个表示当前日期的date对象通过SimpleDateFormat类指定好的模板进行相关的格式化操作的话,那么取得的时间就非常的方便了。
import java.util.* ; // 导入需要的工具包
import java.text.* ; // 导入SimpleDateFormat所在的包
class DateTime{ // 以后直接通过此类就可以取得日期时间
private SimpleDateFormat sdf = null ; // 声明SimpleDateFormat对象
public String getDate(){ // 得到的是一个日期:格式为:yyyy-MM-dd HH:mm:ss.SSS
this.sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
return this.sdf.format(new Date()) ;// 将当前日期进行格式化操作
}
public String getDateComplete(){ // 得到的是一个日期:格式为:yyyy年MM月dd日 HH时mm分ss秒SSS毫秒
this.sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒SSS毫秒") ;
return this.sdf.format(new Date()) ;// 将当前日期进行格式化操作
}
public String getTimeStamp(){ // 得到的是一个时间戳
this.sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS") ;
return this.sdf.format(new Date()) ;// 将当前日期进行格式化操作
}
};
public class DateDemo07{
public static void main(String args[]){
DateTime dt = new DateTime() ;
System.out.println("系统日期:"+dt.getDate()) ;
System.out.println("中文日期:"+dt.getDateComplete()) ;
System.out.println("时间戳:"+dt.getTimeStamp()) ;
}
};
通过代码可以发现,直接使用SimpleDateFormat类取得时间会比使用Calendar类更加方便,而且不用去增加补零的操作,所以在开发中如果需要取得一个日期的话,则基本上都使用SimpleDateFormat类进行操作。
11-5-6、Math与Random类
Math类
表示数学操作,例如:平方根、四舍五入等。
public class MathDemo01{
public static void main(String args[]){
// Math类中的方法都是静态方法,直接使用“类.方法名称()”的形式调用即可
System.out.println("求平方根:" + Math.sqrt(9.0)) ;
System.out.println("求两数的最大值:" + Math.max(10,30)) ;
System.out.println("求两数的最小值:" + Math.min(10,30)) ;
System.out.println("2的3次方:" + Math.pow(2,3)) ;
System.out.println("四舍五入:" + Math.round(33.6)) ;
}
};
上面代码的求四舍五入的时候实际上是将小数点之后的内容全部忽略掉了,如果此时需要进行准确位数的四舍五入,则需要使用其他的类完成——BigDecimal。
Random类
Random类的主要功能是产生随机数,可以产生一个指定范围的随机数。Random类是定义在java.util包中的类。
例:生成10个随机数字,且数字不大于100:
import java.util.Random ;
public class RandomDemo01{
public static void main(String args[]){
Random r = new Random() ; // 实例化Random对象
for(int i=0;i<10;i++){
System.out.print(r.nextInt(100) + "\t") ;
}
}
};
11-5-7、NumberFormat类
NumberFormat表示数字的格式化类,即:可以按照本地的风格习惯进行数字的显示。类的定义如下:
·public abstract class NumberFormat extends Format
No
方法
类型
描述
1
public static Locale[] getAvailableLocales()
普通
返回所有语言环境的数组
2
public static final NumberFormat getInstance()
普通
返回当前默认语言环境的数字格式
3
public static NumberFormat getInstance(Locale inLocale)
普通
返回指定语言环境的数字格式
4
public static final NumberFormat getCurrencyInstance()
普通
返回当前默认环境的货币格式
5
public static NumberFormat getCurrencyInstance(Locale inLocale)
普通
返回指定语言环境的数字格式
MessageFormat、DateFormat、NumberFormat是Format三个常用的子类,如果要想进一步完成一个好的国际化程序,则肯定需要同时使用这样三个类完成,根据不同的国家显示日期,或者显示货币的形式。
此类在java.text包中,所以直接导入此包即可。
import java.text.* ;
public class NumberFormatDemo01{
public static void main(String args[]){
NumberFormat nf = null ; // 声明一个NumberFormat对象
nf = NumberFormat.getInstance() ; // 得到默认的数字格式化显示
System.out.println("格式化之后的数字:" + nf.format(10000000)) ;
System.out.println("格式化之后的数字:" + nf.format(1000.345)) ;
}
};
11-5-8、DecimalFormat类
DecimalFormat也是Format的一个子类,主要的作用是用来格式化数字使用,当然,在格式化数字的时候要比直接使用NumberFormat更加方便,因为可以直接指定按用户自定义的方式进行格式化操作,与之前讲解的SimpleDateFormat类似,如果要想进行自定义格式化操作,则必须指定格式化操作的模板。
No
标记
位置
描述
1
0
数字
代表阿拉伯数字,每一个0表示一位阿拉伯数字,如果该位不存在则显示0
2
#
数字
代表阿拉伯数字,每一个#表示一位阿拉伯数字,如果该位不存则不显示
3
.
数字
小数点分隔符或货币的小数分隔符
4
-
数字
代表负号
5
,
数字
分组分隔符
6
E
数字
分隔科学计数法中的尾数和指数
7
;
子模式边界
分隔正数和负数子模式
8
%
前缀或后缀
数字乘以100并显示为百分数
9
\u2030
前缀或后缀
乘以1000并显示为千分数
10
¤
\uQQA4
前缀或后缀
货币记号,由货币号替换,如果两个同时出现,则用国际货币符号替换,如果出现在某个模式中,则使用货币小数分隔符,而不使用数分隔符。
11
,
前缀或后缀
用于在前缀或后缀中为特殊字符加引号,例如:“##”将123格式化为“#123”。要创建单引号本身,请连续使用两个单引号:“#o’’clock”
例:
import java.text.* ;
class FormatDemo{
public void format1(String pattern,double value){ // 此方法专门用于完成数字的格式化显示
DecimalFormat df = null ; // 声明一个DecimalFormat类的对象
df = new DecimalFormat(pattern) ; // 实例化对象,传入模板
String str = df.format(value) ; // 格式化数字
System.out.println("使用" + pattern
+ "格式化数字" + value + ":" + str) ;
}
};
public class NumberFormatDemo02{
public static void main(String args[]){
FormatDemo demo = new FormatDemo() ; // 格式化对象的类
demo.format1("###,###.###",111222.34567) ;
demo.format1("000,000.000",11222.34567) ;
demo.format1("###,###.###¥",111222.34567) ;
demo.format1("000,000.000¥",11222.34567) ;
demo.format1("##.###%",0.345678) ;
demo.format1("00.###%",0.0345678) ;
demo.format1("###.###\u2030",0.345678) ;
}
};
11-5-9、大数操作(BigIntger、BigDecimal)
正常情况下一个整数最多只能放在long类型之中,但是如果现在有如下的一个数字:11212121212121212111122121212121212121
根本就是无法保存的,所以为了解决这样的问题,在java中引入了两个大数的操作类:
·操作整型:BigInteger
·操作小数:BigDecimal
BigInteger
如果在操作的时候一个整型数据已经超过了整数的最大类型长度long的话,则此数据就无法装入,所以,此时要使用BigInteger类进行操作。
NO
方法
类型
描述
1
public BigInteger(String val)
构造
将一个字符串变为BigInteger类型的数据
2
public BigInteger add(BigInteger val)
普通
加法
3
public BigInteger subtract(BigInteger val)
普通
减法
4
public BigInteger multiply(BigInteger val)
普通
乘法
5
public BigInteger divide(BigInteger val)
普通
除法
6
public BigInteger max(BigInteger val)
普通
返回两个大数字中的最大值
7
public BigInteger min(BigInteger val)
普通
返回两个大数字中的最小值
8
public BigInteger[] divideAndRemainder(BigInteger val)
普通
除法操作,数组的第一个元素为除法的商,第二个元素为除法的余数
BigInteger是在java.math包中。
import java.math.BigInteger ;
public class BigIntegerDemo01{
public static void main(String args[]){
BigInteger bi1 = new BigInteger("123456789") ; // 声明BigInteger对象
BigInteger bi2 = new BigInteger("987654321") ; // 声明BigInteger对象
System.out.println("加法操作:" + bi2.add(bi1)) ; // 加法操作
System.out.println("减法操作:" + bi2.subtract(bi1)) ; // 减法操作
System.out.println("乘法操作:" + bi2.multiply(bi1)) ; // 乘法操作
System.out.println("除法操作:" + bi2.divide(bi1)) ; // 除法操作
System.out.println("最大数:" + bi2.max(bi1)) ; // 求出最大数
System.out.println("最小数:" + bi2.min(bi1)) ; // 求出最小数
}
};
发现divide()方法本身只是把最终的商保存下来了,但是这样的两个数字相除的时候肯定是无法整除,肯定存在余数。
import java.math.BigInteger ;
public class BigIntegerDemo01{
public static void main(String args[]){
BigInteger bi1 = new BigInteger("123456789") ; // 声明BigInteger对象
BigInteger bi2 = new BigInteger("987654321") ; // 声明BigInteger对象
System.out.println("加法操作:" + bi2.add(bi1)) ; // 加法操作
System.out.println("减法操作:" + bi2.subtract(bi1)) ; // 减法操作
System.out.println("乘法操作:" + bi2.multiply(bi1)) ; // 乘法操作
System.out.println("除法操作:" + bi2.divide(bi1)) ; // 除法操作
System.out.println("最大数:" + bi2.max(bi1)) ; // 求出最大数
System.out.println("最小数:" + bi2.min(bi1)) ; // 求出最小数
BigInteger result[] = bi2.divideAndRemainder(bi1) ; // 求出余数的除法操作
System.out.println("商是:" + result[0] +
";余数是:" + result[1]) ;
}
};
BigDecimal
对于不需要任何准确计算精度的程序可以直接使用float或double完成,但是如果需要精确计算的结果,则必须使用BigDecimal类。
No
方法
类型
描述
1
Public BigDecimal(double val)
构造
将double表示形式转换为BigDecimal
2
Public BigDecimal(int val)
构造
将int表示形式转换为BigDecimal
3
Public BigDecimal(String val)
构造
将字符串表示形式转换为BigDecimal
4
Public BigDecimal add(BigDecimal augend)
普通
加法
5
Public BigDecimal subtract(BigDecimal subtrahend)
普通
减法
6
Public BigDecimal multiply(BigDecimal multiplicand)
普通
乘法
7
Public BigDecimal divide(BigDecimal divisor)
普通
除法
例:
import java.math.* ;
class MyMath{
public static double add(double d1,double d2){ // 进行加法计算
BigDecimal b1 = new BigDecimal(d1) ;
BigDecimal b2 = new BigDecimal(d2) ;
return b1.add(b2).doubleValue() ;
}
public static double sub(double d1,double d2){ // 进行减法计算
BigDecimal b1 = new BigDecimal(d1) ;
BigDecimal b2 = new BigDecimal(d2) ;
return b1.subtract(b2).doubleValue() ;
}
public static double mul(double d1,double d2){ // 进行乘法计算
BigDecimal b1 = new BigDecimal(d1) ;
BigDecimal b2 = new BigDecimal(d2) ;
return b1.multiply(b2).doubleValue() ;
}
public static double div(double d1,double d2,int len){ // 进行乘法计算
BigDecimal b1 = new BigDecimal(d1) ;
BigDecimal b2 = new BigDecimal(d2) ;
return b1.divide(b2,len,BigDecimal.ROUND_HALF_UP).doubleValue() ;
}
public static double round(double d,int len){ // 进行四舍五入
BigDecimal b1 = new BigDecimal(d) ;
BigDecimal b2 = new BigDecimal(1) ;
return b1.divide(b2,len,BigDecimal.ROUND_HALF_UP).doubleValue() ;
}
};
public class BigDecimalDemo01{
public static void main(String args[]){
System.out.println("加法运算:" + MyMath.round(MyMath.add(10.345,3.333),1)) ;
System.out.println("减法运算:" + MyMath.round(MyMath.sub(10.345,3.333),3)) ;
System.out.println("乘法运算:" + MyMath.round(MyMath.mul(10.345,3.333),2)) ;
System.out.println("除法运算:" + MyMath.div(10.345,3.333,3)) ;
}
};
11-5-10、对象的克隆技术
对象克隆:对象的复制,完整的复制一个对象。
如果要想完成对象克隆的话,则肯定依靠Object类。
protected Object clone( ) throws CloneNotSupportedException
以上的方法就是对象克隆的方法,如果现在一个类的对象被克隆,则就必须在此类中明确的覆写此方法,但是此方法不能直接调用。
Cloneable是一个接口,但是在此接口中并没有规定任何的操作方法,所以此接口实际上属于标识接口,表示一种能力。
class Person implements Cloneable{ // 实现Cloneable接口表示可以被克隆
private String name ;
public Person(String name){
this.name = name ;
}
public void setName(String name){
this.name = name ;
}
public String getName(){
return this.name ;
}
public String toString(){
return "姓名:" + this.name ;
}
public Object clone()
throws CloneNotSupportedException
{
return super.clone() ; // 具体的克隆操作由父类完成
}
};
public class CloneDemo01{
public static void main(String args[]) throws Exception{
Person p1 = new Person("张三") ;
Person p2 = (Person)p1.clone() ;
p2.setName("李四") ;
System.out.println("原始对象:" + p1) ;
System.out.println("克隆之后的对象:" + p2) ;
}
};
对象所在的类中必须实现Cloneable接口才可以完成对象的克隆操作。
11-5-11、Arrays
Arrays表示数组的操作类,是直接定义在java.util包中的,主要的功能可以实现数组元素的查找,数组内容的填充、排序等。
No
方法
类型
描述
1
Public static boolean equals(int[] a,int[] a1)
普通
判断两个数组是否相等,此方法被重载多次,可以判断各种数据类型的数组
2
Public static void fill(int[] a,int val)
普通
将指定内容填充到数组之中,此方法被重载多次,可以填充各种数据类型的数组
3
Public static void sort(int[] a)
普通
数组排序,此方法被重载多次,可以对各种类型的数组进行排序
4
Public static int binarySearch(int[] a,int key)
普通
对排序后的数组进行检索,此方法被重载多次,可以对各种类型的数组进行搜索
5
Public static String toString(int[] a)
普通
输出数组信息,此方法被重载多次,可以输出各种数据类型的数组
例子:
import java.util.* ;
public class ArraysDemo{
public static void main(String arg[]){
int temp[] = {3,4,5,7,9,1,2,6,8} ; // 声明一个整型数组
Arrays.sort(temp) ; // 进行排序的操作
System.out.print("排序后的数组:") ;
System.out.println(Arrays.toString(temp)) ; // 以字符串输出数组
// 如果要想使用二分法查询的话,则必须是排序之后的数组
int point = Arrays.binarySearch(temp,3) ; // 检索位置
System.out.println("元素‘3’的位置在:" + point) ;
Arrays.fill(temp,3) ;// 填充数组
System.out.print("数组填充:") ;
System.out.println(Arrays.toString(temp)) ;
}
};
11-5-12、比较器(Comparable、Comparator)
Comparable接口的作用
可以直接使用java.util.Arrays类进行数组的排序操作,但对象所在的类必须实现Comparable接口,用于指定排序接口。Comparable接口定义如下:
public interface Comparable<T>{
public int compareTo(To);
}
此方法返回一个int类型的数据,但是此int的值只能是以下三种:
· 1:表示大于
·-1:表示小于
· 0:表示相等
编写一个实例,要求:
·定义一个学生类,里面有姓名、年龄、成绩三个属性,要求按成绩由高到低排序,如果成绩相等则按照年龄由低到高排序。
class Student implements Comparable<Student> { // 指定类型为Student
private String name ;
private int age ;
private float score ;
public Student(String name,int age,float score){
this.name = name ;
this.age = age ;
this.score = score ;
}
public String toString(){
return name + "\t\t" + this.age + "\t\t" + this.score ;
}
public int compareTo(Student stu){ // 覆写compareTo()方法,实现排序规则的应用
if(this.score>stu.score){
return -1 ;
}else if(this.score<stu.score){
return 1 ;
}else{
if(this.age>stu.age){
return 1 ;
}else if(this.age<stu.age){
return -1 ;
}else{
return 0 ;
}
}
}
};
public class ComparableDemo01{
public static void main(String args[]){
Student stu[] = {new Student("张三",20,90.0f),
new Student("李四",22,90.0f),new Student("王五",20,99.0f),
new Student("赵六",20,70.0f),new Student("孙七",22,100.0f)} ;
java.util.Arrays.sort(stu) ; // 进行排序操作
for(int i=0;i<stu.length;i++){ // 循环输出数组中的内容
System.out.println(stu[i]) ;
}
}
};
注意:
如果在此时Student类中没有实现Comparable接口,则在执行时会出现以下的异常:
Exception in thread “main” java.lang.ClassCastException;
分析比较器的排序原理
实际上之前的排序过程,就是数据结构中的二叉树的排序方法,通过二叉树进行排序,之后利用中序遍历的方式把内容依次读取出来。二叉树排序的基本原理是:
将第一个内容作为根节点保存,之后如果后面的值比根节点的值大,则放在根节点的左子树,如果后面的值比根节点的值小,则放在根节点的右子树。
下面手工实现一个二叉树的比较算法。
为了操作方便,此处使用Integer类完成。
public class ComparableDemo02{
public static void main(String args[]){
Comparable com=null; //声明一个Comparable接口对象
Com=30; //通过Integer为Comparable实例化
System.out.println(“内容为:”+com); //调用的是toString()方法
}
}
了解了此特性之后,下面就可以动手完成一个二叉树算法:
class BinaryTree{
class Node{ // 声明一个节点类
private Comparable data ; // 保存具体的内容
private Node left ; // 保存左子树
private Node right ; // 保存右子树
public Node(Comparable data){
this.data = data ;
}
public void addNode(Node newNode){
// 确定是放在左子树还是右子树
if(newNode.data.compareTo(this.data)<0){ // 内容小,放在左子树
if(this.left==null){
this.left = newNode ; // 直接将新的节点设置成左子树
}else{
this.left.addNode(newNode) ; // 继续向下判断
}
}
if(newNode.data.compareTo(this.data)>=0){ // 放在右子树
if(this.right==null){
this.right = newNode ; // 没有右子树则将此节点设置成右子树
}else{
this.right.addNode(newNode) ; // 继续向下判断
}
}
}
public void printNode(){ // 输出的时候采用中序遍历
if(this.left!=null){
this.left.printNode() ; // 输出左子树
}
System.out.print(this.data + "\t") ;
if(this.right!=null){
this.right.printNode() ;
}
}
};
private Node root ; // 根元素
public void add(Comparable data){ // 加入元素
Node newNode = new Node(data) ; // 定义新的节点
if(root==null){ // 没有根节点
root = newNode ; // 第一个元素作为根节点
}else{
root.addNode(newNode) ; // 确定是放在左子树还是放在右子树
}
}
public void print(){
this.root.printNode() ; // 通过根节点输出
}
};
public class ComparableDemo03{
public static void main(String args[]){
BinaryTree bt = new BinaryTree() ;
bt.add(11) ;
bt.add(6) ;
bt.add(3) ;
bt.add(10) ;
bt.add(9) ;
bt.add(1) ;
bt.add(5) ;
bt.add(5) ;
System.out.println("排序之后的结果:") ;
bt.print() ;
}
};
另一种比较器:Comparator
如果一个类已经开发完成,但是在此类建立的初期并没有实现Comparable接口,此时肯定是无法进行对象排序操作的,所以为了解决这样的问题,java又定义了另一个比较器的操作接口——Comparator。此接口定义在java.util包中,接口定义如下:
public interface Comparator<T>{
public int compare(T 01,T 02);
boolean equals(Object obj);
}
下面定义一个学生类,该类没有实现Comparable接口:
class Student{ // 指定类型为Student
private String name ;
private int age ;
public Student(String name,int age){
this.name = name ;
this.age = age ;
}
public boolean equals(Object obj){ // 覆写equals方法
if(this==obj){
return true ;
}
if(!(obj instanceof Student)){
return false ;
}
Student stu = (Student) obj ;
if(stu.name.equals(this.name)&&stu.age==this.age){
return true ;
}else{
return false ;
}
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){
return name + "\t\t" + this.age ;
}
};
以上的类不存在排序功能,为了让此类可以进行排序操作,需要单独定义一个比较器:
class StudentComparator implements Comparator<Student>{ // 实现比较器
// 因为Object类中本身已经有了equals()方法
public int compare(Student s1,Student s2){
if(s1.equals(s2)){
return 0 ;
}else if(s1.getAge()<s2.getAge()){ // 按年龄比较
return 1 ;
}else{
return -1 ;
}
}
};
定义好了一个第三方的比较器操作类,此类是按照年龄进行排序的。
public class ComparatorDemo{
public static void main(String args[]){
Student stu[] = {new Student("张三",20),
new Student("李四",22),new Student("王五",20),
new Student("赵六",20),new Student("孙七",22)} ;
java.util.Arrays.sort(stu,new StudentComparator()) ; // 进行排序操作
for(int i=0;i<stu.length;i++){ // 循环输出数组中的内容
System.out.println(stu[i]) ;
}
}
};
在使用中尽可能还是使用Comparable在需要排序的类上实现好此接口,而Comparator需要单独建立一个排序的类,这样如果有很多的庆,则排序的规则类也就会非常的多,操作起来比较麻烦。
11-5-13、观察者设计模式
“现在很多的购房者都在关注着房子的价格变化,每当房子价格变化的时候,所有的购房者都可以观察得到”,实际上以上的购房者都属于观察者,他们都在关注着房子的价格。
如果要想实现观察者模式,则必须依靠java.util包中提供的Obeservable类和Observer接口。
import java.util.* ;
class House extends Observable{ // 表示房子可以被观察
private float price ;// 价钱
public House(float price){
this.price = price ;
}
public float getPrice(){
return this.price ;
}
public void setPrice(float price){
// 每一次修改的时候都应该引起观察者的注意
super.setChanged() ; // 设置变化点
super.notifyObservers(price) ;// 价格被改变
this.price = price ;
}
public String toString(){
return "房子价格为:" + this.price ;
}
};
class HousePriceObserver implements Observer{
private String name ;
public HousePriceObserver(String name){ // 设置每一个购房者的名字
this.name = name ;
}
public void update(Observable o,Object arg){
if(arg instanceof Float){
System.out.print(this.name + "观察到价格更改为:") ;
System.out.println(((Float)arg).floatValue()) ;
}
}
};
public class ObserDemo01{
public static void main(String args[]){
House h = new House(1000000) ;
HousePriceObserver hpo1 = new HousePriceObserver("购房者A") ;
HousePriceObserver hpo2 = new HousePriceObserver("购房者B") ;
HousePriceObserver hpo3 = new HousePriceObserver("购房者C") ;
h.addObserver(hpo1) ;
h.addObserver(hpo2) ;
h.addObserver(hpo3) ;
System.out.println(h) ; // 输出房子价格
h.setPrice(666666) ; // 修改房子价格
System.out.println(h) ; // 输出房子价格
}
};
在Observer接口中的update方法里面的两个参数:
·o :表示Observerable类的对象
·arg :需要被观察的内容
11-5-14、正则表达式
正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证、拆分、替换功能。例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法:
·不使用正则完成
·使用正则完成
public class RegexDemo01{
public static void main(String args[]){
String str = "1234567890" ; // 此字符串由数字组成
boolean flag = true ; // 定义一个标记变量
// 要先将字符串拆分成字符数组,之后依次判断
char c[] = str.toCharArray() ; // 将字符串变为字符数组
for(int i=0;i<c.length;i++){ // 循环依次判断
if(c[i]<'0'||c[i]>'9'){ // 如果满足条件,则表示不是数字
flag = false ; // 做个标记
break ; // 程序不再向下继续执行
}
}
if(flag){
System.out.println("是由数字组成!") ;
}else{
System.out.println("不是由数字组成!") ;
}
}
};
以上操作是不使用正则表达式操作。基本思路:就是将字符串拆分,之后一个个的进行比较的验证,但是这样比较麻烦,而且现在只是验证是否由数字组成,如果更加复杂的呢?
此时,将代码换成正则表达式:
import java.util.regex.Pattern ;
public class RegexDemo02{
public static void main(String args[]){
String str = "1234567890" ; // 此字符串由数字组成
if(Pattern.compile("[0-9]+").matcher(str).matches()){ // 使用正则
System.out.println("是由数字组成!") ;
}else{
System.out.println("不是由数字组成!") ;
}
}
};
以上的代码也完成了字符串的验证功能,可以发现,使用此种验证方法比之前的操作代码更加简单。
Pattern、Matcher类
如果要想在程序中应用正则表达式则必须依靠Pattern类与Matcher类,这两个类定义在java.util.regex包中,为正则的核心操作类。Pattern类的主要作用是进行正则规范(如之前的“[0-9]”就属于正则规范)的编写,而Matcher类主要是执行规范,验证一个字符串是否符合其规范。
常用正则规则—I
NO
规范
描述
NO
规范
描述
1
\\
表示反斜线(\)字符
2
\t
表示制表符
3
\n
表示换行
4
[abc]
字符a、b或c
5
[^abc]
除了a、b、c之外的任意字符
6
[a-zA-Z0-9]
表示由字母、数字组成
7
\d
表示数字
8
\D
表示非数字
9
\w
表示字母、数字、下划线
10
\W
表示非字母、数字、下划线
11
\s
表示所有空白字符(换行、空格等)
12
\S
表示所有非空白字符
13
^
行的开头
14
$
行的结尾
15
.
匹配除换行符之外的任意字符
常用正则规则—II
数量表示(X表示一组规范)
NO
规范
描述
NO
规范
描述
1
X
必须出现一次
2
X?
可以出现0次或1次
3
X*
可以出现0次、1次或多次
4
X+
可以出现1次或多次
5
X{n}
必须出现n次
6
X{n,}
必须出现n次以上
7
X{n,m}
必须出现n~m次
逻辑运算符(X、Y表示一组规范)
NO
规范
描述
NO
规范
描述
1
XY
X规范后跟着Y规范
2
X|Y
X规范或Y规范
3
(X)
做为一个捕获组规范
以上的正则,如果要想驱动起来,则必须依靠Pattern类和Matcher类。
Pattern主要是表示一个规则的意思,即:正则表达式的规则需要在Pattern类中使用。
Matcher类主要表示使用Pattern指定好的验证规则。
Pattern类的常用方法
NO
方法
类型
描述
1
public static Pattern compile(String regex)
普通
指定与正则表达式规则
2
public Matcher matcher(CharSequence input)
普通
返回Matcher类实例
3
public String[] split(CharSequence input)
普通
字符串拆分
在Pattern类中如果要想取得Pattern类实例,则必须调用compile()方法。
本类中没有明确的构造方法可以使用,那么则肯定此类的构造方法被私有化了,则可以直接从Pattern类中取得本类的实例。
指定好操作的正则:public static Pattern compile(String regex)
可以为matcher类实例化:public Matcher matcher(CharSequence input)
拆分:public String[] split(CharSequence)
Matcher类的常用方法
NO
方法
类型
描述
1
public Boolean matcher()
普通
执行验证
2
public String replaceAll(String replacement)
普通
字符串替换
例:使用正则规范日期格式
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
public class RegexDemo03{
public static void main(String args[]){
String str = "1983-07-27" ; // 指定好一个日期格式的字符串
String pat = "\\d{4}-\\d{2}-\\d{2}" ; // 指定好正则表达式
Pattern p = Pattern.compile(pat) ; // 实例化Pattern类
Matcher m = p.matcher(str) ; // 实例化Matcher类
if(m.matches()){ // 进行验证的匹配,使用正则
System.out.println("日期格式合法!") ;
}else{
System.out.println("日期格式不合法!") ;
}
}
};
在Pattern类中使用正则进行字符串拆分操作:
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
public class RegexDemo04{
public static void main(String args[]){
// 要求将里面的字符取出,也就是说按照数字拆分
String str = "A1B22C333D4444E55555F" ; // 指定好一个字符串
String pat = "\\d+" ; // 指定好正则表达式
Pattern p = Pattern.compile(pat) ; // 实例化Pattern类
String s[] = p.split(str) ; // 执行拆分操作
for(int x=0;x<s.length;x++){
System.out.print(s[x] + "\t") ;
}
}
};
还可以使用Matcher类中的字符串替换功能。
例:将字符串中的全部数字替换成“_”:
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
public class RegexDemo05{
public static void main(String args[]){
// 要求将里面的字符取出,也就是说按照数字拆分
String str = "A1B22C333D4444E55555F" ; // 指定好一个字符串
String pat = "\\d+" ; // 指定好正则表达式
Pattern p = Pattern.compile(pat) ; // 实例化Pattern类
Matcher m = p.matcher(str) ; // 实例化Matcher类的对象
String newString = m.replaceAll("_") ;
System.out.println(newString) ;
}
};
只要使用正则的验证规则,就可以匹配各种复杂的字符串。
String类对正则的支持
从之前的操作中,可以发现,很多的代码除了要求的字符串不同,使用的正则规则不同,基本上就没有什么特别的。所以在JDK1.4之后,JAVA对正则进行了一些扩充,在String中开始直接支持正则的操作。
在String类中有以下三个方法是支持正则操作的:
NO
方法
类型
描述
1
public Boolean matches(String regex)
普通
字符串匹配
2
public String replaceAll(String regex,String replacement)
普通
字符串替换
3
public String[] split(String regex)
普通
字符串拆分
例:
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
public class RegexDemo06{
public static void main(String args[]){
String str1 = "A1B22C333D4444E55555F".replaceAll("\\d+","_") ;
boolean temp = "1983-07-27".matches("\\d{4}-\\d{2}-\\d{2}") ;
String s[] = "A1B22C333D4444E55555F".split("\\d+") ;
System.out.println("字符串替换操作:" + str1) ;
System.out.println("字符串验证:" + temp) ;
System.out.print("字符串的拆分:") ;
for(int x=0;x<s.length;x++){
System.out.print(s[x] + "\t") ;
}
}
};
但是,在使用正则的时候有一点是需要特别注意的。
现在假设有如下的一个字符串的拆分程序:
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
public class RegexDemo07{
public static void main(String args[]){
String info = "LXH:98|MLDN:90|LI:100" ; // 定义一个字符串
// 拆分的形式:
/*
LXH --> 98
MLDN --> 90
LI --> 100
*/
String s[] = info.split("\\|") ;
System.out.println("字符串的拆分:") ;
for(int x=0;x<s.length;x++){
String s2[] = s[x].split(":") ;
System.out.println(s2[0] + "\t" + s2[1]) ;
}
}
};
如果有时候发现一个字符串无法按照指定的字符拆分的话,则需要使用“\”转义,转义的时候两个“\”表示一个“\”。
11-5-15、JAVA常用类库-定时调度
定时调度就是每当一段时间,程序会自动执行。
如果要使用定时调度,则必须保证程序始终运行,也就是相当于定时调度是在程序外又启动了一个新的线程。
Timer类
Timer类是一种线程设施,可以用来实现在某一个时间或某一段时间后安排某一个任务执行一次,或定期重复执行。该功能要与TimerTask配合使用。TimerTask类用来实现由Timer安排的一次或重复执行的某一个任务。
每一个Timer对象对应的是一个线程,因此计时器所执行的任务应该迅速完成,否则可能会延迟后续任务的执行,而这些后续的任务就有可能堆在一起,等到该任务完成后才能快速连续执行。
Timer类中的常用方法
NO
方法
类型
描述
1
public Timer()
构造
用来创建一个计时器并启动该计时器
2
public void cancel()
普通
用来终止该计时器,并放弃所有已安排的任务,对当前正在执行的任务没有影响
3
public int purge()
普通
将所有已经取消的任务移除,一般用来释放内存空间
4
public void schedule(TimerTask task,Date time)
普通
安排一个任务在指定的时间执行,如果已经超过该时间,则立即执行。
5
public void schedule(TimerTask task,Date firstTime,long period)
普通
安排一个任务在指定的时间执行,之后以固定的频率(单位:毫秒)重复执行。
6
public void schedule(TimerTask task,long delay)
普通
安排一个任务在一段时间(单位:毫秒)后执行,之后以固定的频率(单位:毫秒)重复执行。
7
public void schedule(TimerTask task,long delay,long period)
普通
安排一个任务在一段时间(单位:毫秒)后执行,之后以固定的频率(单位:毫秒)重复执行。
8
public void scheduleAtFixedRate(TimerTask task,Date firstTimer,long period)
普通
安排一个任务在指定的时间执行,之后以近似固定的频率(单位:毫秒)重复执行。
9
public void scheduleAtFixedRate(TimerTask task,long delay,long period)
普通
安排一个任务在一段时间(单位:毫秒)后执行,之后以近似固定的频率(单位:毫秒)重复执行。
schedule()与scheduleAtFixedRate()方法的区别:
两者的区别在于重复执行任务时,对于时间间隔出现延迟的情况处理:
schedule()方法的执行时间间隔永远是固定的,如果之前出现了延迟的情况,之后也会继续按照设定好的间隔时间来执行。
scheduleAtFixedRate()方法可以根据出现的延迟时间自动调整下一次间隔的执行时间。
TimerTask类
要想执行具体的任务,则必须使用TimerTask类。TimerTask是一个抽象类,如果要使用该类,需要自己建立一个类来继承此类,并实现其中的抽象方法。
TimerTask类方法
NO
方法
类型
描述
1
public void cancel()
普通
用来终止此任务,如果该任务只执行一次且还没有执行,则永远不会再执行,如果为重复执行任务,则之后不会再执行(如果任务正在执行,则执行完后不会再执行)
2
public void run()
普通
该任务所要执行的具体操作,该方法为引入的接口Runnable中的方法,子类需要覆写此方法。
3
public long scheduleExecutionTime()
普通
返回最近一次要执行该任务的时间(如果正在执行,则返回此任务的执行安排时间),一般在run()方法中调用,用来判断当前是否有足够的时间来执行完成该任务。
如果现在一个Timer类要想调度程序的话,则需要使用TimerTask的子类。
就依照此概念,完成一个定时调度的程序,每隔2秒打印一次时间:
// 完成具体的任务操作
import java.util.TimerTask ;
import java.util.Date ;
import java.text.SimpleDateFormat ;
class MyTask extends TimerTask{ // 任务调度类都要继承TimerTask
public void run(){
SimpleDateFormat sdf = null ;
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
System.out.println("当前系统时间为:" + sdf.format(new Date())) ;
}
};
完成的是一个具体的任务操作类,以后定时调度就调度的是此类的操作,方法的主体就是run()方法。建立测试类,并执行任务调度:
import java.util.Timer ;
public class TestTask{
public static void main(String args[]){
Timer t = new Timer() ; // 建立Timer类对象
MyTask mytask = new MyTask() ; // 定义任务
t.schedule(mytask,1000,2000) ; // 设置任务的执行,1秒后开始,每2秒重复
}
};
一般在web的开发中此内容比较有用,因为要维护一个容器不关闭才可以一直定时操作下去。
标签: #java系统类库