9--多态&字符串缓冲区&正则表达式

1、多态

1.1、什么是多态

多态:一个事物以不同的形态展示出来,把这种展示称为这个事物的多态性。

         举例:

                   水果:它是水果的统称。而真正面对的肯定是水果下面的某个一类果品。                  

         水果:

                            苹果:

                            香蕉:

                            桃子:

                            .......

                   这个苹果很甜,这时就用苹果自己的形态在描述苹果。

                   这个水果很甜,但是面对的依然苹果,这时苹果就被水果这种形态进行描述。

                   动物:它是动物的统称。真正面对的肯定具体的某类动物。                  

                   动物:

                            一只狗:

                            一只猫:                           

        这只小狗很可爱,没有发生多态现象。这只动物很可爱,这时就发生多态现象。

        多态技术:仅仅是以其他的方式将某个事物进行描述,而事物自身没有发生任何的转变。

 1.2、多态概念

将一种事物(对象)使用它的父类、接口的类型进行展示描述,这种现象被称为多态(对象自身不会改变)。

要想使用多态现象:

      肯定是将某个子类的个体,使用了父类或接口类型进行展示。这样肯定是多态了。

      但是千万不能将子类的个体,使用了父类的其他子类类型展示,这种描述是错误的。

Java中的多态:

      将某个子类对象,描述成父类或接口的类型。但是具体的对象本身是没有发生任何的改变的。

1.3、多态的Java代码体现

格式:

父类或接口类型  引用变量名  =  new  子类或实现类对象();  // 多态

举例:

         Animal a = new Dog();  a就是Animal类型,但是它指向了Dog对象。

         Animal a2 = new Cat();  a2依然还是Animal类型,但是它指向了Cat对象。

 

另外一种多态现象:

         子类类型  变量名1 = new 子类类型(); // 这个是没有发生多态的

         父类类型 变量名2 = 变量名1;  //发生了多态

         Dog d = new Dog(); // 没有多态

         Animal a = d; // 多态了

多态前提:要能够使用多态,必须存在继承或者类和接口的实现关系。

1.4、多态的应用

/*
 * 所有动物类的顶层父类
 */
public abstract class Animal {
	public abstract void eat();
}
/*
 * 描述缉毒的行为,定义在接口
 */
public interface Drug {
	public void drug();
}
/*
 * 描述狗类
 */
public class Dog extends Animal implements Drug{
	public void eat(){
		System.out.println("啃骨头");
	}
	public void lookHome(){
		System.out.println("看门");
	}
	@Override
	public void drug() {
		System.out.println("狗在缉毒");
	}
}
/*
 * 描述猫
 */
public class Cat extends Animal{

	public void eat() {
		System.out.println("吃鱼");
	}
	public void catchMouse(){
		System.out.println("抓老鼠");
	}
}
/*
 * 演示多态
 */
public class DuoTaiTest {
	public static void main(String[] args) {
		
		// 创建狗对象
		Dog d = new Dog();
		d.drug();
		d.eat();
		d.lookHome();
		
		// 创建猫对象
		Cat c = new Cat();
		c.catchMouse();
		c.eat();
		/*
		 * 使用多态的方式操作具体的某个动物
		 */
		Animal a = new Dog(); // 多态就发生了
		/*
		 * 将Dog类型描述成Animal类型, 这时相当于将子类提升成了父类类型
		 * 那么在通过引用变量调用方法和成员变量等类中的内容的时候,
		 * 其实面对的应该父类类型的这个引用变量,这时只能使用父类或者更高的父类中的成员(方法和变量)
		 * 无法使用子类中自己的成员
		 */
		a.eat();
		/*
		 * 使用的接口的类型来表示当前实现类的一个对象
		 */
		Drug d2 = new Dog();
		/*
		 * 只能调用接口中的方法
		 */
		d2.drug();
		
	}
}

1.5、多态在集合中的使用体现

/*
 * 多态使用
 */
public class DuoTaiTest2 {
	public static void main(String[] args) {
		/*
		 * 有多个重复的对象,需要存放到集合中,单列集合,可以保存重复元素
		 * 肯定要使用的List接口下的集合
		 */
		// 多态
		List<String> list = new ArrayList<String>();
		list.add("aaa");
		list.add("aaa");
		list.add("aaa");
		
		// 多态
		Map<String , Integer> map = new HashMap<String , Integer>();
		
		// 遍历Map  , 也是多态
		Set<String> set = map.keySet();
	}
}

1.6、多态中的转型

多态:将一种事物使用另外一种类型展示(描述)。其实这是就将这个事物进行了类型的转换。

向上转型:使用父类的类型指向了自己的子类对象。

 Animal a = new Cat();  这是相当于将Cat对象向上转型为Animal类型。

向下转型(强制类型转换):使用具体的一个子类类型,指向了一个父类(接口)类型的引用变量。这是需要向下转型。

 Cat c = (Cat)a;

/*
 * 多态中的类型转成问题:
 * 	多态(向上转型): 父类或接口的类型   引用变量名  = 子类对象或实现类对象;
 * 	向下转型(强制类型转换):子类或实现类类型  引用变量名 = 父类或接口的引用变量;
 */
public class DuoTaiDemo {
	public static void main(String[] args) {
		
		// 演示多态的向上转型
		Animal a = new Dog(); // 多态
		/*
		 * 使用Animal类型的a引用变量,调用Animal类或者Animal的父类中的成员
		 */
		a.eat();
		/*
		 * 如果需要调用某个对象自己中的一些特有的方法(非体系的共性方法)
		 * 必须将Animal类型的a引用变量,转回到真正a引用所表示的实际对象的类型
		 */
		//Dog d = new Dog();  // 创建新的Dog对象,和上面的多态中Dog不是同一个对象
		Dog d = (Dog)(a);  // 向下转型
		d.lookHome();
		
		/*
		 * 假设现在只知道a的类型是Animal类型,但是指向的是Animal的某个子类对象
		 * 但是具体是哪个对象无法确定
		 */
		Cat c = (Cat) a; // 会发生异常ClassCastException(类型转换异常)
		c.catchMouse();
	}
}

1.7、类型转换中的坑

类型转成中的异常:ClassCastExceptin。

/*
 * ClassCastException异常的避免:
 * 	需要使用类型的判断。然后在确定是具体某个类型的时候再去转换
 */
public class DuoTaiDemo2 {
	public static void main(String[] args) {
		
		// 演示多态的向上转型
		Animal a = new Cat(); // 多态
		/*
		 * 需要向下转型,那么先判断当前父类或接口的引用指向的对象所属具体的类型
		 * 判断具体某个引用指向的对象是哪种类型,需要使用Java中的instanceof 关键字
		 * 格式:
		 * 	 if( 父类或接口的引用变量  instanceof 具体的对象的类型  ){
		 * 	 }
		 */
		if( a instanceof Dog ){
			// 判断成立,说明a指向的对象一定是Dog对象
			Dog d = (Dog) a;
			d.lookHome();
		}
		if( a instanceof Cat ){
			// 判断成立,说明a指向的对象一定是Cat对象
			Cat c = (Cat) a;
			c.catchMouse();
		}
	}
}

1.8、多态中的成员调用问题

/*
 * 多态技术中的成员(方法和变量)的调用问题:
 * 	主要体现的就是通过父类或接口的引用变量来调用成员方法或变量。
 * 
 * 父类或接口的类型   引用变量名 = 子类或实现类对象;
 * 引用变量名.方法名(参数);
 * 引用变量名.成员变量 = 值;
 */
class SuperFu{
	int z = 789;
}
class Fu extends SuperFu{
	int x = 123;
	public void show(){
		System.out.println("Fu show run");
	}
}
class Zi extends Fu{
	int y = 456;
	public void func(){
		System.out.println("Zi func run");
	}
	// Zi类将Fu类中的show方法复写了
	public void show(){
		System.out.println("Zi show run");
	}
}

public class DuoTaiDemo3 {
	public static void main(String[] args) {
		
		/* 没有多态,调用不存在上面说的多态的调用问题
		Zi z = new Zi();
		z.x = 111;
		z.y = 222;
		z.show();
		z.func();
		*/
		/*
		 * 发生了多态现象:需要注意成员变量和方法调用的问题
		 */
		Fu f = new Zi();
		/*
		 * 多态中非静态或静态变量调用:
		 * 	 代码的编译阶段,还是代码的运行阶段,只能访问父类或父类以上的父类中的成员变量。
		 */
		// 可以访问x变量,因为x是Fu类中的
		System.out.println( f.x );
		// 不能访问y变量,因为y是Zi类中的
		//System.out.println( f.y );
		/*
		 * 多态中非静态的方法调用:
		 * 	代码编译的时候,要求调用的方法在父类中必须存在,
		 * 	而运行的时候运行的是子类中复写的这个方法
		 * 
		 * 在实际的开发中,经常需要使用多态来进行程序的编写:
		 * 	我们在调用方法的时候,一般都会查阅父类或接口中的功能,而在创建对象的时候
		 * 	直接找子类或实现类去创建对象,然后采用多态的方式进行方法的调用。
		 * 	父类或接口中有的方法,子类一定会有。这是不关心具体是那个子类或实现类。
		 */
		f.show();
	}
}

多态调用成员(变量和方法)的规则:

  1. 调用成员变量(静态和非静态),不管是编译还是运行都参考的是父类中的成员变量。
  2. 调用非静态的方法,编译的时候,要求父类中必须有这个方法,而运行的时候,其实运行的子类中与父类同名的方法(被复写的方法)。
  3. 调用静态方法,编译和运行用的都是父类中的。

结论:只有非静态的方法在多态调用的时候,编译要求父类中必须有,运行的时候使用的子类中的方法。

2、字符串缓冲区

2.1、缓冲区思想

缓冲区其实就是一个临时的存储空间。可以将某些需要被使用的数据进行预先的存储和处理。最后直接从缓冲区中获取数据。

例如:在线看电影。网速过慢,就会出现loading。其实这时是由于你本地的播放速度超过了下载的缓存速度。本地已经没有缓存的电影数据。这时就会停止播放,等待下载。如果网速足够快,可能还没有看多少,就已经下载完成。但是下载的内存存放在内存的临时空间中(缓冲区)。

2.2、字符串缓冲区

由于String对象创建之后表示的字符串数据是无法被改变的。如果我们需要修改字符串中的字符数据,这时其实会生成一个新的字符串,原来被修改之前的字符串依然存在。

String s = “abc” ; 已经有一个字符串,如果我们需要对”abc”进行处理。将字符转成大写  “ABC” 。其实这时在内存中有两个字符串。“abc”和“ABC”。

只要字符串创建完成之后,在方法区的常量池就会存在这个字符串。如果想对字符串进行各种的修改。那么其实在方法区的常量池都会出现新的字符串。

原来的字符串依然会存在。也就是不会在原来的字符串中直接修改。

String s = “ab”;

String s2 = “cd”;

String s3 = s + s2;

/*
 * 演示String是常量
 */
public class StringDemo {
	public static void main(String[] args) {
		// 在内存中有一个字符串"abc",它就是一个String对象。它在内存有自己的内存地址
		String s = "abc";
		System.out.println(s);
		// 转成大写之后,其实是在内存中生成了一个新的字符串对象。其中保存的"ABC",也会有自己新的内存地址
		//String s2 = s.toUpperCase();
		s = s.toUpperCase();
		System.out.println(s);
		//System.out.println(s2);
		
		String s3 = "a";
		s3 += 1;  // "a1"
		s3 += 3;  // "a13"
		s3 += 5;  // "a135"
		System.out.println(s3);
		
	}
}

如果我们多次字符串进行修改操作,在没有修改完成的过程中,就会生成很多垃圾的字符串,而我们最终只要最后的那个确定的字符串数据。中间的过程中的那些字符串根本就没有实用的意义。像这种要对字符串进行各种的更改操作的方式,建议使用JDK中提供的字符串缓冲区。

字符串缓冲区有两个类:

         StringBuffer、StringBuilder。两个的使用方式完全相同。只是它们在多线程操作的时候性能有区别。

StringBuffer:它是线程安全的字符串缓冲区。通过空参数构造函数创建的StringBuffer的容器,初始容量为16个字符,但是其中没有存放任何字符数据。

2.3、字符串缓冲区中的方法

思想:只要是容器,一般都会提供C(create)R(read)U(update)D(delete)(增删改查)方法。所以我们就学习字符串缓冲区的CRUD方法即可。

2.3.1、增加(添加)方法

append 它可以将不同类型的数据添加到字符串缓冲区中。

insert  给字符串缓冲区指定位置上添加数据。

	// 添加方法
	public static void demo() {
		
		// 创建字符串缓冲区对象
		StringBuffer sb = new StringBuffer();
		
		/*
		 *  添加元素append ,将任何类型的数据添加到字符串缓冲区中
		 */
		sb.append("abc");
		sb.append("bbb");
		sb.append("ccc");
		/*
		 * 字符串缓冲区操作完成之后,需要将其中的内容最终转换一个确定的字符串对象
		 */
		String s = sb.toString();
		System.out.println( s );
		
		/*
		 * insert(int index , 值 )方法:在指定的下标位置上插入元素
		 * 	指定的下标的前面一定要保证有元素。
		 */
		sb.insert(9, "xyz");
		String s2 = sb.toString();
		System.out.println(s2);
	}

2.3.2、修改的方法

	// 修改
	public static void demo2() {
		// 创建字符串缓冲区对象
		StringBuffer sb = new StringBuffer();
		
		/*
		 *  添加元素append ,将任何类型的数据添加到字符串缓冲区中
		 */
		sb.append("abc");
		sb.append("bbb");
		sb.append("ccc");
		
		/*
		 * 修改中指定位置上的元素
		 * setCharAt 修改指定位置上的字符数据
		 */
		sb.setCharAt(3, 'B');
		sb.setCharAt(4, 'B');
		sb.setCharAt(5, 'B');
		System.out.println(sb.toString());
		
		/*
		 * length : 获取的字符串缓冲区中的字符个数
		 * capacity : 获取的字符串缓冲区的大小(容量)
		 * setLength : 它是在修改缓冲区中字符的个数。而不是在修改缓冲区的容量。
		
		sb.setLength(20);
		int len = sb.length();
		System.out.println(len);
		int cap = sb.capacity();
		System.out.println(cap);
		System.out.println(sb.toString());
		 */
		/*
		 * replace : 将从start开始到end结束(不包含)位置上的内容使用指定的字符内容替换
		 */
		sb.replace(0, 6, "ABCDEFGG");
		System.out.println(sb.toString());
		/*
		 * reverse : 将字符串缓冲区中的字符进行位置颠倒(首尾互换)
		 */
		sb.reverse();
		System.out.println(sb.toString());
	}

2.3.3、删除方法

	// 删除
	public static void demo3() {
		// 创建字符串缓冲区对象
		StringBuffer sb = new StringBuffer();
		
		/*
		 *  添加元素append ,将任何类型的数据添加到字符串缓冲区中
		 */
		sb.append("abc");
		sb.append("bbb");
		sb.append("ccc");
		/*
		 * delete : 从start位置删除到end位置
		 */
		sb.delete(0, 3);
		System.out.println(sb.toString());
		/*
		 * deleteCharAt 删除指定位置上的元素
		 */
		sb.deleteCharAt(0);
		System.out.println(sb.toString());
	}

2.3.4、获取

// 获取
	public static void demo4() {
		// 创建容器对象  初始容量16个字符
		StringBuffer sb = new StringBuffer("xuexijava");

		System.out.println(sb.capacity());
		System.out.println(sb.length());
		
	}

有部分方法和String中的方法使用相同>

2.4、StringBuilder

StringBuilder它的性能优越于StringBuffer。一般建议优先使用StringBuilder。

区别:

         相同点:都是字符串缓冲区。都可以对字符串进行CRUD操作。

         不同点:

                            1、StringBuffer:它是线程安全的。效率低。

                            2、StringBuilder:它是线程不安全。效率高。

2.5、String、StringBuffer、StringBuilder区别

String:表示的字符串,字符串本身是本能进行修改的。如果要对字符串本身进行各种转换操作,String类无法完成。

StringBuffer、StringBuilder表示的字符串缓冲区。可以将字符串临时缓存在其中。然后可以在缓冲区中对各个字符进行各种的操作。最后将缓冲区中的结果转成一个字符串数据。

3、正则表达式

字符串是最常用的一种数据。可以调用String类中的方法,以及字符串缓冲区中的方法对字符串进行操作。但是有时有些复杂的操作,可能调用方法可以完成,但是过程比较繁琐。于是针对字符串的一些常见的操作进行简化,采用正则表达式代替字符串某些方法完成对字符串的操作。

正则表达式:它几乎常见的编程语言中都有。并且语法通用。

3.1、介绍正则表达式

正则表达式:它是一种特殊的规则,主要用来对字符串进行操作的。

需求:判断QQ号码是否正确。

分析:1、判断位数。2、全部都是数字。3、第一位不能是零。

/*
 * 验证QQ号码是否正确:
 * 	规则:
 * 		1、全部是数字
 * 		2、位数:范围最少5位,最多12位
 * 		3、首位不能是零
 */
public class CheckQQ {
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入QQ:");
		String QQ = sc.nextLine();
		if( QQ.length() >= 5 && QQ.length() <= 12 ){
			System.out.println("目前为止,QQ的位数正确!!!");
			/*
			 *  判断首位
			 *  	QQ.startsWith("0")
			 *  	QQ.charAt(0) != '0'
			 */
			if( QQ.charAt(0) != '0' ){
				System.out.println("目前QQ的首位不是零");
				/*
				 * 判断纯数字:
				 *  1、遍历字符串,取出每个字符,判断是不是数字字符
				 *  2、使用包装类的parseLong方法,如果字符串中是纯数字,就可以转成一个long型值
				 *  	如果字符串中有非数字的内容,在转的时候肯定会报错。
				 */
				try{
					long l = Long.parseLong(QQ);
					System.out.println("QQ号码正确");
				}catch(NumberFormatException e){
					System.out.println("QQ号码不是纯数字");
				}
			}else{
				System.out.println("位数正确,但首位是零");
			}
		}else{
			System.out.println("QQ的位数错误");
		}
		
		
	}
}

使用正则表达式进行验证:

/*
 * 采用正则表达式来完成QQ的验证
 */
public class CheckQQ2 {
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入QQ:");
		String QQ = sc.nextLine();	
		
		/*
		 *  验证QQ号码是否正确:
		 *   采用正则表达式来验证QQ号码:
		 *   正则表达式:就是使用数字、字母、下划线、等一些符号组合在一起,书写的一个可以验证其他字符的规则。
		 *   学习正则表达式:主要学习如何书写规则,以及正则中都有哪些可以使用的符号
		 */
		boolean b = QQ.matches("[123456789][0-9]{4,11}");
		if( b == true ){
			System.out.println("QQ号码正确");
		}else{
			System.out.println("QQ号码错误");
		}
	}
}

3.2、介绍正则符号

学习正则:主要研究每个符号的具体含义。正则表达式它的体现和普通的字符串没有区别。

需要验证字符串中指定位置上的字符是否符合正则表达式中给出的规则,这时可以直接在正则表达式中书写这个特定规则号即可。

正则表达式和需要被验证的字符串之间有一个一一对应关系:

正则表达式中:

  验证某个位置上的内容

       单个字符:验证某个位置上的字符符号。

       [字符符号]: 表示某个位置上可以出现的字符符号,可以书写多个符号

       [^abc] 任何字符,除了 a、b 或 c(否定)

[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)

[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)

[a-z&&[def]] d、e 或 f(交集)

[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)

[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)

               下面的符号是在简化上面的[ 符号 ]书写格式:

                \d 数字:[0-9]

               \D 非数字: [^0-9]

               \s 空白字符:[ \t\n\x0B\f\r]

               \S 非空白字符:[^\s]

               \w 单词字符:[a-zA-Z_0-9]

               \W 非单词字符:[^\w]

边界问题:

         次数问题:

                   x?  表示x这个规则可以出现零次或者一次

                   x*  表示x这个规则可以出现零次或者多次

                   x+  表示x这个规则可以出现一次或者多次

                   x{n}  表示x这个规则只能出现n次

                   x{n,}  表示x这个规则最少出现n次,多到不限

                   x{n,m}表示x这个规则最少出现n次,最多m次

3.3、正则的功能

3.3.1、验证matches方法

/*
 * 使用正则表达式,验证手机号码
 */
public class RegexDemo {
	public static void main(String[] args) {
		
		String tel = "13890001234";
		
		// 验证,需要使用字符串中的matches方法
		boolean b = tel.matches("1[34578]\\d{9}");
		if( b ){
			System.out.println("手机号码正确");
		}else{
			System.out.println("手机号码错误");
		}
	}
}
/**
 * 演示正则表达式的验证功能
 */
public class RegexDemo {
	public static void main(String[] args) {
		// 身份证号码
		String idCard = "61011020171103123X";
		// 验证身份证号码是否正确
		// 书写正则表达式
		String regex = "[1-9][0-9]{5}[12]\\d{3}[01][0-9][0123]\\d\\d{3}[0-9Xx]";
		// 使用正则表达式对字符串的验证需要使用String类中matchers方法
		boolean b = idCard.matches(regex);
		System.out.println(b);
	}
}

3.3.2、切割split字符串

/**
 * 演示正则表达式的切割功能
 */
public class RegexDemo2 {
	public static void main(String[] args) {
		demo2();
	}
	/*
	 * 以叠词切割 
	 */
	public static void demo2() {
		
		String s = "sdfhaaaajkldsbbbbbbbbbbbjklfjfffsdkljreeeerelkfkkkkknvc";
		/*
		 * 由于上面的这个字符串中的叠词不同。在正则表达式中我们无法确定到底哪个符号是叠词
		 * 也就是说需要使用一个可以代替任何字符存在的一个符号作为切割的符号。
		 * 在正则表达式中   . 来代替可以出现的某个任意字符。
		 * 
		 * 在目前的这个切割中,如果直接书写这个点 . ,那么在切割的时候,就会使用 . 将当前所有的字符匹配上,作为切点
		 * 导致最后是无法切出我们想要的结果。
		 * 
		 * 任意符号只能使用点 . 来表示,当真正在进行切割的时候,点 . 就会对应当前匹配上的某个字符符号。
		 * 而这时希望下一个需要匹配的字符应该和当前.对应上的那个字符一模一样。
		 * 相当于现在需要沿用前一个匹配的结果。
		 * 如果需要沿用已经存在的正则规则,需要使用正则中的组概念。
		 * 正则组:将已经存在的规则使用小括号进行封装。
		 * 	格式:  (规则)
		 * 如果在正则中已经将某个规则封装成组了,那么在当前的组所在的正则位置的后面可以使用 \组号 的方式引用已经存在的组
		 * 
		 * 正则组号:一个正则中有多个组,那么从前往后数左小括号,遇到一个就是一个组。组号从1开始。
		 * 例如: ((A)(B(C)))  
		 * 第一组:((A)(B(C)))   1
		 * 第二组:(A)   2
		 * 第三组:(B(C))  3
		 * 第四组:(C)  4
		 */
		String[] strs = s.split("(.)\\1+");
		
		for (String ss : strs) {
			System.out.println(ss);
		}
		
		
	}
	// 基本的切割
	public static void demo1() {
		
		String s = "aa bb   cc   dd   ee ff";
		// 按照空格,将字符串切割成多个小的字符串
		String[] strs = s.split(" +");
		for (int i = 0; i < strs.length; i++) {
			System.out.println(strs[i]);
		}
	}
}

3.3.3、正则的替换功能

/*
 * 演示正则的替换功能
 */
public class RegexDemo3 {
	public static void main(String[] args) {
		demo3();
	}
	/*
	 *  将 "我我我我我......要要要要要...学学学学学Java...编.....程" 变成 "我要学Java编程"
	 */
	public static void demo3() {
		
		String s = "我我我我我......要要要要要...学学学学学Java...编.....程";
		
		// 将多个叠词转成一个叠词
		s = s.replaceAll("(.)\\1+", "$1");
		System.out.println(s);
		// 中间的小点 需要全部取消
		//s = s.replace('.', '\\');
		/*
		 *  我.要.学Java.编.程
		 *  正则中. 点表示的任意的可以匹配的字符,如果想让点表示点本身含义。那么就必须使用转义字符的方式对点进行转义
		 *  \\开始的内容都称为转义字符。
		 *  \\. 让这个点就表示自己本身的含义,而在正则中不再表示任意可以匹配的字符 
		 */
		s = s.replaceAll("\\.", "");
		System.out.println(s);	
		
	}
	// 将多个叠词,替换成一个叠词
	public static void demo2() {
		String s = "abc   efgAAAAhAB1111CD00000EG";
		
		String s2 = s.replaceAll("(.)\\1+", "$1");
		
		System.out.println(s2);
	}
	// 隐藏手机号码中间4位
	public static void demo() {
		/*
		 * 隐藏手机号码中间4位
		 */
		String tel = "13412345678";
		
		/*
		 *  使用替换功能
		 *  replaceAll(String regex, String replacement) 
		 *  String regex :正则表达式
		 *  String replacement : 替换的内容
		 *  
		 *  将正则中已经存在的规则进行分组,然后引用:
		 *  	如果在当前正则中引用:\\组号
		 *  	如果是在其他地方引用正则中的规则:$组号
		 */
		String t = tel.replaceAll("(1[34578]\\d)(\\d{4})(\\d{4})", "$1****$3");
		System.out.println(t);
	}
}

3.3.4、正则的获取功能

需求:一段文字中有手机号码,需要从中将手机号码获取出来。                  

正则对象:正则表达式本身是以字符串形式展示,但是有时我们也需要将正则表达式封装Java对象,然后按照对象的方式操作正则表达式。

Pattern表正则表达式,没有对外提供构造方法,也就是我们不能参加Pattern类的对象。

使用其中的静态方法,可以将一个字符串形式正则表达式,转成Pattern对象。

		// 书写正则表达式
		String regex = "1[345678]\\d{9}";
		
		// 将字符串格式的正则表达式转成正则对象
		Pattern pattern = Pattern.compile(regex);

有了正则对象之后,还有一个匹配器对象,两个对象结合在一起,就可以对字符串进行高级的操作。

/**
 * 演示正则表达式的获取功能
 * 
 * 需求:有一个文件,在文件的数据里面嵌入的有手机号码,
 * 现在需要从这个文件的数据中将所有手机号码获取出来。
 * @author WX
 */
public class RegexDemo4 {
	/**
	 * main方法,是程序的入口方法
	 * @param args
	 */
	public static void main(String[] args) throws IOException {
		demo2();
	}
	// 完成需求
	public static void demo2() throws IOException {
		
		BufferedReader bufr = new BufferedReader( new FileReader("e:/1.txt") );
		
		String line = null;
		while( ( line = bufr.readLine() ) != null ){
			// 现在已经从文件中读取到一行字符串,需要使用正则获取其中想要的手机号码
			getTel("1[345678]\\d{9}" , line);
		}
		// 关流
		bufr.close();
	}
	/*
	 * 专门根据指定的正则和字符串,从中获取数据
	 */
	public static void getTel( String regex , String line ){
		
		// 获取到正则对象
		Pattern pattern = Pattern.compile(regex);
		// 获取到匹配器对象
		Matcher matcher = pattern.matcher(line);
		// 需要使用循环找出符合条件的手机号码
		while( matcher.find() ){
			// 找出匹配上的字符内容
			String tel = matcher.group();
			// 将找出的内容进行其他的处理
			System.out.println(tel);
		}
	}
	/*
	 * Pattern对象
	 */
	public static void demo1() {
		
		String s = "shfj134145678skj13112384567d" ;
		// 书写正则表达式
		String regex = "1[345678]\\d{9}";
		
		// 将字符串格式的正则表达式转成正则对象
		Pattern pattern = Pattern.compile(regex);
		/*
		 *  通过正则得到匹配器,目的是将正则和字符串结合到一起
		 *  使用Pattern类中的matcher方法,将字符串和正则组合到一起,
		 *  就会得到Matcher对象。Matcher对象就是匹配器,
		 *  它可以负责通过正则去对需要匹配的字符串进行各种的操作。
		 */
		Matcher matcher = pattern.matcher(s);
		/*
		 * Matcher中的find方法:
		 * 	是通过正则对象到字符串中找可以符合正则规则的内容。找到就返回true.
		 */
		boolean b = matcher.find();
		System.out.println(b);
		/*
		 * Matcher中的group方法:
		 * 	将fin都找到的字符内容从原始的字符串中获取(截取)出来。
		 */
		String s2 = matcher.group();
		System.out.println(s2);
	}
}

猜你喜欢

转载自blog.csdn.net/baozi7263/article/details/105573482