Java语言基础-反射机制、正则表达式
反射机制
反射机制是在运行状态中,对于任意一个类,都能知道这个类(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="abc1@sian.com.cn";
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;
}
}
浙公网安备 33010602011771号