黑马程序员-java基础(十)-反射、正则表达式

-----------android培训java培训、期待与您交流! ----------

反射、正则表达式

一、概述


反射:

        Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

        简单一句话:反射就是将java类中的各种成分映射成相应的类

1、反射的基石——Class

a、所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

b、Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。

field中有修饰符、类型、变量名等复杂的描述内容,因此也可以将字段封装称为一个对象。用来获取类中field的内容,这个对象的描述叫Field

c、Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;

同理方法和构造函数也被封装成对象MethodConstructor。要想对一个类进行内容的获取,必须要先获取该字节码文件的对象

P.S.

字节码

当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。

2Classclass的区别

a、classJava中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。

b、Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是ClassClassJava程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。


Person类
public class Person {
	public int num;
	private String name;
	private int age;
	static String cou="cn";
	public Person(){
		super();
		System.out.println("null.person run");     
	}
	public Person(String name,int age){
		this.name=name;
		this.age=age;
		System.out.println(name+":"+age+"person run");     
	}
	public void show(){
        System.out.println(name + "...show run..." + age);
	}

	private void privateMethod(){
        System.out.println("privatemethod run");
	}

	public void paramMethod(String str,int num){
        System.out.println("paramMethod run..." + str + ":" + num);
	}

	public static void staticMethod(){
        System.out.println("static method run...");
	}
	public int getAge(){
		return age;     
	}

}
反射的基本应用
package cn.swu;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectDemo {

	public static void main(String[] args) throws Exception,NoSuchMethodException{
		Person p=new Person("zhangsan",23);
		//获取字节码文件方法一:通过对象获取
		Class cla0=p.getClass();
		//获取字节码文件方法二:通过类来获取
		Class cla1=Person.class;
		//获取字节码文件方法三:通过给定类的字符串名称(最方便)
		Class cla2=Class.forName("cn.swu.Person");
		System.out.println(cla0==cla1);
		System.out.println(cla1==cla2);
		System.out.println("-----------------------------");		
		
		
		//用反射获取空参数的构造方法,并创建对象		
		Person p0=(Person)cla2.newInstance();
		System.out.println("-----------------------------");
		
		
		//用反射获取带参的构造方法(构造方法必须被public修饰)
		Constructor con=cla2.getConstructor(String.class,int.class);
		//用反射调用带参的构造方法,创建对象
		Object obj=con.newInstance("zhangsan",23);
		System.out.println("-----------------------------");
		
		
		//获取public修饰的字段
		System.out.println(cla2.getField("num").toString());
		System.out.println("-----------------------------");
		
		
		//获取所有类型包括私有的字段
		Field[] field=cla2.getDeclaredFields();
		for (Field f:field){
			System.out.println(f.toString());
		}
		System.out.println("-----------------------------");
		
		
		//私有的字段是无法赋值的,只有通过以下的暴力访问
		field[2].setAccessible(true);
		field[2].setInt(p0, 20);
		System.out.println(p0.getAge());
		System.out.println("-----------------------------");
		
		
		//获取所有本类的的方法
		Method[] methods=cla2.getDeclaredMethods();
		for(Method m:methods){
			System.out.println(m);
		}
		System.out.println("-----------------------------");
		
		
		//调用空参数的一般函数
		Method method0=cla2.getMethod("show",null);
		method0.invoke(obj,null);
		System.out.println("-----------------------------");
		
		
		//调用带参数的一般函数
		Method method1=cla2.getMethod("paramMethod", String.class,int.class);//获取函数
		System.out.println(method1);
		method1.invoke(obj, "wangwu",30);//调用函数
		
	}

}
运行结果:


   

二、反射的应用

        一个已经可以使用的应用程序,因为程序已经做好可以运行使用,不能再进行代码的加入了。而当后期我们新的功能加入程序时,该怎么做呢?就如我们的电脑一样,后期我们可能会鼠标、键盘等,所以电脑给我们预留了usb接口,只要符合这个接口规则的设备,电脑就可以通过加载驱动等操作来使用。

        那这个程序能用了,如何使用后期出现的功能类呢?

        常用的作法,会提供一个配置文件,来供以后实现此程序的类来扩展功能。对外提供配置文件,让后期出现的子类直接将类名字配置到配置文件中即可。该应用程序直接读取配置文件中的内容。并查找和给定名称相同的类文件。进行如下操作:

        1)加载这个类。

        2)创建该类的对象。

        3)调用该类中的内容。

       应用程序使用的类不确定时,可以通过提供配置文件,让使用者将具体的子类存储到配置文件中。然后该程序通过反射技术,对指定的类进行内容的获取。

       好处:反射技术大大提高了程序的扩展性。

USB.java

package cn.swu;
//定义接口规则
 public interface USB {
	public void run();
	public void stop();	
}
Mouse.java

package cn.swu;
//鼠标类,实现规则
public class Mouse implements USB {
	public void run(){
			System.out.println("mouse run...");
		}
	public void stop(){
		System.out.println("mouse stop......");
	}
}
Keyboard.java

package cn.swu;
//键盘类,实现USB规则
public class Keyboard implements USB {
	public void run(){
		System.out.println("Keyboard run...");
	}
	public void stop(){
		System.out.println("Keyboard stop......");
	}
}
Mypad.java

package cn.swu;
//Mypad类,用来加载USB
public class Mypad {
	public void run(){
		System.out.println("Mypad is RUNNING.....");
	}
	public static void useUSB(USB u)throws Exception{
		u.run();
		Thread.currentThread().sleep(2000);
		u.stop();
	}
}
RefleciTest.java

package cn.swu;
//从配置文件中读取后期扩展的USB,并加载运行
import java.io.*;
import java.util.Properties;

public class ReflectTest {

	public static void main(String[] args)throws Exception {
		Mypad pad=new Mypad();
		pad.run();
		//配置文件关联输入流
		FileInputStream fi=new FileInputStream("USB.properties");
		Properties pop=new Properties();
		//从输入流中读取属性列表
		pop.load(fi);
		//Class cla0=Class.forName("cn.Mouse");
		for(int i=0;i<pop.size();i++){
			//获取配置文件中对应的类名
			String USBname=pop.getProperty("usb"+i);
			//获取该类的字节码文件对象
			Class cla=Class.forName(USBname);
			//利用反射,创建对象
			USB usb=(USB)cla.newInstance();
			//加载USB
			pad.useUSB(usb);					
		}
		fi.close();
	}
}
配置文件

USB.properties

usb0=cn.swu.Mouse
usb1=cn.swu.Keyboard
运行结果:


正则表达式

正则表达式:符合一定规则的表达式,专用于操作字符串

特点:用一些特定的符号来表示一些代码操作,简化书写

1、匹配:String类中的matches(String regex),判断是否和指定的正则表达式匹配

package cn.swu1;
//用正则表达判断qq号是否合法,第一位不能为0,共5-15位
public class Test2 {

	public static void main(String[] args) {
		String QQ="02345565";
		String reg="[19][0-9]{1,14}";//[第一位1-9][0-9]出现{1-14次}
		System.out .println(QQ.matches(reg));
	}
}

2、切割:String 类中的 split(String regex, int limit) ,根据匹配给定的正则表达式来拆分此字符串
package cn.swu1;
//用正则表达判断切割字符串
public class Test2 {
	public static void main(String[] args) {		
		splitDemo("c:\\a\\b.txt","\\\\");
		//按照叠词切,需要重用规则的结果
		//将规则封装成一个组用()完成。且每个组都有一个编号,从1开始
		//想要使用已有的组可以通过\n(n为组编号)的形式来获取
		splitDemo("assgoegggsdfqqq","(.)\\1\\1");//需要转义\所以要两个\
	}
	public static void splitDemo(String str,String reg){
		String[] str1=str.split(reg);
		for(String s:str1){
			System.out.println(s);
		}
	}
}
运行结果:

3、替换:String 类中的replaceAll(String regex,String replacement)  使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
package cn.swu1;
//用正则表达判断替换字符串
public class Test2 {
	public static void main(String[] args) {		
		//将叠词用一个词替代
		//$编号:使用前一规则中对应编号的组
		replaceDemo("assgoegggsdfqqq","(.)\\1+","$1");//$1就分别代表s、g、q
	}
	public static void replaceDemo(String str,String reg,String newStr){
			String s=str.replaceAll(reg, newStr);
			System.out.println(s);		
	}
}


4、获取:将字符串中符合规则的子串取出
操作步骤:
1、将正则表达式封装成对象
2、让正则表达式和要操作的字符串相关联
3、关联后,获取正则匹配引擎
4、通过引擎对符合规则的字符串取出
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
 * 用正则表达式判断将符合规则的子串取出
1、将正则表达式封装成对象
2、让正则表达式和要操作的字符串相关联
3、关联后,获取正则匹配引擎
4、通过引擎对符合规则的字符串取出*/
public class Test2 {
	public static void main(String[] args) {		
		//将单词长度为3的单词找出
		findDemo("some one like you 666 !","\\b(.){3}\\b");//"\b"表示单边界的意思
	}
	public static void findDemo(String str,String reg){
		//Tep1:将指定的正则表达式封装成对象
		Pattern p=Pattern.compile(reg);
		//Tep2:让正则表达式对象和字符串相关联,并获取匹配引擎
		Matcher m=p.matcher(str);
		//Tep3:通过匹配引擎找到匹配的字符串
		while(m.find()){
			System.out.println(m.group());
			System.out.println(m.start()+"..."+m.end());//m.start和m.end为对应的角标
		}
	}
}
运行结果:

/*
 * 将字符串"我我我...我..我要要要...要..学学学...学..学编.......编..编编...编.编...程...程....程程程"
 * 更正为我要学编程输出
*/
public class Test2 {
	public static void main(String[] args) {
		String str="我我我...我..我要要要...要..学学学...学..学编.......编..编编...编.编...程...程....程程程";
		//将点去掉="."替换为""
		str=str.replaceAll("[.+]", "");
		//将叠字去掉
		str=str.replaceAll("(.)\\1+", "$1");
		System.out.println(str);
	}
}
import java.io.*;
import java.util.TreeSet;
/*
需求: 把以下IP存入一个txt文件,编写程序把这些IP按数值大小,从小到达排序并打印出来。
134.54.231.245
61.54.231.9
192.54.231.246
61.54.231.48
45.53.231.249
思路:
1、为了让ip可以按照字符串顺序比较,只要让ip的每一段的位数相同,将不足位补零
*/
public class Test2 {
	public static void main(String[] args)throws Exception {
		BufferedReader br=new BufferedReader(new FileReader("IP.txt"));
		TreeSet ts=new TreeSet();
		String line=null;
		while((line=br.readLine())!=null){
			line=line.replaceAll("\\b(\\d)", "00$1");//每一段中都补两个零
			line=line.replaceAll("0*(\\d{3})", "$1");//每一段都只保留后三位
			ts.add(line);//将字符串存入treeSet集合,使用TreeSet集合自然排序的功能
		}
		for(Object o:ts){
			String str=o.toString().replaceAll("[0]+(\\d)", "$1");//将排好序的字符串多余的零去掉
			System.out.println(str);
		}
	}
}
运行结果:

【邮箱爬虫】
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
需求: 将一个文本中的邮箱全部打印到控制台上。
思路:
1、读取文本文件,用正则表达式判断是否为文件格式
*/
public class Test2 {
	public static void main(String[] args)throws Exception {
		BufferedReader br=new BufferedReader(new FileReader("mail.txt"));//读取存有邮箱的文本文件
		String line=null;
		String reg="\\w+@\\w+(\\.\\w+)+";//定义邮箱格式的正则表达式
		Pattern p=Pattern.compile(reg);//将正则表达式封装成对象
		while((line=br.readLine())!=null){
			Matcher m=p.matcher(line);//获取正则表达式和字符串相关联的引擎
			while(m.find()){
				System.out.println(m.group());
			}
		}
	}
}
运行结果



 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值