您的位置:首页 > 编程语言 > Java开发

JAVA基础--正则与反射

2016-08-22 14:45 246 查看
正则表达式

1:正则表达式:符合某种规则的字符串(请注意正则表达式就是个字符串,只不过符合某种规则)

由一个案例引出了正则表达式

写一个程序要求:输入一个qq号,请判断输入的这个qq号是否正确?

1)如果没有正则表达式的时候,写这个程序非常的麻烦

[java] view
plain copy

<span style="white-space:pre"> </span>private static boolean checkQq(String qq) {

boolean flag = true;

// 长度

if (qq.length() >= 5 && qq.length() <= 15) {

//是否不是0开头

if(!qq.startsWith("0")){

//判断全部是数字

char[] chs = qq.toCharArray();

for(char ch : chs){

if(!(ch>='0' && ch<='9')){

flag = false;

break;

}

}

}else{

flag = false;

}

} else {

flag = false;

}

return flag;

}

2)有了正则表达式非常的简单

[java] view
plain copy

private static boolean checkQq2(String qq) {

//return qq.matches("[1-9][0-9]{4,14}");

return qq.matches("[1-9]\\d{4,14}");

}

2:正则表达式的规则:

A:字符

x 字符 x,任意字符代表自己本身。

\\ 反斜线字符

\r
回车

\n
换行

B:字符类

[abc] a、b 或 c,任意字符一次。

[^abc] 任何字符,除了 a、b 或 c

[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内

[0-9] 任意的数字字符一次

C:预定义字符类

. 任意的字符

\d 数字:[0-9]

\w 单词字符:[a-zA-Z_0-9]

单词字符:英文,数字,及_

D:边界匹配器

^ 行的开头

$ 行的结尾

\b 单词边界(也就是说这里出现的不能是单词字符)

abc hello world?haha

E:Greedy 数量词

X? X,一次或一次也没有

X* X,零次或多次

X+ X,一次或多次

X{n} X,恰好 n 次

X{n,} X,至少 n 次

X{n,m} X,至少 n 次,但是不超过 m 次

F:组

捕获组可以通过从左到右计算其开括号来编号。组零始终代表整个表达式。

((A)(B(C)))

第一组:(A)(B(C))

第二组:A

第三组:B(C)

第四组:C

3:正则表达式的应用

1)String类利用正则表达式完成字符串的判断功能(校验功能)(public boolean matches(String
regex))

案例1:判断字符串”qaq”中间的字符是否是元音(aeiou)

String regex = "q[aeiou]q";

String str = "qbq";

boolean flag = str.matches(regex);

System.out.println(flag);

案例2:校验电话号码

String regex = "1[35]\\d{9}";

Scanner sc =new Scanner(System.in);

System.out.println("请输入你的手机号:");

String phone = sc.nextLine();

boolean flag = phone.matches(regex);

System.out.println(flag);

案例3:校验邮箱

//String regex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,8}(\\.[a-zA-Z_0-9]{2,3})+";

String regex = "\\w+@\\w{2,8}(\\.\\w{2,3})+";

Scanner sc = new Scanner(System.in);

System.out.println("请输入你的邮箱:");

String email = sc.nextLine();

boolean flag = email.matches(regex);

System.out.println(flag);

2)String类利用正则表达式完成字符串的切割功能(public String[] split(String regex))

案例1:按 "." 来切割字符串"aa.bb.cc"

[java] view
plain copy

<span style="white-space:pre"> </span>String str2 = "aa.bb.cc";

String regex2 = "\\.";

String[] strArray2 = str2.split(regex2);

for (String s : strArray2) {

System.out.println(s);

}

案例2:按 所有的空格 切割字符串"-1 99 4 23"

[java] view
plain copy

<span style="white-space:pre"> </span>String str4 = "-1 99 4 23";

String regex4 = " +";

String[] strArray4 = str4.split(regex4);

for (String s : strArray4) {

System.out.println(s);

}

案例3:切割计算机上的路径,把每一层路径切割出来,

比如:D:\itcast\20131130\day27\code 切成 D:itcast 20131130 day27
code

[java] view
plain copy

<span style="white-space:pre"> </span>//注意java表示此路径要用这样的一个字符串:"D:\\itcast\\20131130\\day27\\code"

String str5 = "D:\\itcast\\20131130\\day27\\code";

String regex5 = "\\\\";

String[] strArray5 = str5.split(regex5);

for (String s : strArray5) {

System.out.println(s);

}

案例4:按照叠词(重复字符)切割: "sdqqfgkkkhjppppkl";(这个地方引入了组的概念)

[java] view
plain copy

<span style="white-space:pre"> </span>String str = "sdqqfgkkkhjppppkl";

String regex = "(.)\\1+";

//".+" sdfgq

//"(.)\\1+" ssss

//右边出现的应该是和左边是一模一样的。

String[] strArray = str.split(regex);

for (String s : strArray) {

// sd,fg,hj,kl

System.out.println(s);

}

3)String类利用正则表达式完成字符串的替换功能

public String replaceAll(String regex,String replacement):用给定的字符串去替换字符串对象中满足正则表达式的字符。

案例1:把"sdaaafghccccjkqqqqql"替换成"sdafghcjkql",也就是叠词只留一个字符

[java] view
plain copy

<span style="white-space:pre"> </span>String str2 = "sdaaafghccccjkqqqqql";

// 叠词是在同一个字符串中用\编号来引用

String regex2 = "(.)\\1+";

// 在替换方法中,第二个字符串数据中可以使用$编号的形式来引用第一个正则表达式中的组的内容

String result2 = str2.replaceAll(regex2, "$1");

System.out.println(result2);

System.out.println("--------------------");

案例2:把某个嘴很磕巴的人写出的一个字符串

“我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程” 还原成 “我要学编程”

[java] view
plain copy

<span style="white-space:pre"> </span>String str = "我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程";

String result = str.replaceAll("\\.", "");

String finalResult = result.replaceAll("(.)\\1+", "$1");

System.out.println(finalResult);

4)用正则表达式的包装类Pattern 和 匹配器Mathcher 结合 来完成 查找获取功能

①:记住获取模式对象和匹配器对象的这两步

// 把正则表达式编译成模式对象

Pattern p = Pattern.compile("a*b");

// 通过模式对象调用匹配方法获取到匹配器对象

Matcher m = p.matcher("aaaaab");

// 调动匹配器对象的判断功能

②:Mathcher的matches方法 和String类的matches方法差不多,只不过调用方式不一样

二者区别:

A:Mathcher的matches方法没有参数,因为在生成匹配器对象的这个过程中,

就已经把正则表达式,和需要查找的字符串传给了匹配器对象

B:String类的matches方法

String对象直接调用public boolean matches(String regex)方法,把正则表达式传进来

// 把正则表达式编译成模式对象

Pattern p = Pattern.compile("a*b");

// 通过模式对象调用匹配方法获取到匹配器对象

Matcher m = p.matcher("aaaaab");

// 调动匹配器对象的判断功能

boolean b = m.matches();

System.out.println(b);

③:Mathcher的find()方法和group()方法

find():找到字符串中匹配正则表达式的字符 返回值类型是boolean 找到了就true 找不到就false

group():获取find()找到字符

案例1:想要获取字符串中 3个字符组成的单词

[java] view
plain copy

// 定义规则

String regex = "\\b[a-z]{3}\\b";

String str = "da jia zhu yi le, ming tian bu fang jia, xie xie!";

// 想要获取3个字符组成的单词

Pattern p = Pattern.compile(regex);

Matcher m = p.matcher(str);

while(m.find()){

System.out.println(m.group());

}

案例2:请把mail.txt中所有邮箱找到,并遍历出来。

A:通过字符输入流读取数据。

B:把读取到的每一行数据进行查找。

C:把查找到的数据存储到集合中。

D:遍历集合。

[java] view
plain copy

<span style="white-space:pre"> </span>// 通过字符输入流读取数据。

BufferedReader br = new BufferedReader(new FileReader("mail.txt"));

// 创建一个集合

ArrayList<String> array = new ArrayList<String>();

// 定义邮箱规则

String regex = "\\w+@\\w{2,8}(\\.\\w{2,3})+";

String line = null;

while ((line = br.readLine()) != null) {

Pattern p = Pattern.compile(regex);

Matcher m = p.matcher(line);

while (m.find()) {

array.add(m.group());

}

}

// 遍历集合。

for (String s : array) {

System.out.println(s);

}

br.close();

反射

1:反射机制:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

2:学习反射需要有以下步骤

A:首先学习字节码文件

B:第二学习 获取字节码文件的构造方法 并创建对象

C:有了对象了,就要学会获取对象中的成员变量

D:能获取对象中的成员变量了,那么还要学习成员方法

1)字节码文件的三种获取方式

①:Object类的getClass()方法:对象.getClass()

Person p = new Person();

Class c = p.getClass();

注意所有同一个类的字节码文件对象(实例)都是同一个(因为一个类就有唯一的字节码文件)

比如: Person p = new Person();

Class c = p.getClass();

Person p2 = new Person();

Class c2 = p2.getClass();

System.out.println(p == p2);// false

System.out.println(c == c2);// true

②:数据类型的静态的class属性:类名.class

Class c3 = Person.class;

③:通过Class类的静态方法forName(String className)(一般只用最后一种,前面两种了解即可)

Class c4 = Class.forName("cn.itcast_01.Person");

2)反射获取类的构造方法

public Constructor<?>[] getConstructors():所有公共构造方法

public Constructor<?>[] getDeclaredConstructors():所有构造方法 包括私有

public Constructor<T> getConstructor(Class<?>... parameterTypes):获取单个构造方法

比如:

[java] view
plain copy

<span style="white-space:pre"> </span>Class c = Class.forName("cn.itcast_01.Person");

Constructor con = c.getConstructor();//获取无参构造,因为没有参数

Object obj = con.newInstance();//用无参构造方法创建对象

System.out.println(obj);

Constructor con = c.getConstructor(String.class, int.class);//获取有参构造,因为有参数

Object obj = con.newInstance("林青霞", 26);//用有参构造方法创建对象

System.out.println(obj);

注意:

这个地方讲了一个可变参数

[java] view
plain copy

<span style="white-space:pre"> </span> public static void main(String[] args) {

int a = 10;

int b = 20;

int result = sum(a, b);//随意传任意个参数

System.out.println(result);

int c = 30;

result = sum(a, b, c);//随意传任意个参数

System.out.println(result);

int d = 40;

result = sum(a, b, c, d);//随意传任意个参数

System.out.println(result);

int e = 50;

result = sum(a, b, c, d, e);//随意传任意个参数

System.out.println(result);

}

public static int sum(int... x) {

int result = 0;

for (int i : x) {//底层就会把参数们封装层成一个数组,所以x是个数组

result += i;

}

return result;

}

3)反射获取类的成员变量

Field[] fields = c.getFields();// 获取所有公共的成员变量

Field[] fields = c.getDeclaredFields();// 获取所有的成员变量

Field field = c.getField("age");// 获取单个的成员变量

比如:获取非私有的单个成员变量

[java] view
plain copy

<span style="white-space:pre"> </span>// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");

//获取构造器对象

Constructor con = c.getConstructor();

Object obj = con.newInstance();

// 获取单个的成员变量

Field field = c.getField("age");

field.set(obj, 20);//给obj对象的field字段赋值为20

System.out.println(obj);

获取私有的单个成员变量

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");

// 创建对象

Constructor con = c.getConstructor();

Object obj = con.newInstance();

Field nameField = c.getDeclaredField("name");

nameField.setAccessible(true);//你就不要限制我了。这个地方是暴力访问,是Field父类的方法

nameField.set(obj, "林青霞");

4)反射获取类的成员方法

[java] view
plain copy

<span style="white-space:pre"> </span>Method[] methods = c.getMethods();// 所有公共方法,包括父类的

Method[] methods = c.getDeclaredMethods();// 本类的所有方法

Method m1 = c.getMethod("show", null);//无参数无返回值

m1.invoke(obj, null);

Method m2 = c.getMethod("function", String.class);//带参数无返回值

m2.invoke(obj, "林青霞");

Method m3 = c.getMethod("reutrnValue", String.class,int.class);//带多个参数有返回值

Object ooo = m3.invoke(obj, "林青霞",26);// ooo就是返回的值

Method m4 = c.getDeclaredMethod("hello", null);//私有方法的调用

m4.setAccessible(true);//暴力访问

m4.invoke(obj, null);

3:案例:动态创建某个配置文件中提供的一个类的名字的这个类的对象,并执行其方法

[java] view
plain copy

<span style="white-space:pre"> </span>Properties prop = new Properties();

FileReader fr = new FileReader("test.properties");

prop.load(fr);

fr.close();

//获取类名

String className = prop.getProperty("className");

//获取方法名

String methodName = prop.getProperty("methodName");

//获取字节码文件对象

Class c = Class.forName(className);

Constructor con = c.getConstructor();

Object obj = con.newInstance();

Method m = c.getMethod(methodName, null);

m.invoke(obj, null);

4:泛型只是在编译期间(或者是你在写代码期间)强制要求你的做的一些规范,

等编译通过生成了字节码文件后,泛型就会被擦除,运行期间就没有泛型了

[java] view
plain copy

ArrayList<Integer> array = new ArrayList<Integer>();

// 获取字节码文件对象

Class c = array.getClass();

Method m = c.getMethod("add", Object.class);

m.invoke(array, "hello");

m.invoke(array, "world");

m.invoke(array, "java");

System.out.println(array);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: