正则、反射
1、反射-概述
反射就是在程序运行过程中,通过.class文件动态的获取类的信息(属性,构造,方法),并调用
注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面的属性和方法,还要求能够给类增加属性和方法,而JAVA中的反射只能获取调用,不能修改类的结构
在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用
2、创建Class文件的三种方式
Class.forName("类全名");
对象名.getClass();
类名.class
推荐使用:Class.forName("类全名");
3、获取构造方法并创建对象
概述:
java.lang.reflect.Constructor:构造方法管理器,通过该对象的newInstance方法能创建构造方法
一、步骤
1、获取Class对象
2、通过调用getDeclaredConstructor或者getConstructor 方法创建构造器(Constructor)对象,如果构造方法没有形式参数写null
public Constructor getDeclaredConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法可以获取私 有构造方法
public Constructor getConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法不能获取私有构造方 法
3、如果获取到的是私有的构造方法的构造器对象,需要调用构造器对象的setAccessible(true)方法
4、通过构造器对象的newInstance(实际参数1, 实际参数2)创建对象,如果没有实际参数写null
二、举例
1、通过private Person(String name, int age)创建对象
Class clazz = Class.forName("com.itcast.Person");//必须通过类全名获取
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);//形式参数列表对应的.class列表
con.setAccessible(true);//此处不设置,无法创建该对象,因为构造方法是私有的
Object obj = con.newInstance("zhangsan",120);//调用newInstance(实际参数列表)创建对象
2、通过public Person()创建对象
Class clazz = Class.forName("com.itcast.Person");//必须通过类全名获取
Constructor con = clazz.getDeclaredConstructor(null);//因为没有形式参数,所以写null
con.setAccessible(true);//此处不设置,无法创建该对象,因为构造方法是私有的
Object obj = con.newInstance();//因为不需要实际参数,所以调用无参的newInstance方法
4、获取属性并调用
概述:
java.lang.reflect.Field:属性管理器对象,可以对该类的对象的属性值进行修改和获取
一、步骤
1、获取Class对象
2、通过调用getDeclaredField("属性名")或通过调用getField("属性名") 获取属性管理器
3、如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
4、调用属性管理器的set(该类的对象,值) 来设置属性值
调用属性管理器的get(该类的对象)来获取属性值
二、举例
Person p1 = new Person();
Person p2= new Person();
Class clazz = Class.forName("Person");//第一步获取Class对象
Field field = clazz.getDeclaredField("name");//第二步通过调用getDeclaredField("属性名")或通过调用getField("属 性名") 获取属性管理器
field.setAccessible(true);//第三步如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
field.set(p1, "张三");//第四步用属性管理器的set(该类的对象,值) 来设置属性值
field.set(p2, "李四");
System.out.println(field.get(p1));//第四步调用属性管理器的get(该类的对象)来获取属性值
System.out.println(field.get(p2));
5、获取成员方法并调用
概述:
java.lang.reflect.Method:方法管理器,可以执行该类的对象的方法
一、步骤
1、获取Class对象
2、通过调用getDeclaredMethod("方法名",形式参数1.class, 形式参数2.class..)或通过调用geMethod("方法名",形式参数1.class, 形式参数2.class..) 获取属性管理器,如果没有形式参数写null
3、如果获取的是私有的方法,调用方法管理器的setAccessible(true)方法
4、通过属性管理器的invoke(该类的对象,实际参数)来执行方法,如果没有实际参数写null
二、案例
Person p1 = new Person("张三",13);
Person p2= new Person("李四",14);
Class clazz = Class.forName("Person");
/*
* 调用setName方法
*/
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.setAccessible(true);//如果getName方法是私有的,此处必须写
setName.invoke(p1, "张三改");
/*
* 调用getName方法
*/
Method getName = clazz.getDeclaredMethod("getName", null); //获取Person类的getName方法对应的方法管理器
getName.setAccessible(true);//如果getName方法是私有的,此处必须写
Object object = getName.invoke(p1, null);//执行p1对象的getName方法,并且将返回值赋值给object
System.out.println(object);
6、反射练习
1:通过反射修改成员变量的值,包括私有
2: 通过反射运行配置文件
在JAVA项目下新建配置文件config,内容为
class=Person
name=jack
JAVA代码:
Properties p = new Properties();
p.load(new FileReader("config"));
String className = (String)p.get("class");
String name = (String)p.get("name");
Class clazz = Class.forName(className);
//创建对象
Constructor constructor = clazz.getConstructor(null);
Object instance = constructor.newInstance();
//通过setName设置name属性
Method setName = clazz.getDeclaredMethod("setName", String.class);
setName.invoke(instance,name );
//通过getName设置name属性
Method method = clazz.getDeclaredMethod("getName",null);
Object object = method.invoke(instance, null);
System.out.println(object);
3: 通过反射给 ArrayList<Integer>中添加String 类型的数据
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
Class clazz = Class.forName("java.util.ArrayList");//必须通过类全名获取
Method method = clazz.getDeclaredMethod("add", Object.class);
method.setAccessible(true);
method.invoke(list, "ss");
for(Object obj: list){
System.out.println(obj);
}
7、正则表达式
(1)概念
就是符合一定规则的字符串
(2)常用功能:
1:判断功能
String -- matches
2:切割功能
String -- split
3:替换功能
String -- replaceAll
4:获取功能
Pattern
Matcher
compile()
find()
group()
(3)案例:
1:校验邮箱和电话号码
2:我要学编程
3:获取文本文件中的邮箱
7、正则规则
(1):特殊字符
\\:反斜线
\r:回车
\n:换行
(2):字符类
[abc]:a,b或者c的任意一个。
[^abc]:除了a,b,c以外的字符。
[a-zA-Z]:包括了26个英文字母。
[0-9]:包括了0-9这个10个数字字符。
(3):预定义字符类
. 任意字符
\d 数字[0-9]
\D 非数字[^0-9]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
(4):边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
(5):Greedy 数量词
x? 0次或1次
x* 0次或多次
x+ 1次或多次
x{n} 恰好n次
x{n,} 至少n次
x{m,n} 至少m次,但不能超过n次
8、常见的正则表达式
正则表达式用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。
匹配中文字符的正则表达式: [\u4e00-\u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了
匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
匹配空白行的正则表达式:\n\s*\r
评注:可以用来删除空白行
匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力
匹配首尾空白字符的正则表达式:^\s*|\s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
评注:表单验证时很实用
匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用
匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
评注:匹配形式如 0511-4405222 或 021-87888822
匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始
匹配中国邮政编码:[1-9]\d{5}(?!\d)
评注:中国邮政编码为6位数字
匹配身份证:\d{15}|\d{18}
评注:中国的身份证为15位或18位
匹配特定数字:
^[1-9]\d*$ //匹配正整数
^-[1-9]\d*$ //匹配负整数
^-?[1-9]\d*$ //匹配整数
^[1-9]\d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮点数(负浮点数 + 0)
匹配特定字符串:
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^\w+$ //匹配由数字、26个英文字母或者下划线组成的字符串