反射与正则表达式
一、类的加载: 原理理解: 当使用某个类的时候,如果该类还没有被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。 a、加载: 就是指将class文件读入到内存,并创建一个Class对象 任何类被使用时系统都会建立一个Class对象 b、连接: 验证 : 是否有正确的内部结果,并和其他类协调一致。 准备: 负责为类的静态成员分配内存,并配置默认初始化值。 解析: 将类的二进制数据中的符号引用替换为直接的引用。 c、初始化:
类初始化时机: 1.访问类的实例 2.访问类的静态变量,或者为静态变量赋值, 3.调用类的静态方法 4.调用反射方式来强制创建某个类或者接口对应的 5.Java.lang.Class对象。 6.初始化某个类的子类 7. 直接使用java.exe命令来运行某个主类。
二、类加载器:
将.class文件加载到内存中,并生成对应的Class对象 分为三种: 1.BootstrapClassLoader 根类加载器: (引导类加载器)负责java核心类加载, 如System,String等,在JDK中JRE的lib目录下rt.jar文件中 2.Extension ClassLoader扩展类加载器: 负责JRE的扩展目录中Jar包的加载 在JDK中JRE的lib目录下ext目录 3.SystemClassLoader 系统类加载器: 负责在JVM启动时加载来自java命令的class文件 以及classpath环境变量所指定的jar包和类路径
三、反射 1、原理理解: 能够知道任意一个类的所有属性和方法,且能调用它的任意一个方法和属性, 这种动态获取的信息以及动态调用对象的方法的功能称为java语音的反射机制。
要解剖一个类,首先要获取到类的每一个字节码文件对应的Class类型的对象, 其中用的是Class类中的方法: 成员变量 Field 构造方法 Constructor 成员方法Method
三种方式: 1. Person p = new Person(); Class c1 = p.getClass();
2. Class c2 = Person.class;
3. Class c3 = Class.forName(“myReflect.Person”); PS: c1 == c2 true c2 == c3 true 1和2都运用于日常(2较方便),3常用于项目开发, 3中的全路径通常通过配置文件中存储的路径,因为容易出错。
3、Constructor 获取构造方法:
1)得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法 Constructor[] cons = Class.forName(“myReflect.Person”).getConstructors(); 2)获取某一个构造方法: Constructor con=Person.class.getConstructor(String.class,int.class); 括号中是参数的字节码文件对象。 4、Field 获取类中一个成员变量
FieldgetField(String s);//只能获取公有和父类中公有 FieldgetDeclaredField(String s);//获取该类中任意成员变量,包括私有 setAccessible(ture); //如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。 set(Objectobj,Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。 Object get(Objectobj);//返回指定对象上Field表示的字段的值。
5、Method 调用某个对象身上的方法,要先得到方法,再针对某个对象调用。 Method[] getMethods();//只获取公共和父类中的方法。 Method[] getDeclaredMethods();//获取本类中包含私有。 MethodgetMethod("方法名",参数.class(如果是空参可以写null)); Object invoke(Objectobj,参数);//调用方法 如果方法是静态,invoke方法中的对象参数可以为null。 示例1:import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class ReflectField { public static void main(String[] args) { Class clazz = Human.class;// 获取字节码文件对象 // 获取所有的成员变量 // Field[] fields = c.getFields(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); /*输出: * private java.lang.String Human.name * private int Human.age * private java.lang.String Human.address */ } // 获取单个的成员变量并赋值 try { // 通过带参构造方法创建对象 Constructor con = clazz.getConstructor(String.class,int.class,String.class);// 这个是公共构造方法 Object obj = con.newInstance("天下第一",22,"中国·武汉"); // 获取address并对其赋值 // Field addressField = clazz.getField("address");//NoSuchFieldException Field addressField = clazz.getDeclaredField("address"); // public void set(Object obj,Object value) // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 addressField.setAccessible(true);// 因为IllegalAccessException,所有要暴力访问 addressField.set(obj,"武汉"); // 给obj对象的addressField字段设置值为"武汉" // 获取name并对其赋值 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true);// 因为IllegalAccessException,所有要暴力访问 nameField.set(obj,"night"); // 获取age并对其赋值 Field ageField = clazz.getDeclaredField("age"); ageField.setAccessible(true); ageField.set(obj,22); ((Human) obj).show();// :22——武汉 } catch (Exception e) { e.printStackTrace(); } } } class Human { private String name; private int age = 0; private String address = "未填写"; private Human(String name) { this.name = name; } public Human(String name,int age,String address) { this.name = name; this.age = age; this.address = address; } public void show() { System.out.println(name + ":" + age + "——" + address); } } 四、正则表达式 正则即是正确的规则。 正则表达式通过一些特殊的符号来操作字符串数据,可以简化书写,不过定义太多也不便于阅读。
|