可以直接使用java.util.Arrays类进行数组的排序操作,但对象所在的类必须实现Comparable接口,用于指定排序接口。
Comparable接口定义如下:
public interface Comparable<T>{ public int compareTo(T o); }
从接口的定义格式上来看,可以发现如果想实现对象属性的排序功能,要实现Comparable接口,并且覆写compareTo(T o)方法。此方法返回的是一个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"+age+"\t\t"+score+"\t\t"; } public int compareTo(Student stu){ //覆写compareTo方法,实现排序规则的应用 if(this.score<stu.score){ return -1; } if(this.score>stu.score){ return 1; } else{ if(this.age<stu.age){ return -1; } if(this.age>stu.age){ return 1; } else{ return 0; } } } } public class ComparableDemo01 { public static void main(String args[]){ Student stu[]={ new Student("张三",20,89.1f), new Student("李四",26,53.5f), new Student("王五",30,79.0f), new Student("赵六",20,66.0f), new Student("孙七",25,66.0f) }; java.util.Arrays.sort(stu); //进行排序操作 for(Student x:stu){ //循环输出 System.out.println(x); } } }
注意:如果在此时Student类没有实现Comparable接口,则在执行的时候会出现一下异常:
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable
此比较器其实跟Comparable是非常类似的。如果现在已经完成了一个类的开发,但是并没有实现Comparable接口,此时肯定是无法进行对象排序操作的,所以为了解决这种问题,java又定义了另一个比较器的操作接口---Comparator。此接口在java.util包中,接口如下定义:
pubic interface Comparator<T>{ public int compare(T o1,T o2); boolena equals(Object obj); }
代码如下:
import java.util.*; class 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 void setName(String name){ this.name=name; } public String getName(){ return name; } public void setAge(int age){ this.age=age; } public int getAge(){ return age; } public String toString(){ return name+"\t\t"+age+"\t\t"+score+"\t\t"; } } 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 ComparableDemo02 { public static void main(String args[]){ Student stu[]={ new Student("张三",20,89.1f), new Student("李四",26,53.5f), new Student("王五",30,79.0f), new Student("赵六",20,66.0f), new Student("孙七",25,66.0f) }; java.util.Arrays.sort(stu,new StudentComparator()); //进行排序操作 for(Student x:stu){ //循环输出 System.out.println(x); } } }
总结:在开发中尽量还是使用Comparable在需要排序的类上实现好此接口,而Comparator需要单独建立一个排序的类,这样如果有很多的话,则排序的规则类也就会很多,操作起来比较麻烦些。注意:在java中只要是对象排序,永远都是以Comparable接口为准的。
所谓观察者设计模式,就是某一样东西被多个观察者观察,当这样东西发生变化,则会及时反馈到每个观察者的身上。如果要想实现观察者设计模式,则必须依靠java.util包中的Observable类和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) ; // 输出房子价格 } };
正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证、拆分、替换等功能。
例如:现在要求判断一个字符串是否由数字组成,有以下两种方式:
·不使用正则完成
·使用正则完成
第一种方式代码:
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("不是由数字组成!") ; } } };
这两个类为正则的核心操作类,都是定义在java.util.regex包中。Pattern类主要是进行正则规范(如之前的操作“[0-9]“就属于正则规范)的编写,而Matcher类主要是执行规范,验证一个字符串是否符合规范。
常用正则规则:
·\d:表示数字, [0-9]
·\D:表示非数字,[^0-9]
·\w:表示字母、数字、下划线,[a-zA-Z0-9]
·\W:[^a-zA-Z0-9]
常用正则规范2:
以上的正则,如果要想驱动起来,则必须依靠Pattern和Matcher类。
Pattern主要是表示一个规则的意思,即:正则表达式的规则需要在Pattern类中使用。
Matcher类主要表示使用Pattern指定好的规则验证。
Pattern类的常用方法:
方法 |
描述 |
public static Pattern compile(String regex) |
指定正则表达式规则 |
public Matcher matcher(CharSequence input) |
返回Mather类的实例 |
public String[] split(CharSequence input) |
字符串拆分 |
在Patter类中如果要想取得Pattern类的实例,则必须调用compile()方法。
本类中没有明确的构造方法可以使用,那么此类的构造方法肯定被私有化了,如果是这样的类,都可以通过本类中的一个静态方法获得该类的实例。
Matcher类中的常用方法:
方法 |
描述 |
Public Boolean matches() |
执行验证 |
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类中有以下三个方法是支持正则操作的:
方法 |
描述 |
public boolean matches(String regex) |
字符串匹配 |
public String replaceAll(String regex,String replacement) |
字符串替换 |
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]) ; } } };
如果有时候发现一个字符串无法按照指定的字符拆分的话,则需要使用“\”转义,转义的时候连个“\”表示一个“\”。
总结:
1、 使用正则可以方便完成字符串的验证、拆分、替换等功能。
2、 在开发中一般会使用String类提供好的正则支持,很少使用Pattern或者是Matcher类。
3、 在使用一些正则的时候,对于一些敏感的字符要进行转义。
定时调度:每隔一段时间,程序会自动执行,成为定时调度。
如果要使用定时调度,则必须保证程序运行这才可以,也就说是相当于定时调度在程序之外又启动了一个新的线程。使用Timer和TimerTask两个类完成定时调度。
Timer类是一种线程设施,可以用来实现在某一个时间或某一段时间后,安排某一个任务执行一次,或定期重复执行。该功能要与TimerTask类配合使用。TimerTask类用来实现由Timer安排的一次或重复执行的某一个任务。
Timer类的常用方法:
方法 |
类型 |
描述 |
public Timer() |
构造 |
用来创建一个计时器并启动 |
public void cancel() |
普通
|
用来终止该计时器,并放弃所有已安排的任务,对当前正在执行的任务没有影响。 |
public int purge() |
普通 |
将所有已经取消的任务移除,一般用来释放内存空间 |
public void schedule(TimerTask task,Date time) |
普通
|
安排一个任务在指定的时间执行,如果已经超过该时间,则立即执行。 |
public void scheduleAtFixedRate(TimerTask task,Date firstTime,long period) |
普通 |
安排一个任务在指定的时间执行,之后以近似固定的频率(单位:毫秒)重复执行 |
Schedule()与scheduleAtFixedRate()方法的区别:
两者的区别在于重复执行任务时,对于时间间隔出现延迟的情况处理: ·Schedule()方法的执行时间间隔永远是固定的,如果之前出现了延迟的情况,之后也会按照设定好的间隔时间执行。 ·scheduleAtFixedRate()方法可以根据出现的延迟时间自动调整下一次间隔的执行时间。 |
要想执行具体的任务,则必须使用TimerTask类。TimerTask是一个抽象类,如果要使用该类,需要建立一个子类继承该类,并实现其中的抽象方法。
方法 |
描述 |
public void cancle()
|
用来终止此任务,如果该任务只执行一次并且还没有执行,则永远不会再执行,如果为重复执行任务,则之后不会再执行(如果该任务正在执行,则执行完后不会再执行) |
public void run() |
该任务所要执行的具体操作,该方法为引入接口Runable中的方法,子类需要覆写。 |
public long scheduledExecutionTime()
|
返回最近一次执行任务的时间(如果正在运行,则返回该任务的执行安排时间),一般在run()方法中调用,用来判断当前是否有足够的时间来执行完该任务。 |
//完成具体的任务操作 import java.util.*; import java.text.SimpleDateFormat; class MyTask extends TimerTask //任务调度类都要继承TimerTask { public void run(){ SimpleDateFormat sd=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); System.out.println("当前系统时间为:"+sd.format(new Date())); } }
完成的是一个具体的任务操作类,以后定时调度就是调度此类的操作,方法的主体就是run()方法。注意要继承TimerTask类,下面建立测试类,并执行任务调度:
import java.util.*; public class TestTask { public static void main(String args[]){ Timer t=new Timer(); MyTask mytask=new MyTask(); t.schedule(mytask,1000,2000); } }
总结:一般在web开发中此内容比较有用,因为要维护一个容器不关闭才可以一直定时调度下去。