Step By Step(Java 常用对象篇<二>)
1. Calendar:
对于每一个Java的开发者而言,这是一个再熟悉不过的对象了,这里我们给出一个巧妙的例子,至于如何巧妙,看了输出结果就清楚了。
1 public class MyTest {
2 public static void main(String args[]) {
3 GregorianCalendar d = new GregorianCalendar();
4 int today = d.get(Calendar.DAY_OF_MONTH);
5 int month = d.get(Calendar.MONTH);
6 // set d to the first date of the month
7 d.set(Calendar.DAY_OF_MONTH, 1);
8 int weekday = d.get(Calendar.DAY_OF_WEEK);
9 // get first day of week(Sunday in the U.S.)
10 int firstDayOfWeek = d.getFirstDayOfWeek();
11 // determine the required indentation for the first line
12 int indent = 0;
13 while (weekday != firstDayOfWeek) {
14 ++indent;
15 d.add(Calendar.DAY_OF_MONTH, -1);
16 weekday = d.get(Calendar.DAY_OF_WEEK);
17 }
18 // print weekday names
19 String[] weekdayNames = new DateFormatSymbols().getShortWeekdays();
20 do {
21 System.out.printf("%4s", weekdayNames[weekday]);
22 d.add(Calendar.DAY_OF_MONTH, 1);
23 weekday = d.get(Calendar.DAY_OF_WEEK);
24 } while (weekday != firstDayOfWeek);
25 System.out.println();
26
27 for (int i = 1; i <= indent; ++i)
28 System.out.print(" ");
29
30 d.set(Calendar.DAY_OF_MONTH, 1);
31 do {
32 // print day
33 int day = d.get(Calendar.DAY_OF_MONTH);
34 System.out.printf("%5d", day);
35 // mark current day with *
36 if (day == today)
37 System.out.print("*");
38 else
39 System.out.print(" ");
40 // advance d to the next day
41 d.add(Calendar.DAY_OF_MONTH, 1);
42 weekday = d.get(Calendar.DAY_OF_WEEK);
43 // start a new line at the start of the week
44 if (weekday == firstDayOfWeek)
45 System.out.println();
46 } while (d.get(Calendar.MONTH) == month);
47 // the loop exists when d is day 1 of the next month
48
49 // print final end of line if neccessary
50 if (weekday != firstDayOfWeek)
51 System.out.println();
52 }
53 }
54 /* 输出结果如下:
55 星期日 星期一 星期二 星期三 星期四 星期五 星期六
56 1 2 3
57 4 5 6 7* 8 9 10
58 11 12 13 14 15 16 17
59 18 19 20 21 22 23 24
60 25 26 27 28 29 30
61 */
2. java.utils.Arrays:
该类为我们提供了很多操作数组的方法,他们都是非常方便且高效的,很多时候比我们自行实现的数组操作要高效的多,然而有的时候它却并不为我们所熟知。记得我第一次用到他们的时候,那时我已经使用Java开发有一段时间了,当时的感觉立刻使我想起了很多C语言的CRT函数,如memset、memcpy等,还有一些C++标准库中用到的泛型算法,确实有一种一见如故的感觉。这里只是列出了一些常用的静态域方法,还需要提醒的是Java的集合框架中也提供了Collections工具类,其作用和Arrays有些相仿,只是主要作用于集合框架中的各个容器类。
int binarySearch(type[] a,type key)
这个方法查询key元素值在a数组中出现的索引;如果a数组不包含key元素值,则返回负一。调用该方法时要求数组中元素已经按升序排列,这样才能得到正确结果。
binarySearch(type[] a,int fromIndex,int toIndex,type key)
这个方法与前一个方法类似,但它只搜索a数组中formIndex到toIndex索引的元素。调用该方法时要求数组中元素已经按升序排列,这样才能得到正确结果。
type[] copyOf(type[] original,int newLength)
这个方法将会把original数组复制成一个新数组,其中length是新数组的长度。如果length小于original数组的长度,则新数组就是原数组的前面length个元素;如果length大于original数组的长度,则新数组的前面元素就是原数组的所个元素,后面补充0(数值型)、false(布尔型)或者null(引用型)。
type[] copyOfRange(type[] original,int from,int to)
这个方法与前面方法相似,但这个方法只复制original数组的from索引到to索引的元素。
boolean equals(type[] a,type[] a2)
如果a数组和a2数组的长度相等,而且a数组和a2数组的数组元素也一一相同,该方法将返回true.
void fill(type[] a,type val)
该方法将会把a数组所有元素值都赋值为val.
void fill(type[] a,int fromIndex,int toIndex,type val)
该方法与前一个方法的作用相同,区别只是该方法仅仅将a数组的fromIndex到toIndex索引的数组元素赋值为val.
void sort(type[] a)
该方法对a数组的数组元素进行排序。
void sort(type[] a,int fromIndex,int toIndex)
该方法与前一个方法相似,区别是该方法仅仅对fromIndex到toIndex索引的元素进行排序。
1) 一个基本的示例代码:
1 public static void main(String[] args) {
2 int[] a1 = new int[]{3,4,5,6};
3 int[] a2 = new int[]{3,4,5,6};
4 //a1数组和a2数组的长度相等,每个元素依次相等,将输出true
5 System.out.println("a1数组和a2数组是否相等:" + Arrays.equals(a1,a2));
6 //通过复制a数组,生成一个新的b数组
7 int[] b = Arrays.copyOf(a1,6);
8 System.out.println("a1数组和b数组是否相等:" + Arrays.equals(a1,b));
9 //输出b数组的元素,将输出[3, 4, 5, 6, 0, 0]
10 System.out.println("b数组的元素为:" + Arrays.toString(b));
11 //将b数组的第3个元素(包括)到第5个元素(不包括)赋为1
12 Arrays.fill(b,2,4,1); //fill方法可一次对多个数组元素进行批量赋值
13 //输出b数组的元素,将输出[3, 4, 1, 1, 0, 0]
14 System.out.println("b数组的元素为:" + Arrays.toString(b));
15 //对b数组进行排序
16 Arrays.sort(b);
17 //输出b数组的元素,将输出[0, 0, 1, 1, 3, 4]
18 System.out.println("b数组的元素为:" + Arrays.toString(b));
19 }
20 /* 输出结果如下:
21 a1数组和a2数组是否相等:true
22 a1数组和b数组是否相等:false
23 b数组的元素为:[3, 4, 5, 6, 0, 0]
24 b数组的元素为:[3, 4, 1, 1, 0, 0]
25 b数组的元素为:[0, 0, 1, 1, 3, 4]
26 */
2) 和java.utils.Arrays中提供的数组copy相比,Java中还提供另外一个数组copy的方法:System.arraycopy();
void arraycopy(Object from,int fromIndex,Object to,int toIndex,int count)
将第一个数组中的元素copy到第二个数组中。
from: 任意类型的数组
fromIndex: 原始数组中待copy元素的启示下标
to: 与from同类型的数组
toIndex: 目标数组放置copy元素的起始下标
count: copy的元素数量
1 public static void main(String[] args) {
2 int[] arr1 = {1, 2, 3, 4, 5};
3 int[] arr2 = new int[5];
4 System.arraycopy(arr1, 0, arr2, 0, arr1.length);
5 for(int i = 0; i < arr2.length; i++)
6 System.out.print(arr2[i] + " ");
7 System.out.println();
8 }
9 /* 输出结果如下:
10 1 2 3 4 5
11 */
3) 比较System.arraycopy和通过手工赋值方式copy数组数据在执行效率上的差异:
1 public static void main(String args[]) {
2 final int testLength = 100000;
3 int[] arr1 = new int[testLength];
4 int[] arr2 = new int[testLength];
5 for (int i = 0; i < testLength; ++i) {
6 arr1[i] = i;
7 }
8 long start = System.currentTimeMillis();
9 for (int j = 0; j < 1000; ++j)
10 System.arraycopy(arr1, 0, arr2, 0, arr1.length);
11 long elapse = System.currentTimeMillis() - start;
12 System.out.println("The elapse for System.arraycopy is " + elapse + " ms");
13
14 start = System.currentTimeMillis();
15 for (int i = 0; i < 1000; ++i) {
16 for (int j = 0; j < testLength; ++j)
17 arr2[j] = arr1[j];
18 }
19 elapse = System.currentTimeMillis() - start;
20 System.out.println("The elapse for normal copy is " + elapse + " ms");
21 }
22 /* 输出结果如下:
23 The elapse for System.arraycopy is 187 ms
24 The elapse for normal copy is 297 ms
25 */
3. 类加载器:ClassLoader
Java程序中所有的class都是通过JVM的类加载器机制来进行加载、链接和解析并最终生成本地的可执行码后再被执行的。每个Java的程序都至少拥有三个类加载器:
1) 引导类加载器(bootstrap classlClassLoader) 引导类加载负责加载系统类,如rt.jar等,它是JVM整体中的一部分,通常都是用c语言来实现的,引导类加载器没有对应的ClassLoader对象,因此当执行String.class.getClassLoader()时,将返回null。
2) 扩展类加载器(extension classlClassLoader)
它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。这为引入除Java核心类以外的新功能提供了一个标准机制。
3) 系统类加载器(system classloader)
它负责在JVM被启动时,加载CLASSPATH所指定的JAR类包和类路径。通过ClassLoader.getSystemClassLoader()方法可以找到该类加载器。
以上三个类加载器之间存在一种父子关系,需要明确说明的是这种父子关系并非继承链上的超类和子类之间的关系,而是ClassLoader内部都维护着一个指向其parent类加载器的对象引用,这种关系有些类似于树中子节点和父节点之间的关系。因此在得到system classloader的之后,再想获得extension classlClassLoader就非常容易了,如调用ClassLoader.getSystemClassLoader().getParent()方法将返回扩展类加载器的对象引用,如果继续调用扩展类加载器的getParent()方法,如ClassLoader.getSystemClassLoader().getParent().getParent(),原本该调用之后应该返回引导类加载器(bootstrap classlClassLoader)的对象引用,然而由于该类并非Java对象,因此该调用将返回null。由于String是由引导类加载器来加载的,我们也可以通过以下调用来验证这一结果。
1 public static void main(String[] args) {
2 System.out.println(String.class.getClassLoader());
3 }
4 /* 输出结果为:
5 null
6 */
对于我们自定义的ClassLoader,如果没有明确的指定,其确实的parent将指向系统类加载器(system classloader)。
ClassLoader加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个ClassLoader加载一个Class的时候,这个Class所依赖的和引用的所有Class也由这个ClassLoader负责载入,除非是显式的使用另外一个ClassLoader载入;委托机制则是先让parent(父)类加载器寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必须重新启动JVM才能生效的原因。
每个ClassLoader加载Class的过程是:
1) 检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2) 如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4
3) 请求parent classloader载入,如果成功到8,不成功到5
4) 请求jvm从bootstrap classloader中载入,如果成功到8
5) 寻找Class文件(从与此classloader相关的类路径中寻找)。如果找不到则到7.
6) 从文件中载入Class,到8.
7) 抛出ClassNotFoundException.
8) 返回Class.
事实上对于绝大多数的应用场景,我们均不需要实现自定义的ClassLoader,Java中已有的三个ClassLoader已经足够完成几乎所有的工作了,那么自定义ClassLoader的应用场合又是什么呢?这里可以给出一个常用的case。众所周知,Java编译后的.class很容易被反编译工具翻译回原有的.java文件,这样便会给系统带来一些潜在的风险和不安定因素,出于安全方面考虑,我们需要将编译后的.class文件进一步加密,而加密后的文件,是无法通过JVM自带的三个ClassLoader完成正常加载工作的,因此这里就需要我们实现自定义的ClassLoader,该加载器将会在读入加密的.class文件之后,在内存中进行解密,再将解密后的字节码交给JVM去继续执行。这里需要提醒注意的是,对于需要动态加载的普通插件jar包,我们并不需要通过自定义的ClassLoader来完成其加载工作,而是直接使用URLClassLoader即可,见如下代码:
1 public void testLoader() {
2 URL u = new URL("file:///path/plugin.jar");
3 URLClassLoader pluginLoader = new URLClassLoader(new URL[] { u });
4 Class<?> c = pluginLoader.loadClass("mypackage.MyClass");
5 }
对于自定义的类加载器类,我们需要扩展自ClassLoader,按照JDK的推荐,我们只需在子类中重载findClass方法。在通过父类加载器检查所请求的类后,此方法将被loadClass方法调用。以下的示例代码将会在读入.class文件之后模拟解密的操作,再将解密后的字节码作为参数交给ClassLoader.defineClass方法并返回预定义类的Class对象。
1 //FileClassLoader为自定义的ClassLoader
2 public class FileClassLoader extends ClassLoader {
3 public static final String drive = "d:/";
4 public static final String fileType = ".class";
5 public FileClassLoader() {
6 super();
7 }
8 public FileClassLoader(ClassLoader arg0) {
9 super(arg0);
10 }
11 public Class<?> findClass(String name) {
12 byte[] data = loadClassData(name);
13 return defineClass(name, data, 0, data.length);
14 }
15 public byte[] loadClassData(String name) {
16 FileInputStream fis = null;
17 byte[] data = null;
18 try {
19 fis = new FileInputStream(new File(drive + name + fileType));
20 ByteArrayOutputStream baos = new ByteArrayOutputStream();
21 int ch = 0;
22 //可以在这里完成读入后解密再回写的byte数组中的操作。
23 while ((ch = fis.read()) != -1)
24 baos.write(ch);
25 data = baos.toByteArray();
26 } catch (IOException e) {
27 e.printStackTrace();
28 }
29 return data;
30 }
31 }
32 //该测试类为将被FileClassLoader加载的class
33 public class MyApp {
34 private static int ii = 0;
35 static {
36 ii = 10;
37 System.out.println("Static block is initialized.");
38 }
39
40 public void print() {
41 System.out.println("ii = " + ii);
42 System.out.println("This is MyApp.print");
43 }
44 }
45 //以下代码为测试自定义ClassLoader调用的代码
46 public static void main(String[] args) throws Exception {
47 //如果将MyApp.class文件同时放到D:/根目录和应用程序当前的bin目录下时,
48 //会发现MyApp的类加载器不在是FileClassLoader,而是sun.misc.Launcher$AppClassLoader,
49 //因为AppClassLoader作为FileClassLoader的parent已经加载了该class,
50 //因此FileClassLoader将不会再重新加载该class。
51 FileClassLoader loader = new FileClassLoader();
52 Class<?> objClass = loader.loadClass("MyApp");
53 System.out.println("Begin to getMethod");
54 Method m = objClass.getMethod("print");
55 System.out.println("Begin to newInstance.");
56 Object obj = objClass.newInstance();
57 System.out.println("Begin to invoke.");
58 m.invoke(obj);
59 System.out.println(objClass.getName());
60 System.out.println(objClass.getClassLoader());
61 }
62 /* 输出结果如下:
63 Begin to getMethod
64 Begin to newInstance.
65 Static block is initialized.
66 Begin to invoke.
67 ii = 10
68 This is MyApp.print
69 MyApp
70 FileClassLoader@1d7ad1c
71 */
在介绍关于ClassLoader的最后,我们来讨论一下Class.forName("className")和loader.loadClass("className")两者之间的区别。
Class.forName()包含两个Overload的方法,我们经常使用的Class.forName(name)方法,在其实现的内部将会调用另一个Class.forName(name,initialize,loader)方法,其等同于Class.forName(name,true,CallClass.class.getClassLoader())的调用。这里的第二个参数表示装载类的时候是否初始化该类,即是否调用类的静态块的语句及初始化静态成员变量。而Class c = ClassLoader.loadClass(name)没有指定是否初始化的选项。因此在调用该方法时,被调用类的静态块代码不会被执行,静态变量也不会被初始化,只有在执行c.newInstance()后才能够初始化类。因此我们可以将loadClass()等同于Class.forName(name,false,cl)的调用。从上面的例子我们也可以看出,MyApp对象的静态块初始化代码的调用是在main函数执行了newInstance之后完成的。
下面的示例代码为通过手工方式加载Oracle的JDBC驱动jar包,以便我们更清楚的区分两者之间的差异:
1 public static void main(String[] args) {
2 String filename = "file:///C:/oracle/product/10.2.0/db_1/jdbc/lib/ojdbc14.jar";
3 URL u = new URL(filename);
4 URLClassLoader cl = new URLClassLoader(new URL[]{u});
5 Class<?> c = cl.loadClass("oracle.jdbc.driver.OracleDriver");
6 System.out.println(c.getClassLoader());
7 c.newInstance();
8 System.out.println("Over.");
9 }
如果替换为我们熟悉的Class.forName()加载方式,见如下代码:
1 public static void main(String[] args) throws Exception {
2 String filename = "file:///C:/oracle/product/10.2.0/db_1/jdbc/lib/ojdbc14.jar";
3 URL u = new URL(filename);
4 URLClassLoader cl = new URLClassLoader(new URL[]{u});
5 Class<?> c = Class.forName("oracle.jdbc.driver.OracleDriver");
6 System.out.println(c.getClassLoader());
7 System.out.println("Over.");
8 }
9 /* 输出结果均为:
10 sun.misc.Launcher$AppClassLoader@ad3ba4
11 Over.
12 */
4. ProcessBuilder:
在实际开发中,我们常常为了节省开发成本和缩短开发周期,会充分利用操作系统为我们提供的shell命令来获取一些和系统相关的信息,同时导入他们的输出结果并加以分析,这样做不仅降低了开发的难度,也节省了大量的开发时间。这里我们将提供一段示例代码来演示Java的程序如何利用这些shell命令来完成自己的功能需求。
1 public class MyTest {
2 private static void execNotepadAndWait() {
3 try {
4 ProcessBuilder proc = new ProcessBuilder("notepad.exe", "testfile");
5 proc.start();
6 //阻塞父进程直到子进程结束。
7 proc.wait();
8 } catch (Exception e) {
9 System.out.println("Error executing notepad.");
10 }
11 }
12 private static void forkProcessAndGetInputStream() throws IOException {
13 //启动子进程
14 Process process = new ProcessBuilder("java","-h").start();
15 //从子进程中获取其输出信息作为当前程序的输入流。
16 InputStream is = process.getInputStream();
17 //以文本字符的方式读入,以便后面可以按行读取。
18 InputStreamReader isr = new InputStreamReader(is);
19 BufferedReader br = new BufferedReader(isr);
20 String line = null;
21 while ((line = br.readLine()) != null) {
22 System.out.println(line);
23 }
24 }
25 public static void main(String args[]) throws IOException {
26 forkProcessAndGetInputStream();
27 execNotepadAndWait();
28 }
29 }
5. 正则表达式:
这里给出的基本都是Java中正则表达式的示例代码,至于基础的语法规则,只是通过在代码中加上适当的注释,再结合输出结果的方式予以介绍,如果确实需要系统学习的,网上有很多很多优秀的文章详细介绍了这方面的知识。好吧,现在让我们开始吧。
1) 通用的规则和使用方法:
1 public static void main(String[] args) {
2 //这里\表示转义符,双斜杠\\表示一个\,\w表示所有的字母,
3 //不分大小写,\s表示空格符,如" \n\r\t",\d表示数字
4 Pattern patt = Pattern.compile("(\\w+)\\s(\\d+)");
5 Matcher matcher = patt.matcher("Bananas 123");
6 matcher.lookingAt();
7 System.out.println("Name: " + matcher.group(1));
8 System.out.println("Number: " + matcher.group(2));
9 //^q表示以q开头的,其中^字符在这个上下文中表示以...开头。
10 //[^u]表示所有不是u的字符都合法, 在[^ ]上下文中,^表示取非。
11 //\.表示dot的原意,因为该字符为meta字符,表示任意字符,加上
12 //转义符之后就只是表示原意了。
13 String pattern = "^q[^u]\\d+\\.";
14 String input = "QA777. is the next flight. It is on time.";
15 Pattern reCaseInsens = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
16 Pattern reCaseSens = Pattern.compile(pattern);
17 Matcher m = reCaseInsens.matcher(input); // will match any case
18 boolean found = m.lookingAt(); // will match any case
19 System.out.println("IGNORE_CASE match " + found);
20 m = reCaseSens.matcher(input); // Get matcher w/o case-insens flag
21 found = m.lookingAt(); // will match case-sensitively
22 System.out.println("MATCH_NORMAL match was " + found);
23 }
24 /* 输出结果如下:
25 Name: Bananas
26 Number: 123
27 IGNORE_CASE match true
28 MATCH_NORMAL match was false
29 */
2) 利用正则表达式拆分字符串到字符串数组:
1 public static void main(String[] args) {
2 String[] x = Pattern.compile("ian").split("the darwinian devonian explodian chicken");
3 for (int i = 0; i < x.length; i++) {
4 System.out.println(i + " \"" + x[i] + "\"");
5 }
6 }
7 /* 输出结果如下:
8 0 "the darwin"
9 1 " devon"
10 2 " explod"
11 3 " chicken"
12 */
3) 在String中应用正则表达式:
1 public static void main(String[] args) {
2 String pattern = ".*Q[^u]\\d+\\..*";
3 String line = "Order QT300. Now!";
4 if (line.matches(pattern)) {
5 System.out.println(line + " matches \"" + pattern + "\"");
6 } else {
7 System.out.println("NO MATCH");
8 }
9 }
10 /* 输出结果如下:
11 Order QT300. Now! matches ".*Q[^u]\d+\..*"
12 */
4) 正则表达式和CharSequence:
1 public class TestMain {
2 public static void testSearchAndReplace() {
3 Pattern p = Pattern.compile("(i|I)ce");
4 String candidateString = "I love ice. Ice is my favorite. Ice Ice Ice.";
5
6 Matcher matcher = p.matcher(candidateString);
7 String tmp = matcher.replaceFirst("Java");
8 System.out.println(tmp);
9 }
10 public static void testSearchAndReplace() {
11 CharSequence inputStr = "a b c a b c";
12 String patternStr = "a";
13 String replacementStr = "x";
14 // 将inputStr中所有的a替换为x
15 Pattern pattern = Pattern.compile(patternStr);
16 Matcher matcher = pattern.matcher(inputStr);
17 String output = matcher.replaceAll(replacementStr);
18 System.out.println(output);
19 }
20 private static void testNormalSearch() {
21 String patternStr = "b";
22 Pattern pattern = Pattern.compile(patternStr);
23 CharSequence inputStr = "a b c b";
24 Matcher matcher = pattern.matcher(inputStr);
25 boolean matchFound = matcher.find();
26 System.out.println(matchFound);
27 //group()将返回find()找到的匹配字符串,可以将其视为s.substring(m.start(), m.end())
28 String match = matcher.group();
29 System.out.println(match);
30 //获取该group的起始下标
31 int start = matcher.start();
32 //获取该group的结束下标
33 int end = matcher.end();
34 System.out.println(start);
35 System.out.println(end);
36 }
37 public static void main(String[] args) {
38 testNormalSearch();
39 testSearchAndReplace();
40 testSearchAndReplace();
41 }
42 }
43 /* 输出结果如下:
44 true
45 b
46 2
47 3
48 x b c x b c
49 I love Java. Ice is my favorite. Ice Ice Ice.
50 */
5) 用正则表达式验证电子邮件地址是否合法:
1 public static void main(String args[]) {
2 String EMAIL_REGEX = "^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$";
3 String email = "user@domain.com";
4 if (email.matches(EMAIL_REGEX)) {
5 System.out.println("This is a valid email.");
6 }
7 }
8 /* 输出结果如下:
9 This is a valid email.
10 */
6) 判断日期的合法性:
1 public static void main(String args[]) {
2 String date = "12/12/1212";
3 String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}";
4 System.out.println(date.matches(datePattern));
5 }
6 /* 输出结果如下:
7 true
8 */
7) 国内带区号的电话号码匹配:
1 public static void main(String args[]) {
2 String phoneNumber = "(010)1234567";
3 //由于(和)都是正则中的meta字符,因此需要在其前面加\,以表示其原始含义。
4 String pattern = "^(\\(0[0-9]{2,3}\\))?[0-9]{7,8}$";
5 System.out.println(phoneNumber.matches(pattern));
6 }
7 /* 输出结果如下:
8 true
9 */
8) 验证IPv4地址的合法性:
1 public class MyTest {
2 public static boolean checkIPV4(String ipAddress) {
3 String regex0 = "(2[0-4]\\d)" + "|(25[0-5])";
4 String regex1 = "1\\d{2}";
5 String regex2 = "[1-9]\\d";
6 String regex3 = "\\d";
7 StringBuilder builder = new StringBuilder(256);
8 builder.append("(").append(regex0).append(")|(").append(regex1)
9 .append(")|(").append(regex2).append(")|(").append(regex3)
10 .append(")");
11 StringBuilder builder2 = new StringBuilder(1024);
12 builder2.append("(").append(builder).append(").(").append(builder)
13 .append(").(").append(builder).append(").(").append(builder)
14 .append(")");
15 Pattern p = Pattern.compile(builder2.toString());
16 Matcher m = p.matcher(ipAddress);
17 return m.matches();
18 }
19
20 public static void main(String args[]) {
21 System.out.println("192.168.0.1 is "
22 + (checkIPV4("192.168.0.1") ? "legal IP" : "illegal IP"));
23 }
24 }
25 /* 输出结果如下:
26 192.168.0.1 is legal IP
27 */