【JavaSE基础】04-常用类API(二)

1、包装类(Wrapper Clas)

(0)、包装类的引入及其描述

先来看一下以下两个主要的需求:

  • 1、输出100的二进制、八进制、十六进制表示
  • 2、判断一个数据是否在 int 范围内

在还没有学习到常用类,没有体会到API提供的强大功能之前,我们可能会首先想到,我该怎么去实现这个需求呢?但是,现在是时候换一个想法了:API提供什么可以直接拿来用的方法了呢?从此刻起,做一名拿来主义。能拿来的绝不自己创造,“ 不要重复创造轮子 ”,并且我们也不会比哪些开发Java 的人写出的方法更优,当然为Java写类库,很酷!

在拿来之前,回想一下,之前来说,我们能够随手拿来的好像都只是引用数据类型的对象,它们在自身类中定义了一些成员方法,创建对象之后就可以去调用,但是基本数据类型(原始数据类型),如何实现呢?

为了对基本数据类型进行更多、更方便的操作,Java为四类八种基本数据类型提供了对应的类类型,亦即包装类(Wrapper Class)。
在这里插入图片描述

最常用的操作:基本类型和字符串的转换。

(1)、Number 抽象类

0:java.lang包下的Number是一个抽象类,在使用的时候,使用的是具体的子类得对象,描述说:抽象类 Number 是 BigDecimal、BigInteger、Byte、Double、Float、Integer、Long 和 Short 类的超类。 Number 的子类必须提供将表示的数值转换为 byte、double、float、int、long 和 short 的方法。

A:成员变量:【Field Summary】没有

B:构造方法:【Constructor Summary】仅有一个无参构造,public Number() { } 抽象类的无参构造仅仅是为了工子类(具体类)初始化使用,不可以创建对象。

C:成员方法:【Method Summary】

  • a、已实现,供子类继承

    • (1)public byte byteValue()

    • (2)public short shortByte

    • 基础语法阶段说明过,byte、short在参与运算的时候会自动提升为int类型,如果想要得到byte、short结果的话,就需要对int类型进行强制类型的转换。已经实现两个方法底层的源码就是将 intValue 方法的返回值进行了一个强制类型的转换。

  • b、尚未实现,供子类重写实现

    • (1)public abstract int intValue()

    • (2)public abstract long longValue()

    • (3)public abstract float floatValue()

    • (4)public abstract double doubleValue()

    • 面向对象抽象类讲解的时候,我们建议大家永远手动给出抽象成员方法的默认修饰符public abstract (无论是接口或是抽象类的抽象方法),这就是原因。Java大师们都给了,你凭什么不给。

(2)、Integer 类 *

0:java.lang包下的Integer类,描述说:Integer 类在对象中包装了一个基本类型 int 的值。 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还提供了处理 int 类型时非常有用的其他一些常量和方法。

A:成员变量:【Field Summary】 静态常量值

  • a、public static final int MAX_VALUE int类型可表示的最大值
  • b、public static final int MIN_VALUE int类型可表示的最小值
  • c、public static final int SIZE int类型所占用的bit位数 32 bit = 4 byte
  • d、public static final int TYPE 代表原始类型int类实例
  • e、public static final int BYTES int类型所占用的byte位数 since JDK 1.8

B:构造方法:【Constructor Summary】

  • a、public Integer(int i) 使用int类型数值 i 创建一个Integer对象
  • b、public Integer(String s) throws NumberFormatException 使用String类型数值 s 创建一个Integer对象。如果给定的s包含无法转换的字符的话,就抛出NumberFormatException 异常。

C:成员方法:【Method Summary】

除了直接继承自Number的6个方法以及少数间接继承自Object的方法外,均为 static 方法(使用Integer类名直接调用)。

  • a、public int intValue() 获取封装在Integer对象中的int值(继承自Number)

  • b、public static int parseInt(String s) 将String类型解码为int类型值。(其实底层是 Integer.parseInt(s, 10);

  • c、public static int parseInt(String s,int radix) throws NumberForMatException 将String类型按照指定进制radix解码为int类型值。如果String中包含有无法转化的字符,则抛出NumberFormatException异常。

  • d、public String toString() 将Integer对象转化为字符串(继承自Object)(其实底层是Integer.toString(int)

  • e、public static String toString(int i) 将int类型值转化为字符串(其实底层是Integer.toString(int i,int radix)

  • f、public static String toString(int i,int radix) 按照指定的进制radix将int类型值转化为字符串。(其中 radix 的值介于 [Character.MIN_RADIX,Character.MAX_RADIX],亦即是[2,36],最小的是二进制,最大是36进制,如果不在该区间之内,则radix默认是 10 。最小的边界二进制很好理解,最大的边界值是因为 0-9 和 a-z 一共36个)

  • g、public static Integer valueOf(int i) 以int类型值创建一个Integer对象

  • h、public static Integer valueOf(String s) throws NumberFormatException 将String类型值解析为int类型值,然后创建一个Integer对象。如果String中包含有无法转化的字符,则抛出NumberFormatException异常。(其实底层是 Integer.valueOf(parseInt(s, 10));也就是 Integer.valueOf(int)

  • i、public static Integer valueOf(String s,int radix) throws NumberFormatException 将String类型值按照指定的radix进制解析为int类型值,然后创建一个Integer对象。如果String中包含有无法转化的字符,则抛出NumberFormatException异常。(其实底层是 Integer.valueOf(parseInt(s, radix));也就是 Integer.valueOf(int)

D:常用编程技巧:【Art of Programming】

  • a、int与String的相互转

  • I、int --> String : 编码
    - (1)字符串拼接:String str = "" + num;
    - (2)借助Integer方法:Integer.toString(int i[, int radix])(推荐使用)、new Integer(int i).toString()(已存在Integer对象 integer 时使用)(如果先使用int创建对象Integer,在调用方法toString方法得到字符串,性能差)
    - (3)借助String方法:String str = String.valueOf(int i)(极力推荐使用

  • II、String --> int : 解码
    - (1)已存在使用String作为参数创建的Integer对象:new Integer(String s).intValue()
    - (2)调用静态解析方法:Integer.parseInt(String s[,int radix])

注意:进制radix的存在是一个约束,当给定了进制的时候,则 int 或 String 中只能存在着 [0 , radix-1] 之间的字符,否则抛出 NumberFormatException 异常。

PS:其他继承自Number的最终类Byte、Short、Long、Float、Double与Integer类像似!

注意:方法源码的分析、模仿

示例:分析ValueOf方法的源码

public final class Integer extends Number implements Comparable<Integer>
{
	private final int value;

	public Integer(int value)
	{
		this.value = value;
	}

	public Integer(String s) throws NumberFormatException
	{
		this.value = parseInt(s, 10);
	}
	
	public static Integer valueOf(int i)
	{
		if (i >= IntegerCache.low && i <= IntegerCache.high)
			return IntegerCache.cache[i + (-IntegerCache.low)];
		return new Integer(i);
	}

	public static Integer valueOf(String s) throws NumberFormatException
	{
		return Integer.valueOf(parseInt(s, 10));
	}

	public static Integer valueOf(String s, int radix)
			throws NumberFormatException
	{
		return Integer.valueOf(parseInt(s, radix));
	}

	/**
	 * Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS.
	 * The cache is initialized on first usage. The size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. During VM initialization, java.lang.Integer.IntegerCache.high property may be set and saved in the private system properties in the sun.misc.VM class.
	 */

	private static class IntegerCache
	{
		static final int low = -128;
		static final int high;
		static final Integer cache[];

		static
		{
			// high value may be configured by property
			int h = 127;
			String integerCacheHighPropValue = sun.misc.VM
					.getSavedProperty("java.lang.Integer.IntegerCache.high");
			if (integerCacheHighPropValue != null)
			{
				try
				{
					int i = parseInt(integerCacheHighPropValue);
					i = Math.max(i, 127);
					// Maximum array size is Integer.MAX_VALUE
					h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
				} catch (NumberFormatException nfe)
				{
					// If the property cannot be parsed into an int, ignore
					// it.
				}
			}
			high = h;

			cache = new Integer[(high - low) + 1];
			int j = low;
			for (int k = 0; k < cache.length; k++)
				cache[k] = new Integer(j++);

			// range [-128, 127] must be interned (JLS7 5.1.7)
			assert IntegerCache.high >= 127;
		}

		private IntegerCache() { }
	}
}

(3)、JDK 5 新特性:自动拆装箱

定义:

  • a、自动装箱(autoboxing):基本类型向类类型的自动转换
  • a、自动拆箱(auto-unboxing):类类型向基本类型的自动装换

示例:使用XJad反编译下面代码的字节码文件

class Demo
{
	public static void main(String args[])
	{
		Integer ii = 100;
		ii += 200;
		System.out.println("ii:"+ii);
	}
}

反编译结果:

import java.io.PrintStream;

class Demo
{
	Demo() { }

	public static void main(String args[])
	{
		Integer ii = 100;
		/** 反编译结果如下:很容易看得出来是 从基本类型到类类型的自动装箱(auto-boxing) */
		/** Integer integer = Integer.valueOf(100); */
		ii += 200;
		/** 反编译结果如下:很容易看得出来是 显示从类类型到基本类型的自动拆箱(auto-unboxing) 之后是 从基本类型到类类型的自动装箱(auto-boxing)*/
		/** integer = Integer.valueOf(integer.intValue() + 200); */
		System.out.println("ii:"+ii);
		/** 反编译结果如下: 
		 *  System.out.println((new StringBuilder()).append("ii:").append(integer).toString()); */
	}
}

面试题

1、分析代码以下代码:(解答在上面

class Demo
{
	public static void main(String args[])
	{
		Integer ii = 100;
		ii += 200;
		System.out.println("ii:"+ii);
	}
}

2、输出以下代码的结果:

class Demo
{
	public static void main(String args[])
	{
		Integer i1 = 127
		Integer i2 = 127
		Integer i3 = 128
		Integer i4 = 128
		System.out.println(i1 == i2);
		System.out.println(i1.euqals(i2));
		System.out.println(i3 == i4);
		System.out.println(i3.euqals(i4));
	}
}

>>> true
    true
    false
    true

解答

  • 针对 -128~127 之间的数据,Integer定义了一个私有静态的内部类Integer$IntegerCache,并在内部类中创建了一个数据缓冲池static final Integer cache[],如果数据在此范围内,则直接返回,并不会申请新的空间(创建对象)。(参看 示例:分析valueOf方法的源码

结论

  • Integer的数据直接赋值(若数值在 -128~127 之间,会直接从缓冲池中返回)。

推论

  • a、Byte、Short、Long 和 Integer 一样,拥有缓冲池,并且数值范围也是 -128~127 之间直接返回;
  • b、Character 则同样拥有一个私有静态内部类,并针对 0~127 之间的字符在内部类中创建了一个数据缓冲池static final char cache[],若数据在这个范围内,则直接返回;
  • c、Boolean 则是只有两个值,没有缓冲池,是true就返回true,是false就返回false,不会申请任何空间,直接返回;
  • d、Float、Double 则没有这样的内部类,更不可能存在着缓冲池了。

附属1、 valueOf(Byte b) 方法 和 内部类源码:

public static Byte valueOf(byte b)
{
    final int offset = 128;
    return ByteCache.cache[(int)b + offset];
}

private static class ByteCache 
{
	private ByteCache(){}
	static final Byte cache[] = new Byte[-(-128) + 127 + 1];

	static
    {
	    for(int i = 0; i < cache.length; i++)
	        cache[i] = new Byte((byte)(i - 128));
	}
}

附属2、 valueOf(Boolean) 方法 源码:

public static Boolean valueOf(boolean b) 
{
	return (b ? TRUE : FALSE);
}

附属3、 valueOf(Character c) 方法 和 内部类源码:

public static Character valueOf(char c) 
{
	if (c <= 127) 
	{ // must cache
		return CharacterCache.cache[(int)c];
	}
	return new Character(c);
}
private static class CharacterCache 
{
	private CharacterCache(){}
	static final Character cache[] = new Character[127 + 1];
	static 
	{
		for (int i = 0; i < cache.length; i++)
			cache[i] = new Character((char)i);
	}
}

(4)、Character 类

在刚刚涉及到String的获取功能时,提供了一个案例:统计字符串中大小写字符和数字以及其他字符的个数。利用String获取功能中的length、charAt、indexOf、lastIndexOf、substring以及判断功能contains,再加上转换功能中的toLowerCase、toUpperCase,给出了三个版本的实现,但是随着这些不同的实现我们慢慢意识到可能已经写的够多了,可以想办法去偷懒了,这就要借助我们的偷懒神奇 - API帮助文档。在我们想要对一串字符进行判断的时候,API 为String类提供了判断功能,它们判定了字符串之间的包含关系、相等关系,以及字符串自身的相关属性。那么如果操作的对象变成了一个字符的话,API 又会提供什么类去封装 什么样的属性和行为,留给我们区使用呢?这就是 Character 类。(String类的底层实现是字符数组,也就是字符的集合)

0:java.lang包下的Character,使用时,不需要导包。描述说:Character 类在对象中包装一个基本类型 char 的值。Character 类型的对象包含类型为 char 的单个字段。 此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然。

A:成员变量:【Filed Summary】 太多,不要求,需要的时候再去看。

B:构造方法:【 Constructor Summary】 仅仅存在一个包装char值得构造方法 public Character(char value),创建对象时,Character c = new Character(char),还有一种简化的方式 Character c = char; (底层原理是Character.valueOf(char) 以类型为char的值创建一个Character对象)

C:成员方法 【Method Summary】:参照操作字符串的String类成员方法分类方式

除了少数接继承自Object的方法外,均为 static 方法(使用Integer类名直接调用)。

  • a、Character 类的判断功能

    • (1)public static boolean isDigit(char ch) 判断指定字符是否为数字
    • (2)public static boolean isLetter(char ch) 判断制定字符是否是字母
    • (3)public static boolean isLowerCase(char ch) 判断制定字符是否是小写字母
    • (4)public static boolean isUpperCase(char ch) 判断制定字符是否是大写字母
    • (5)public static boolean isWhitespace(char ch) 判断指定字符是否为空白字符(‘\n’、‘\t’、‘\r’)
  • b、Character 类的获取功能(仅有一个)

    • (1)public static Character valueOf(char c) 包装指定char值,创建一个Character对象
  • c、Character 类的转换功能

    • (1)public static char toLowerCase(char ch) 将指定字符转换为小写
    • (2)public static char toUpperCase(char ch) 将指定字符转换为大写
    • (3)public static String toString(char c)将指定字符转换为字符串
    • (4)public String toString(char ch) 将指定字符转换为字符串(继承自Object)

重构-示例:统计大小写字符和数字以及其他字符在字符串中出现的次数

package com.rupeng.wrapper;

public class CharDemo
{
	public static void main(String[] args)
	{
		String str = "Hello, rp_12306@rupeng.com ! Welcome to Rupeng. "
				+ "Let's play game -- \"Guess number\".";
		int numCount = 0;
		int chrCount = 0;
		int otherCount = 0;
		char[] chs = str.toCharArray();
		for (int i = 0; i < chs.length; i++)
		{
			if (Character.isDigit(chs[i]))
			{
				numCount++;
			} else if (Character.isLetter(chs[i]))
			{
				chrCount++;
			} else
			{
				otherCount++;
			}
		}
		System.out.println(numCount);
		System.out.println(chrCount);
		System.out.println(otherCount);
	}
}

面试题

1、说说Java常量池?

常量池(方法区中):在编译时就可以确定的数据会被放在常量池中。常量池主要有下面的三个内容:(1)、存放类文件的信息:类名、包名、方法名、字段名和类型…;(2)、存放static final 字段(自定义常量);(3)、7类常量池:字符串和6个基本类型(不包含Float和Double)的包装类的内容。

2、* 疯狂的正则表达式 *

通过上述常用类的学习,我们来看一下下面的需求:

检验一个QQ号码的正确性。要求:(1)长度是5到15位;(2)不可以以0开头;(3)只含有数字

获悉需求之后,通过分析给出以下代码:

示例:QQ号的检验程序!

package com.rupeng.wrapper;

import java.util.Scanner;

/**
 * 需求:检验QQ号的合法性。出现不合法就予以提示 
 * 			 要求:(1)长度是5到15位;(2)不可以以`0`开头;(3)只含有数字
 * 
 * 分析:将QQ号使用String字符串进行接受,方便判断; 
 * 				当出现以上任何一个是不满足的,就给出对应提示信息
 * 
 * 编码:在进行编码的时候,先是基于功能的去实现,不考虑具体的优化。
 * 				但是请注意一件事情:上面这些条件并不是彼此之间互斥(如果使用基本的if...return是不合理的)
 * 				 诸如:(先考虑前两个条件)
 * 				if(length<5||length>15)
 * 				 {
 * 					 out("length is not legal"!);
 * 					 return;
 * 				 }
 * 				 if(firstChar	== '0')
 * 				 {
 * 					 out("firstChar is not legal"!);
 * 					 return;
 * 				 }
 * 咋一看可能觉得是一个结构比较好的程序。但是试着这样的输入 0122(长度不够且以0开头)
 * 		但是给出的提示只是第一个,因为return的关系,以0开头这个问题的提示被屏蔽了。
 *  也就是说这段代码对于基本的功能都没有完成。(基础都没有)
 * 
 * @author Joian
 */
public class QQDemo
{
	public static void main(String[] args)
	{
		System.out.println("Please enter your QQ number: ");
		String QQ = new Scanner(System.in).nextLine();
		if (QQ == null)
		{
			System.out.println("Null");
			return;
		}

		if (QQ.length() < 5 || QQ.length() > 15)
		{
			System.out.println("Length of QQ number is not legal !");
			return;
		}
		for (int i = 0; i < QQ.length(); i++)
		{
			char chr = QQ.charAt(i);
			if (i == 0 && chr == '0')
			{
				System.out.println("Not in the beginning of character 0.");
				return;
			}
			if (chr < '0' || chr > '9')
			{
				System.out.println("Cannot Contain any non numeric characters");
				return;
			}
		}
		System.out.println("QQ number is valid !");
	}
}

功能完整性改进-示例:QQ号的检验程序!

package com.rupeng.wrapper;

import java.util.Scanner;

public class QQDemo2
{
	public static void main(String[] args)
	{
		System.out.println("Please enter your QQ number: ");
		String QQ = new Scanner(System.in).nextLine();
		if (QQ == null)
		{
			System.out.println("Null");
			return;
		}
		int count = 0;
		String[] msg = new String[] { "Length of QQ number is not legal !",
				"Not in the beginning of character 0.",
				"Cannot Contain any non numeric characters" };
		if (QQ.length() < 5 || QQ.length() > 15)
		{
			count++;
		}
		for (int i = 0; i < QQ.length(); i++)
		{
			char chr = QQ.charAt(i);
			if (i == 0 && chr == '0')
			{
				count++;
			}
			if (chr < '0' || chr > '9')
			{
				count++;
			}
		}
		if (count == 0)
		{
			System.out.println("QQ number is valid !");
		} else
		{
			for (int i = 0; i < (count < 3 ? count : 3); i++)
			{
				System.out.println(msg[i]);
			}
		}
	}
}

上面的代码实现太过于繁琐,如果说可以通过一定的规则在实现上会不会更加的easy呢,于是我们在API探索到了“正则表达式”。

先来看看它的强大之处,对于QQ号的检验:

package com.rupeng.wrapper;

import java.util.Scanner;

public class QQDemo3
{
	public static void main(String[] args)
	{
		System.out.println("Please enter your QQ number: ");
		String QQ = new Scanner(System.in).nextLine();
		if (QQ == null)
		{
			System.out.println("Null");
			return;
		}
		String regex = "[1-9][0-9]{4,14}";
		boolean flag = QQ.matcher(regex);
		if(!falg)
		{
			System.out.println("QQ number is not legal");
		}
		else
		{
			System.out.println("QQ number is legal");
		}
	}
}

String类的成员方法

  • public boolean matches(String regex) 判断当前字符串是否满足给定的正则表达式regex 。 调用此方法的str.matches(regex)形式与以下表达式的结果完全相同:Pattern.matches(regex,str)。 若给定的正则表达式无效的话,抛出 PatternSyntaxException 。 since JDK 1.4

A:正则表达式的组成规则

规则字符在java.util.regex.Pattern -public final class Pattern extends Object implements Serializable中,具体的规则如下:

  • a、字符
构造匹配
x字符 x (任意字符表示其本身,例:‘a’)
\\反斜杠字符 ‘’
\t制表符 ‘\u0009’
\n换行符 ‘\u000A’
\r回车符 ‘\u000D’
  • b、字符类
构造匹配
[abc]字符 a、b、c中的一个(简单类)
[^abc]除了字符 a、b、c外的任意一个字符(否定)
[a-zA-Z]a-z或者A-Z中的字符 含端点字符(范围)
[0-9]0-9范围内的数字字符(范围)
[a-d[m-p]]等价 [a-dm-p] 并集
[a-z&&[def]]交集
[a-z&&[^bc]]差集
[a-d[^m-p]]差集
  • c、预定义字符类
构造匹配
.任意字符("\\.“表示”."本身)
\d数字0-9:[0-9] “\d”
\D非数字0-9:[^\d] “\D”
\w单词字符:[a-zA-Z_0-9] “\w”
\W非单词字符:[^\w] “\W”
\s空白字符:[ \t\n\x0B\f\r] “\s”
\S非空白字符:[^\s] “\S”
  • d、边界字符
构造匹配
^行的开头
$行的结尾
\b单词边界
\B非单词边界
  • e、Greedy数量词
构造匹配
X?X,一次或一次也没有
X*X,零次或多次
X+X,一次或多次
X{n}X,恰好 n 次
X{n,}X,至少 n 次
X{n,m}X,至少 n 次,但是不超过 m 次
所有的量词都是贪婪的,会尽量多的匹配 eg:"g+" 匹配 "aggge" 中的 "ggg"防止贪婪行为的做法:使用 "g+?" 即可将量词匹配变得懒惰,匹配 "aggge" 时只是 "g"
  • f、Logical运算符
构造匹配
XYX 后跟 Y
X|YX 或 Y
(X)X,作为捕获组

在这里插入图片描述
捕获组 0 永远是表达式本身的匹配。


B:正则表达式的应用

  • a 、String类成员方法:判断功能(9) public boolean matches(String regex) 判断指定字符穿是否满足正则表达式regex

示例:用户名的验证。类似 :rp_xxx@rupeng.com(其中xxx是指1或多个字符)

String regex = "rp_[^_]\\w+@rupeng.com";

// sspu学校邮箱验证的正则表达式
String mailregex = "\\w+@sspu\\.((com)|(cn))";
  • b 、String类的成员方法:转换功能(18) (也可称为分割功能)pubic String[] split(String regex) 根据给定的正则表达式 regex 拆分字符串,得到字符串数组
  • 作用:使用给定的表达式和限制参数 0 来调用两个参数的 split 方法 public String[] split(String regex,int limit) limit 参数控制模式应用的次数,n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。

例如,字符串 “boo:and:foo” 使用这些参数可生成以下结果:

Regex结果
:{"boo","and","foo"}
o{"b","",":and:f"}

示例1:数据库查找年龄段“18-24”之间的人员

// 实际开发中年龄段因该是文本列表框的一个子项,
// 通过获取子项的值,再进行分割,就可以传入数据库查询
String ageStr = "18-24";
String[] age = ageStr.split("-");
int startAge = Integer.parseInt(age[0]);
int endAge = Integer.parseInt(age[1]);

// 数据库中查询年龄在 18-24岁 之间的人员信息
String sql = "SELECT * FROM employee WHERE age BETWEEN " + startAge + " AND " + endAge;

示例2:给定输入:“91 27 46 38 50”,按照升序排序输出

/** 第一种解决方案 */
package com.rupeng.wrapper;

import java.util.Arrays;

public class SortDemo1
{
	public static void main(String[] args)
	{
		String inStr = "91 27 46 38 50";
		String regex = " ";
		String[] outStrs = inStr.split(regex);
		Arrays.sort(outStrs);
		StringBuilder out = new StringBuilder();
		for (int i = 0; i < outStrs.length; i++)
		{
			out.append(outStrs[i]).append(" ");
		}
		System.out.println(out.toString());
	}
}

/** 第二种解决方案 */
package com.rupeng.wrapper;

import java.util.Arrays;

public class SortDemo2
{
	public static void main(String[] args)
	{
		String inStr = "91 27 46 38 50";
		String regex = " ";
		String[] outStrs = inStr.split(regex);
		int[] outInt = new int[outStrs.length];
		for (int i = 0; i < outInt.length; i++)
		{
			outInt[i] = Integer.parseInt(outStrs[i]);
		}
		Arrays.sort(outInt);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < outInt.length; i++)
		{
			sb.append(outInt[i]).append(" ");
		}
		System.out.println(sb.toString());
	}
}
  • c、 String类的成员方法:替换功能(3)public String replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 调用此方法的 str.replaceAll(regex, repl) 形式与以下表达式产生的结果完全相同:Pattern.compile(regex).matcher(str).replaceAll(repl)

示例:给定字符串 str = “helloqq10000java”,分别实现不同需求

/** 需求1:将所有数字都是用"*"代替 */
package com.rupeng.wrapper;

public class NumDemo1
{
	public static void main(String[] args)
	{
		String str = "helloqq10000java";
		/** regex = "[0-9]" */
		String regex = "\\d";
		str = str.replaceAll(regex, "*");
		System.out.println(str);
	}
}

/** 需求2:将所有数字用一个"*"代替 */

/** regex = "[0-9]+" */
String regex = "\\d+";
str = str.replaceAll(regex, "*");

/** 需求3:去除所有数字 */

/** regex = "[0-9]+" */
String regex = "\\d+";
str = str.replaceAll(regex, "");

P.S.
$ 符号在正则表达式中的使用
正则中可以使用 () 将一个表达式代表一个组,每一个组在表达式中都用对应的引用值,整个表达式默认是第 0 组,所以自己声明的组需要从 1 开始,譬如:第1组表示为 \\1。(如果不从 1 开始,可能没有任何的效果,也可能抛出异常)
$ 用来引用一个组 (),组号从1开始;格式:$组号

String str = "abbbbbbbbcgggggggkjjjjjjji";
// 需求:连续重复的字符只显示一次
String repStr = str.replaceAll("([a-z]\\1+)","$1");
  • d、获取功能

模式:Pattern类 *

public final class Pattern extends Object implements Serializable

0:java.util.regex包下的Pattern类,描述说:Pattern是正则表达式的编译表示形式。指定为字符串的正则表达式必须先编译为此类的实例。然后,将得到的模式实例用于创建Matcher对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有的状态都保留在匹配器中,所以多个匹配器可以使用同一个模式。

因此,典型的调用顺序是:

Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(srcStr);
boolean b = m.matches();

在仅使用一次正则表达式时,可以方便地通过Pattern类的matches方法的。此方法编译的表达式并在单个调用中将输入的序列与其匹配。

boolean b = Pattern.matches(regex,srcStr);

等价于上面的三个语句,但是对于重复的匹配而言,它的效率不高。因为每次进行匹配的时候,都需要从头开始,编译模式、构造匹配器、进行匹配,而使用上面三条语句,则每次只需要重置匹配器或构造新的匹配器,即可进行匹配,不用再次编译模式。故此,效率低最终原因就是:无法重用已编译的模式。

Pattern类的实例是不可变的,可供多线程安全的访问。Matcher类的实例应用于此则不安全。

Pattern类是正则表达式的编译表示形式。通过上面的实现,可以有一个简单猜测:所有关于正则表达式的匹配问题都包括以下几个步骤

  • (1)依据给定的正则表达式regex,编译创建Pattern模式对象;
  • (2)使用创建的模式对象,构造一个或多个Matcher匹配器对象;
  • (3)使用给定的字符序列进行匹配,匹配的所有状态存放在每一个匹配器对象中;
  • (4)根据需求,调用所需状态值。

总结以上所有关于正则表达式功能方法:
在这里插入图片描述
A:成员变量:【Field Summary】

B:构造方法:【Constructor Summary】 私有构造,模式实例通过静态方法compile编译创建

C:成员方法:【Method Summary】

  • a、 public static Pattern compile(String regex) 将正则表达式编译到模式中。默认的匹配标志符 0;当regex不符合正则表达式的规则时,抛出PatternSyntaxException异常 。底层调用的是:私有构造方法 new Pattern(regex, 0)

  • b、public static Pattern compile(String regex,int flags) 将正则表达式编译到给定匹配标识符flags的模式中。当regex不符合正则表达式的规则时,抛出PatternSyntaxException异常 。底层调用的是:私有构造方法 new Pattern(regex, flags)

  • c、public int flags() 返回此模式的匹配标志

  • d、public Matcher matcher(CharSequence input) 创建 给定输入与此模式的匹配器。若尚未编译,先进行同步编译,然后使用 Matcher m = new Matcher(this, input); 获取匹配器

  • e、public String pattern() 返回编译到此模式的正则表达式

  • f、public String[] split(CharSequence input) 根据围绕此模式的匹配来拆分给定字符序列后,得到字符串数组。是String类的成员方法 public String[] split(String regex) 底层的实现原理。其实际调用的是split(input,0)

  • g、public String[] split(CharSequence input,int limit) 是 split 方法最底层的实现,其他的split实现都是直接或者间接得调用此功能实现的。

匹配器:Matcher类 *

public final class Matcher extends Object implements MatchResult since JDK 1.4

0:Matcher类在java.util.regex包下,描述说:Matcher匹配器是通过解释Pattern模式对字符序列执行匹配操作的引擎。通过调用Pattern模式 matcher 方法创建匹配器实例。创建的匹配器实例可以通过以下三种方式进行匹配:

  • matches 方法尝试将整个输入字符序列与该模式匹配
  • lookingAt 方法尝试将整个输入字符序列从头开始与该模式匹配。当且仅当输入字符序列的前缀和匹配器匹配时,返回 true 。
  • find 方法扫描输入字符序列以查找与该模式匹配的下一个子序列。当且仅当输入字符序列的子序列与匹配器匹配时,返回 true 。

每个方法都返回一个表示成功或失败的bolean值。通过查询匹配器的状态可以获取关于成功匹配的更多信息。

可以通过调用匹配器的 reset() 方法来显示重置匹配器,若需要重新给定输入字符序列,则可以通过调用其 reset(CharSequence)方法。重置匹配器将放弃其显式状态信息并将添加位置设置为零。

此类实例应用多线程不安全

A:成员变量:【Field Summary】

B:构造方法:【Constructor Summary】 仅仅存在私有构造方法,由Pattern类的matcher方法调用创建Matcher实例

C:成员方法:【Method Summary】

  • a、public boolean matches() 匹配整个输入字符序列

  • b、public boolean lookingAt() 匹配输入字符序列的前缀

  • c、public boolean find() 匹配整个字符序列的子序列

  • d、public Matcher reset() 重置匹配器

  • e、public Matcher reset(CharSequence input) 重置匹配器,给定新的输入字符序列

  • f、public Pattern pattern() 返回由此匹配器解释的模式。 注意:Pattern类中的同名方法public String pattern()返回的是用于构建模式的正则表达式(字符串)

  • g、public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列。是 String类中 replace 系列方法的最底层原理。

继承自接口 MatchResult 的有关状态信息的三个主要方法:

  • h、public int start([int group]) 返回上次匹配的 group 的初始索引。当 int group 不提供时,实际是调用的 start(0)

    • int group :匹配模式中捕获组的索引
  • i、public int end([int group]) 返回 上次匹配的 group 的偏移量;如果匹配成功但组本身没有任何匹配项,则返回 -1。 int group 不提供时,实际是调用的 end(0)

  • j、public String group([int group]) 返回由上次匹配操作所匹配的输入字符序列的子序列。int group 不提供时,实际是调用的 group(0)

注意:以上,必须在匹配操作进行之后,才能获取。否则抛出异常

  • IllegalStateException : No Match Found 【表示没有进行任何的匹配操作,或者上次匹配操作失败】

  • IndexOutOfBoundsException : Illegal start index 【给定索引的模式中不存在捕获组】

实例:获取给定字符串中长度为8的专有单词(也就是说大写字符开头)

package com.rupeng.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexDemo
{
	public static void main(String[] args)
	{
		String info = "Hello, everyone ! I am Joian Sun."
				+ " I come from Fuyang City, Anhui Province. "
				+ "Currently studying at Shanghai Second Polytechnic University, "
				+ "Software Engineering. ";
		String regex = "\\b[A-Z]\\w{7}\\b";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(info);
		while (m.find())
		{
			System.out.println(m.group());
		}
	}
}

面试题

1、硬盘上的路径 “E:\com\rupeng\java” ,获取盘符和各级文件夹名称。

解答:

String link = "E:\\com\\rupeng\\java";
String regex = "\\\\";
String[] dirs = link.split(regex);

3、数学工具类:Math

0:类的引入及其描述

java.lang包下的Math类,包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

A:成员变量【Field Summary】

  • public static final double E 自然对数底数 e
  • public static final double PI 圆周率 π

B:构造方法【Constructor Summary】

仅仅存在私有的构造方法,因是工具类不需要实例化

C:成员方法【Method Summary】

主要针对四种基本类型(int、long、float、double )的部分实用功能

  • a、public static double ceil(double d) 向上取整;注意:Math.ceil(x) 的值与 -Math.floor(-x) 的值完全相同。 (亦即 互为相反数的正浮点数向上取整的值和负浮点数向下取整的值相同)

  • b、public static double floor(double d) 向下取整

  • c、public static long round(double d) 返回最接近 d 的 long 值;结果等于 (long)Math.floor(d + 0.5d)

  • d、public static int round(float f) 返回最接近 f 的 int 值;结果等于 (int)Math.floor(f + 0.5f)

  • e、public static double random() 返回在[0.0,1.0)之间的随机数。第一次使用时创建一个伪随机数类Random的对象 new java.util.Random()

示例:随机生成[1,100]之间的任意正整数

int num = (int)(Math.random() * 100) + 1;

面试题

1、请阐述 round 实现四舍五入的原理

解答:简言之,任意数加上0.5,然后向下取整

(int)Math.floor(num + 0.5f);  // float类型的四舍五入
(long)Math.floor(num + 0.5d);  // double类型的四舍五入

2、设计一个方法,可以实现获取任意范围内的随机数

public static int getRandom(int low,int high)
{
	return (int)(Math.random() * (high - low + 1)) + low;
}

4、伪随机数:Random类

0:类的引入及其描述

java.util包下的Random类,主要用于产生伪随机数流

A:成员变量【Field Summary】

没有

B:构造方法【Constructor Summary】

  • public Random() 没有给定种子,创建Random的实例,默认的种子值是当前时间的毫秒数。每次产生的随机数不定

  • public Random(long seed) 给定seed种子值,每次产生的随机数和第一次的相同

Random rnd = new Random(seed);
// 相当于:
Random rnd = new Random();
rnd.setSeed(seed);  // 设置种子值

C:成员方法:【Method Summary】

主要说明int相关得成员方法,其他的类似

  • public int nextInt() 返回 int 范围内的随机数
  • public int nextInt(int n) 返回 [0,n) 范围内的随机数
  • public void setSeed(long seed) 使用单个 long 种子设置此随机数生成器的种子

重写示例:获取[1,100]范围内的随机数

public static int getRandom(int low,int high)
{
	return new Random().nextInt(100)+1
}

但是如果是要获取指定范围内的随机数的话,就没有那么容易了,并且很多应用程序发现Math.random()方法更易使用。

PS:建议使用 Math.random()方法 实现随机数的获取 !


小总结:

在这里插入图片描述


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老坛算粉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值