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

来源:互联网 发布:mt4自动化交易编程 编辑:程序博客网 时间:2024/05/21 19:39
-----------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类,用来加载USBpublic 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();//加载USBpad.useUSB(usb);}fi.close();}}
配置文件

USB.properties

usb0=cn.swu.Mouseusb1=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.24561.54.231.9192.54.231.24661.54.231.4845.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());}}}}
运行结果



 


1 0
原创粉丝点击