反射机制
反射机制是在运行状态中,对于任意一个类,都能知道这个类(class文件)的所有属性和方法。
对于任意一个对象,都能调用它的任意一个方法和属性。
这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。
简单来说,动态获取类中的信息,就是Java的反射机制。
可以理解为对类的解剖。
Tomcat
提供了处理请求和应答的方式。
因为具体的处理动作不同,所以对外提供了接口,由开发者来实现具体的请求和应答处理。
Class类可以获取字节码文件中的所有内容,反射就是依靠该类来完成的。
想要对一个类文件进行解剖,只要获取到该类的字节码文件即可。
获取类的字节码文件:
package cn.itcast.reflect.demo; import cn.itcast.bean.Person; /* * 要想对字节码文件进行解剖,必须要有字节码文件对象 */ public class ReflectDemo { /** * @param args * @throws ClassNotFoundException */ public static void main(String[] args) throws ClassNotFoundException { // getClassObject_1(); // getClassObject_2(); getClassObject_3(); } /* * 方式三:(重点) * 只要通过给定的类的字符串名称,就可以获取该类,更为扩展。 * 可以用Class类中的方法完成。 * 该方法就是forName。 * 各种方式只要有名称即可,更为方便,扩展性更强。 */ public static void getClassObject_3() throws ClassNotFoundException { String className="cn.itcast.bean.Person"; Class clazz=Class.forName(className); System.out.println(clazz); } /* * 方式二: * 任何数据类型都具有一个静态的属性.class来获取其对应的Class对象。 * 不需要构造函数。 * 相对简单,但是还是需要明确用到类中的静态成员。 * 不够扩展 */ public static void getClassObject_2() { Class clazz=Person.class; Class clazz1=Person.class; System.out.println(clazz==clazz1); } /* * 获取字节码对象的方式: * 方式一: * Object类中的getClass方法 * 想要用这种方式,必须要明确具体的类,并创建对象。 */ public static void getClassObject_1(){ Person p=new Person(); Class clazz=p.getClass(); Person p1=new Person(); Class clazz1=p1.getClass(); System.out.println(clazz==clazz1); } }
获取Class中的构造函数:
package cn.itcast.reflect.demo; import java.lang.reflect.Constructor; public class ReflectDemo2 { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { // createNewObject(); createNewObject_2(); } public static void createNewObject_2() throws Exception { // cn.itcast.bean.Person p = new cn.itcast.bean.Person("小强",39); /* * 当要获取指定名称对应类中的所体现的对象时, * 而该对象初始化不使用空参数构造函数 * 既然是通过指定的构造函数进行兑现的初始化, * 应先获取到该构造函数。 * 通过字节码文件即可完成 * 该方法是:getConstructor(parameterTypes) */ String name = "cn.itcast.bean.Person"; Class clazz = Class.forName(name); //获取到了指定的构造函数对象 Constructor constructor=clazz.getConstructor(String.class,int.class); //通过该构造器对象的newInstance方法进行对象的初始化 Object obj=constructor.newInstance("小明",38); } public static void createNewObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException { // 早期:new的时候,先根据被new的类的名称查询该类的字节码文件,并加载进内存,并创建该字节码文件对象,然后创建该字节码文件对应的Person对象 cn.itcast.bean.Person p = new cn.itcast.bean.Person(); // 现在: String name = "cn.itcast.bean.Person"; // 找寻该名称的类文件,并加载进内存,并产生Class对象 Class clazz = Class.forName(name); // 如何产生该类的对象 Object obj = clazz.newInstance();// 创建新实例 } }
获取Class中的字段示例:
public class AccessibleObjectextends Object implements AnnotatedElement
AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。
package cn.itcast.reflect.demo; import java.lang.reflect.Field; public class ReflectDemo3 { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { getFieldDemo(); } /* * 获取字节码文件中的字段 */ public static void getFieldDemo() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); // Field field=clazz.getField("age");//该方法只能获取到public的字段 Field field=clazz.getDeclaredField("age");//只能获取本类中的所有字段(包含私有) //取消字段的访问权限检查,暴力访问 field.setAccessible(true); Object obj=clazz.newInstance(); field.set(obj, 90); Object o=field.get(obj); System.out.println(o); } }
获取Class中的方法:
package cn.itcast.reflect.demo; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import cn.itcast.bean.Person; public class ReflectDemo4 { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { // getMethodDemo(); // getMethodDemo_2(); getMethodDemo_3(); } public static void getMethodDemo_3() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("paramMethod", String.class, int.class); Object obj = clazz.newInstance(); method.invoke(obj, "小强", 39); } public static void getMethodDemo_2() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("show", null);// 获取空参数一般方法 // Person p=new Person(); // p.show(); // Object obj=clazz.newInstance(); Constructor constructor = clazz.getConstructor(String.class, int.class); Object obj = constructor.newInstance("小明", 37); method.invoke(obj, null); } /* * 获取指定Class中的公共函数 */ public static void getMethodDemo() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method[] methods = clazz.getMethods();// 获取的都是公有的方法 methods = clazz.getDeclaredMethods();// 只获取本类中所有方法(包括私有) for (Method method : methods) { System.out.println(method); } } }
package cn.itcast.bean; public class Person { private int age; private String name; public Person(String name, int age ) { super(); this.age = age; this.name = name; System.out.println("person param run..."+this.name+":"+this.age); } public Person() { super(); System.out.println("person run"); } public void show(){ System.out.println(name+"...show run..."+age); } private void privateMethod(){ System.out.println("private method run"); } public void paramMethod(String str,int num){ System.out.println("paramMethod run......"+str+":"+num); } public static void staticMethod(){ System.out.println("staticMethod run"); } }
反射练习:
package cn.itcast.reflect.test; import java.io.File; import java.io.FileInputStream; import java.util.Properties; /* * 电脑运行 */ public class ReflectTest { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { MainBoard mb=new MainBoard(); mb.run(); //每次添加设备都需要修改代码,传递新创建的对象 // mb.usePCI(new SoundCard());//新增SoundCard,需要修改程序 //不修改代码,就能够完成以上动作 //不使用new,而是直接获取class文件,在内部实现创建对象的动作 File configFile=new File("pci.properties"); Properties prop=new Properties(); FileInputStream fis=new FileInputStream(configFile); prop.load(fis); for(int x=0;x<prop.size();x++){ String pciName=prop.getProperty("pci"+(x+1)); Class clazz=Class.forName(pciName);//用Class去加载这个pci子类 PCI p=(PCI) clazz.newInstance();//创建的对象肯定是PCI的子类,可以直接将创建的对象类型强转为PCI mb.usePCI(p); } fis.close(); } }
package cn.itcast.reflect.test; public class MainBoard { public void run() { System.out.println("main board run"); } public void usePCI(PCI p) {//多态,提高扩展性 if (p != null) { p.open(); p.close(); } } } package cn.itcast.reflect.test; public interface PCI { public void open(); public void close(); } package cn.itcast.reflect.test; public class SoundCard implements PCI{ public void open(){ System.out.println("sound open"); } public void close(){ System.out.println("sound close"); } } package cn.itcast.reflect.test; public class NetCard implements PCI{ @Override public void open() { System.out.println("net open"); } @Override public void close() { System.out.println("net close"); } }
pci.properties pci1=cn.itcast.reflect.test.SoundCard pci2=cn.itcast.reflect.test.NetCard
正则表达式
正则表达式用于操作字符串数据;
通过特定的符号来体现;
正则表达式虽然简化了书写,但是阅读性变差了。
package cn.itcast.regex.demo; public class RegexDemo { /** * @param args */ public static void main(String[] args) { String qq = "123456789"; // checkQQ(qq); String regex = "[1-9][0-9]{4,14}";// 正则表达式 // String regex="[1-9]\\d{4,14}";//正则表达式 // boolean b=qq.matches(regex); // System.out.println(qq+":"+b); String str = "aoob"; String reg = "ao+b";// o有一次或多次 boolean b = str.matches(reg); System.out.println(b); } /* * 需求:定义一个功能对QQ号进行校验 * 要求:长度5-15位;只能是数字;0不能开头 */ public static void checkQQ(String qq) { int len = qq.length(); if (len >= 5 && len <= 15) { if (!qq.startsWith("0")) { try { long l = Long.parseLong(qq); System.out.println(qq + "正确"); } catch (NumberFormatException e) { System.out.println(qq + "含有非法字符"); } } else { System.out.println(qq + "不能0开头"); } } else { System.out.println("长度错误"); } } }
正则表达式对字符串的常见操作
组和捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C)))
2 \A
3 (B(C))
4 (C)
组零始终代表整个表达式。
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器获取。
与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。
以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。
public final class Patternextends Object implements Serializable
正则表达式的编译表示形式。
指定为字符串的正则表达式必须首先被编译为此类的实例(将正则表达式封装为对象)。然后,可将得到的模式用于创建 Matcher (匹配)对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
因此,典型的调用顺序是
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
package cn.itcast.regex.demo; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexDemo2 { /** * @param args */ public static void main(String[] args) { /* * 正则表达式对字符串的常见操作 * 1.匹配 * 使用的是String类中matchs方法; * * 2.切割 * 使用的是String类中的split方法; * * 3.替换 * 使用的是String类中的replaceAll方法; * * 4.获取 * 将正则规则进行对象的封装; * Pattern p = Pattern.compile("a*b"); * 通过正则对象的matcher方法字符串相关联,获取要对字符串操作的匹配器对象Matcher * Matcher m = p.matcher("aaaaab"); * 通过Matcher匹配器对象的方法对字符串进行操作 * boolean b = m.matches(); */ // functionDemo1(); // functionDemo2(); // functionDemo3(); functionDemo4(); } /* * 获取示例 */ public static void functionDemo4() { String str = "da jia hao,ming tian bu fang jia!"; String regex = "\\b[a-z]{3}\\b";// \\b-单词边界,否则会出现jia hao min的情况 // 1.将正则封装成对象 Pattern p = Pattern.compile(regex); // 2.通过正则对象获取匹配器对象 Matcher m = p.matcher(str); // 使用Matcher对象的方法对字符串进行操作 // 既然要获取三个字母组成的单词 // 进行查找 find()方法 System.out.println(str); while (m.find()) { System.out.println(m.group());// 获取匹配器的子序列 System.out.println(m.start()+":"+m.end());//输出开始和结束的位置 } } /* * 替换示例 */ public static void functionDemo3() { String str = "zhangsantttxiaoqiangmmmmmzhaoliu"; // str=str.replaceAll("(.)\\1+", "#");//将叠词替换为# str = str.replaceAll("(.)\\1+", "$1");// 将叠词替换为一个字母;$1,获取第一个参数中的第一组 System.out.println(str); String tel = "15812345678";// 158****5678 tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); System.out.println(tel); } /* * 切割示例 */ public static void functionDemo2() { // String str="zhangsan xiaoqiang zhaoliu"; // String[] names=str.split(" +");//空格出现一次或多次 // String str="zhangsan.xiaoqiang.zhaoliu"; // String[] names=str.split("\\."); String str = "zhangsantttxiaoqiangmmmmmzhaoliu";// 按ttt,mmmmm切割 // (X) X,作为捕获组 ;\n 任何匹配的 nth 捕获组 // 组((A) (B(C)) 最外层括号为第一组,次外层为第二组,以此类推;无括号,则为第0组 String[] names = str.split("(.)\\1+");// 第一位是任意字符,对任意字符进行复用 for (String name : names) { System.out.println(name); } } /* * 匹配示例 */ public static void functionDemo1() { // 匹配手机号码是否正确 String tel = "15800001111"; // String regex="1[358][0-9]{9}"; String regex = "1[358]\\d{9}"; boolean b = tel.matches(regex); System.out.println(tel + ":" + b); } }
正则表达式-练习:
package cn.itcast.regex.test; import java.util.TreeSet; public class RegexTest { /** * @param args */ public static void main(String[] args) { /* * 1.治疗口吃:我...我我要要...要要..要学...学...编编编程...程程...程程 * 2.对ip地址排序 * 3.对邮件地址校验 */ // test_1(); // test_2(); test_3(); } /* * 邮箱地址校验 */ public static void test_3() { String mail="[email protected]"; String regex="[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]{2,3})+";//(\\.[a-zA-Z]{2,3})+,类似于.com,.cn的组,存在一次或者多次 regex="\\w+@a\\w+(\\.\\w+)+";//笼统式匹配 boolean b=mail.matches(regex); System.out.println(mail+":"+b); } /* * ip地址排序 * 192.168.10.34 127.0.0.1 3.3.3.3 105.70.11.55 */ public static void test_2() { String ip_str="192.168.10.34 127.0.0.1 3.3.3.3 105.70.11.55"; //1.为了让ip可以按字符串顺序比较,只要让ip的每一段位数相同,补零 //按照每一位所需最多的0的个数进行补充;每一段都加2个0; ip_str=ip_str.replaceAll("(\\d+)", "00$1"); // System.out.println(ip_str);//00192.00168.0010.0034 00127.000.000.001 003.003.003.003 00105.0070.0011.0055 //2.每一段保留三位数字 ip_str=ip_str.replaceAll("0*(\\d{3})", "$1"); // System.out.println(ip_str);//192.168.010.034 127.000.000.001 003.003.003.003 105.070.011.055 //切割ip地址 String[] ips=ip_str.split(" +"); TreeSet<String> ts=new TreeSet<String>(); for(String ip:ips){ ts.add(ip); } for(String ip:ts){ System.out.println(ip.replaceAll("0*(\\d+)", "$1")); } } /* * 治口吃 */ public static void test_1(){ String str="我...我我要要...要要..要学...学...编编编程...程程...程程"; //1.将字符串中的 “.” 去掉,使用替换 str=str.replaceAll("\\.+", ""); //2.替换叠词 str=str.replaceAll("(.)\\1+", "$1"); System.out.println(str); } }
正则表达式-练习-爬虫
package cn.itcast.regex.test; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /* * 网页爬虫:其实是一个用于在互联网中获取符合指定规则数据的程序 * * 爬取邮箱地址 */ public class RegexTest2 { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // List<String> list=getMail(); List<String> list = getMailByWeb(); for (String mail : list) { System.out.println(mail); } } public static List<String> getMailByWeb() throws IOException { // 1.读取源文件 URL url=new URL("http://iask.sina.com.cn/b/1005465.html"); BufferedReader bufIn=new BufferedReader(new InputStreamReader(url.openStream())); // 2.对读取的数据进行规则的匹配,从中获取符合规则的数据 String mail_regex = "\\w+@\\w+(\\.\\w+)+"; List<String> list = new ArrayList<String>(); Pattern p = Pattern.compile(mail_regex); String line = null; while ((line = bufIn.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { // 3.将符合规则的数据存储到集合中 list.add(m.group()); } } bufIn.close(); return list; } public static List<String> getMail() throws IOException { // 1.读取源文件 BufferedReader bufr = new BufferedReader( new FileReader("c:\\mail.html")); // 2.对读取的数据进行规则的匹配,从中获取符合规则的数据 String mail_regex = "\\w+@\\w+(\\.\\w+)+"; List<String> list = new ArrayList<String>(); Pattern p = Pattern.compile(mail_regex); String line = null; while ((line = bufr.readLine()) != null) { Matcher m = p.matcher(line); while (m.find()) { // 3.将符合规则的数据存储到集合中 list.add(m.group()); } } bufr.close(); return list; } }