首页 > 代码库 > java(十四)反射和正则表达式
java(十四)反射和正则表达式
反射机制:
java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用他的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
说简单点:动态获取类中的信息,就是java的反射。可以理解为对类的剖析。
反射技术提高了应用的扩展性,而且应用简单,所以很常用。
想要对一个类文件进行解剖,只要获取该类的字节码文件对象即可。怎么获取呢?
获取字节码对象的方式:
package day28;
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("method 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");
}
}
package day28;
public class ReflectDemo1 {
/**
* 获取字节码对象的方式:
* 1.Object类中的getClass()方法。
* 想要用这种方式,必须要明确具体的类,并创建对象。
* 2.任何数据类型都具备一个静态的属性.class来获取其对应的class对象。
* 这种方法相对简单,但还是需要明确用到类中的静态成员,还是不够扩展。
* 3.可以用Class类中forName方法完成。
* 只要通过给定的类的字符串名称就可以获取该类,更为方便,扩展性更强。
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws ClassNotFoundException {
getClassObject_3();
}
public static void getClassObject_3() throws ClassNotFoundException {
String className="day28.Person"; //注意这里得带着包名,否则就异常了。
Class clazz=Class.forName(className);
System.out.println(clazz);
}
public static void getClassObject_2() {
Class clazz=Person.class;
Class clazz1=Person.class;
System.out.println(clazz==clazz1);
}
public static void getClassObject_1() {
Person p=new Person();
Class clazz=p.getClass();
Person p1=new Person();
Class clazz1=p.getClass();
System.out.println(clazz==clazz1);
}
}
获取字节码文件的构造函数,并创建对象。
package day28;
import java.lang.reflect.Constructor;
public class ReflectDemo2 {
/**
* 获取字节码文件的构造函数,并创建对象。
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
createNewObject_2();
}
public static void createNewObject_2() throws Exception {
//以前这样就能创建带参的对象。
Person p=new Person("小强",39);
/* 现在:
* 当获取指定名称对应类中的所体现的对象时,而该类对象初始化不使用空参数构造该怎么办呢?
* 既然是通过指定的构造函数进行对象的初始化,就要先获取到该构造函数。如何获取?
* 通过字节码文件对象的方法即可完成。该方法是:getConstructor(paramterTypes);
*/
String name="day28.Person";
Class clazz=Class.forName(name);
Constructor constructor=clazz.getConstructor(String.class,int.class);
Object obj=constructor.newInstance("小明",38);
}
public static void createNewObject_1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//以前这么写,new的时候,先根据被new的类的名称找寻改类的字节码文件,
//然后加载进内存,并创建该字节码文件对象,接着创建该字节码文件对应的person对象。
// Person p=new Person();
//现在
String name="day28.Person";
//找寻该名称的类文件,并加载进内存,并产生class对象。
Class clazz=Class.forName(name);
//如何产生该类的对象呢?newInstance方法可以产生空参的对象,但只能是空参。
Object obj=clazz.newInstance();
}
}
获取字节码文件中的字段。
package day28;
import java.lang.reflect.Field;
public class ReflectDemo3 {
/**
* 获取字节码文件中的字段。
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
getFiledDemo();
}
public static void getFiledDemo() throws Exception {
Class clazz=Class.forName("day28.Person");
//Field field=clazz.getField("age"); //只能获取共有的,private修饰的拿不到。
Field field=clazz.getDeclaredField("age"); //只获取本类,但可以获取到私有的内容。
field.setAccessible(true); //对私有字段的访问要取消权限检查。暴力访问。
Object obj=clazz.newInstance();
field.set(obj,89);
Object o=field.get(obj);
System.out.println(o);
}
}
获取字节码文件中的函数。
package day28;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectDemo4 {
/**
* 获取字节码文件中的函数。
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
getMethodDemo_3();
}
public static void getMethodDemo_3() throws Exception, Exception {
Class clazz=Class.forName("day28.Person");
Method method=clazz.getMethod("paramMethod",String.class,int.class);
Object obj=clazz.newInstance();
method.invoke(obj, "小强",89);
}
public static void getMethodDemo_2() throws Exception {
Class clazz=Class.forName("day28.Person");
Method method=clazz.getMethod("show",null); //获取空参数一般方法。
Constructor constructor=clazz.getConstructor(String.class,int.class);
Object obj=constructor.newInstance("小明",37);
method.invoke(obj, null);
}
public static void getMethodDemo() throws Exception {
Class clazz=Class.forName("day28.Person");
Method[] methods=clazz.getMethods(); //获取的都是共有的方法
Method[] methods1=clazz.getDeclaredMethods(); //只获取本类中的所有方法,包含私有
for(Method method:methods1){
System.out.println(method);
}
}
}
反射的实际应用:
package day28;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
public class ReflectTest {
/**
* 电脑运行事例。
* 涉及到的类:MainBoard SoundCard PCI
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
MainBoard mb=new MainBoard();
mb.run();
//早期就这么做,每次添加一个设备都要修改代码传递一个新创建的对象。
// mb.usePCI(new 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的子类
Object obj=clazz.newInstance();
PCI p=(PCI)clazz.newInstance();
mb.usePCI(p);
}
fis.close();
}
}
package day28;
public class MainBoard {
public void run(){
System.out.println("main board run...");
}
public void usePCI(PCI p){ //PCI p=new SoundCard()
if(p!=null){
p.open();
p.close();
}
}
}
package day28;
public interface PCI {
public void open();
public void close();
}
package day28;
import day28.PCI;
public class SoundCard implements PCI {
public void open() {
System.out.println("Sound Open");
}
public void close() {
System.out.println("Sound Close");
}
}
配置文件:PCI.properties
PCI1=day28.SoundCard //这下电脑要填网卡啊啥的,直接在配置文件一写就行了,不用改源代码了。
正则表达式:正确规则的表达式
正则表达式主要用于操作字符串数据。它是通过一些特定的符号来体现的。
所以为了掌握正则表达式,必须要学习并掌握这些符号。
正则表达式虽然将代码简化了,但是阅读性变差了。
package day28;
public class RegexDemo {
/**
* 正则表达式:正确规则表达式
* 正则表达式主要用于操作字符串数据。
*/
public static void main(String[] args) {
/*
* 需求:定义一个功能对qq号进行校验。
* qq号的要求:长度5-15 , 只能是数字 ,0不能开头
*/
String qq="1234556jkl369";
//checkQQ(qq);
String regex="[1-9][0-9]{4,14}"; //正则表达式
boolean b=qq.matches(regex);
System.out.println(qq+":"+b);
}
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(l+"正确!");
}catch(NumberFormatException e){
System.out.println(qq+":含有非法字符");
}
}else{
System.out.println(qq+":不能以0开头");
}
}else{
System.out.println(qq+":长度错误");
}
}
}
package day28;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo2 {
public static void main(String[] args) {
/*
* 正则表达式对字符串的常见操作:
* 1.匹配
* 其实使用的就是String类中的matches方法。
* 2.切割
* 其实使用的就是String类中的split方法。
* 组:(A(B(C))) 从左括号数,依次为第一组,第二组....
* 3.替换
* 其实使用的就是String类中的replaceAll方法
* 4.获取
* 将正则规则进行对象的封装。
* Pattern p = Pattern.compile("a*b");
* 通过正则对象的matcher方法和字符串关联,获取要对字符串操作的匹配器对象Matcher。
* Matcher m = p.matcher("aaaaab");
* 通过Matcher匹配器对象的方法对字符串进行操作。
* boolean b = m.matches();
*
*/
functionDemo_4();
}
public static void functionDemo_1(){
//匹配手机号码是否正确
String tel="15800001111";
String regex="1[358]\\d{9}"; //这里要两个反斜线+d,第一个是把第二个转义,让它变成反斜线的意思
boolean b=tel.matches(regex);
System.out.println(tel+":"+b);
}
public static void functionDemo_2(){
String str="zhangsan****xiaoqiang########zhaoliu";
String regex="(.)\\1+"; //括号(.)就是把.封装成组,这里默认就是第一组,然后引用第一组。
String[] names=str.split(regex);
for(String name:names){
System.out.println(name);
}
}
public static void functionDemo_3(){
String str="zhangsan****xiaoqiang########zhaoliu";
str=str.replaceAll("(.)\\1+", "$1"); //$1表示获取前面参数的第一组
System.out.println(str);
String tel="15800001111";
tel=tel.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2"); //这就等于把第一组和第二组留下,中间换成*
System.out.println(tel);
}
public static void functionDemo_4(){
//获取长度为三个字母的词
String str="da jia hao,ming tian bu fang jia";
String regex="\\b[a-z]{3}\\b"; //两边得有单词边界,否则就把四个五个字母的词也获取到了,只不过获取的是前三个字母,但这并不是我们想要的
System.out.println(str);
//1.将正则封装成对象
Pattern p=Pattern.compile(regex);
//2.通过正则对象获取匹配器对象
Matcher m=p.matcher(str);
//3.使用Matcher对象的方法对字符串进行操作。
//既然要获取三个字母组成的单词,用查找方法find()
while(m.find()){
System.out.println(m.group()); //获取匹配的子序列
System.out.println(m.start()+":"+m.end()); //获取位置
}
}
}
正则表达式的几个练习:
package day28;
import java.util.TreeSet;
public class RegexTest {
/**
* 练习:
* 1.治疗口吃:我我...我..我...我我要..要...要要..要要学.学学...学学.学编...编编...编编编..编程.程.程.程
* 2.对IP地址排序。
* 3.对邮件地址校验
* @param args
*/
public static void main(String[] args) {
test_1();
test_2();
test_3();
}
public static void test_3() {
String mail="woshinibaba@sina.com.cn";
String regex="[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]{1,3}){1,3}";
boolean b=mail.matches(regex);
System.out.println(mail+":"+b);
}
public static void test_2() {
String ip_str="192.168.10.34 127.0.0.1 3.3.3.3 105.70.11.55";
//为了让IP可以按照字符串顺序比较,只要每段位数相同即可。
//所以就要补0。最多补两个0,所以每段前面都加两个0。然后每段保留后3位即可。
ip_str=ip_str.replaceAll("(\\d+)", "00$1");
ip_str=ip_str.replaceAll("0*(\\d{3})", "$1");
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" ));
}
/* 这么做可以排序,但结果不对3.3.3.3应该是最小,排在最前面。
* 但是却排在了最后,但只要变成003.003.003.003就可以完成了,所以就要补0.
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);
}
*
*/
}
public static void test_1(){
String str="我我...我..我...我我要..要...要要..要要学.学学...学学.学编...编编...编编编..编程.程.程.程";
//1.将字符串中的.去掉。用替换
str=str.replaceAll("\\.", "");
//2.替换叠词
str=str.replaceAll("(.)\\1+", "$1");
System.out.println(str);
}
}
//实现 网页爬虫功能。
package day28;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest2 {
/**
* 网页爬虫。
* 就是一个程序,用于在互联网中获取符合指定规则的数据。
*
* 爬取邮箱地址。
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
List<String> list=getMails();
for(String mail:list){
System.out.println(mail);
}
}
public static List<String> getMails() throws Exception{
//1.读取源文件
BufferedReader bufr=new BufferedReader(new FileReader("mail.html"));
/*
* 如果要源文件是网络上的一个网页,稍微修改就行。
* URL url=new URL("网址");
* BufferedReader bufIn=new BufferedReader(new InputStreamReader(url.openStream()));
* 再把下面的bufr换成bufIn就行。
*/
//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);
//3.将符合规则的数据存储到集合中。
while(m.find()){
list.add(m.group());
}
}
return list;
}
}
本文出自 “12946849” 博客,请务必保留此出处http://12956849.blog.51cto.com/12946849/1955747
java(十四)反射和正则表达式