Aop的实现是依靠动态代理实现的,动态代理又依靠反射。所以先拿出一天时间回顾一下反射等相关知识。
类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
1.加载
就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。
2.连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
3.初始化
类初始化的时机:
1.创建类的实例
2.访问类的静态变量,或者为静态变量赋值
3.调用类的静态方法
4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
5.直接使用java.exe命令来运行某个主类
类加载器
负责将.class文件加载到内在中,并为之生成对应的Class对象。
虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
类加载器的组成
1.Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
2.Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
3.Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径(自己写的类)
反射:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
获取Class文件的三种方式
1.Object中的getClass()方法
Person person = new Person();
Class c = person.getClass();
2.数据类型的静态属性class
Class c3 = Person.class;
3..Class类中的静态方法
public static Class forName(String className)
Class c4 = Class.forName("Reflect.Person"); //带包的全路径
以上三中方式都可以获得Class字节码文件,开发时候用第三种 Class.forName。因为第三种是一个字符串,而不是具体的类名,这样我们可以把字符串配到配置文件里
接下来我们看一下如何通过反射获取构造方法并使用
新建Person类:
package Reflect;
public class Person {
private String name;
private int age;
private String address;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void show() {
System.out.println("show........");
}
public void method(String s) {
System.out.println("method "+s);
}
public String getString(String s,int i) {
return s+"==="+i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address + "]";
}
}
首先获取Person字节码文件:
//获取字节码文件
Class c4 = Class.forName("Reflect.Person"); //带包的全路径
通过getConstructors();获取所有public 修饰的构造函数
Constructor[] constructors = c4.getConstructors();
for (Constructor con : constructors) {
System.out.println(con);
}
通过getDeclaredConstructors获取所有的构造函数
//获取全部的构造方法
Constructor[] constructors2 = c4.getDeclaredConstructors();
for (Constructor con1 : constructors2) {
System.out.println(con1);
}
获取单个构造函数(分为有参数的构造器和无参数的构造器)
获取无参的构造器:
Constructor c1 = c4.getConstructor();//返回的构造方法对象(无参)
Object object = c1.newInstance();//相当于Person p = new Person();
System.out.println(object);
获取有参数的构造器:
//获取有参数的构造函数
Constructor con = c4.getConstructor(String.class,int.class,String.class);
Object obj = con.newInstance("张三",34,"济南"); //通过带参构造方法对象创建对象
System.out.println(obj);
注意getConstructor的参数是Class。需要获得各参数的Class