1. 类加载过程
Java是一门编译加解析的语言,编译器先将代码编译成字节码文件(class文件),Jvm加载class文件进行解析运行!
类加载通常分三个步骤:class文件的加载、类的链接、类的初始化!
1.1 class文件的加载:
将编译后的class文件,加载到内存中,解析字节码,并生成一个Class对象!
1.1.1 类加载器介绍:
class文件的加载,并不是通过一个加载器实现,是通过多组类加载器共同实现的,共分四类:根类加载器、扩展类加载器、系统类加载器、用户类加载器!
根类加载器:在sun.boot.class.path系统变量中的路径中寻找class文件,并进行加载!
扩展类加载器:在java.ext.dirs系统变量中的路径中寻找class文件,并进行加载!类型为ExtClassLoader
系统类加载器:在java.class.path系统变量中的路径中寻找class文件,并进行加载!类型为AppClassLoader;可以通过ClassLoader.getSystemClassLoader()静态方法获取!
用户类加载器:用户自定义类加载器,根据自定义逻辑进行类加载,一般情况下父类加载器为系统类加载器!
Ps:
- Jvm系统变量可以通过System.getProperties()方式获取并查看!
- 上面四类类加载是存在层级关系的,从上到下:根类加载器、扩展类加载器、系统类加载器、用户类加载器
- 上面四类类加载器只有根类加载器不是ClassLoader的子类,其余类加载器都是ClassLoader的子类,因为根类加载器是Jvm实现!
1.1.2 类加载过程介绍:
当加载一个类的时候,首先判断缓存中是否存在,如果不存在,会通过当前使用的类加载器找到根类加载器,然后一层层向下使用类加载器寻找class文件,加载成功后,退出并返回Class对象;如果到用户类加载器依然没有找到class文件,Jvm抛出ClassNotFoundException!(手动进行类加载的时候,可以指定类加载器;如果依赖于Jvm自动进行类加载的时候,默认使用系统类加载器)
1.1.3 自定义类加载器:
可以通过继承ClassLoader类,来实现自定义用户类加载器,主要通过重写loadClass()和findClass()两个方法来实现,具体细节不再展开描述!好处就是可以定制特定类加载前的部分实现逻辑!
1.2 类的链接:
将class文件加载到内存中的二进制数据合并到JRE中:
1.3 类的初始化:
- 对类变量进行初始化赋值
- 执行静态初始化代码块
Ps:
- 调用ClassLoader.loadClass(类名)只会执行类的加载和链接,不会进行类的初始化,等到类使用的时候才会执行初始化!
- 调用Class.forName(类名)会执行类的加载、链接、并强制初始化!
1.4 触发类加载条件:
- 创建类实例
- 访问类方法
- 访问类成员
- 调用Class.forName()方法
- 加载子类的时候,会先加载所有父类
- 直接使用java.exe命令运行某个主类,会先加载主类
Ps:访问static final属性的类成员变量,如果该对象在编译期间就能确定内容;编译器会在使用它的地方直接替换为它的值,因此访问的时候,不通过类访问,所以不会触发类加载!
2. Java的反射机制
2.1 反射机制的原理:
Java中的反射是通过类加载后生成的Class对象实现的,该对象提供了所有的类操作和类信息获取能力!
获取Class对象的方法:
- 调用Class.forName()类方法,获取Class对象!
- 类.class,通过类的class属性,获取Class对象!
- 通过对象调用Object.getClass()实例方法,获取Class对象!
Ps:后面两种方式,必须保证类加载已经完成,否则无法获取;Class.forName()方式可以在类没有加载的时候调用,触发类加载!
2.2 通过反射获取信息:
2.2.1 获取构造器、获取成员、获取方法相关信息:
Ps:
- getXXX获取某个特定类型的public属性的数据!
- getXXXs获取所有public属性的数据!
- getDeclaredXXX获取某个特定类型的所有属性的数据!
- getDeclaredXXXs获取所有属性的数据!
- 数据获取的时候,都是包括继承的数据!!!
2.2.2 获取类相关信息:
/*获取Class对象所属的外部类*/
public Class<?> getDeclaringClass() throws SecurityException
/*获取类中的所有内部类*/
public Class<?>[] getDeclaredClasses() throws SecurityException
/*获取类中所有public属性的内部类*/
public Class<?>[] getClasses()
/*获取类实现的接口*/
public Class<?>[] getInterfaces()
/*获取类继承的父类*/
public native Class<? super T> getSuperclass()
2.2.3 获取注解相关信息:
/*获取指定类型的注解, 包括父类注解*/
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
/*获取指定类型的注解,不包括父类注解*/
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
/*获取当前类的所有注解,包括父类注解*/
public Annotation[] getAnnotations()
/*获取当前类的所有注解,不包括父类注解*/
public Annotation[] getDeclaredAnnotations()
/*针对Java8 重复注解功能,提供的获取指定类型注解,包括父类注解*/
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass)
/*针对Java8 重复注解功能,提供的获取指定类型注解,不包括父类注解*/
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass)
2.2.4 获取类基本信息:
/*获取包信息*/
public Package getPackage()
/*获取类名字*/
public String getName()
/*获取类的简称*/
public String getSimpleName()
/*获取类的修饰符常量值,通过Modifier工具类解码*/
public native int getModifiers()
/*class信息判断*/
/*判断obj对象是否属于当前类的实例,与instanceof用法一致*/
public native boolean isInstance(Object obj)
/*判断当前类是否是一个接口*/
public native boolean isInterface()
/*判断当前类是否是一个数组类*/
public native boolean isArray()
/*判断当前类是否为基础类类型,Boolean、Character、Byte、Short、Integer、Long、Double、Void*/
public native boolean isPrimitive()
/*判断当前类是否是一个枚举类*/
public boolean isEnum()
/*判断当前类是否是一个匿名类*/
public boolean isAnonymousClass()
/*判断当前类是否被annotationClass注解修饰*/
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
instanceof与isInstatnce解析:
public class InstanceTest
{
public static void main(String[] args)
{
ClassF f = new ClassF();
ClassS s = new ClassS();
/*instanceof Test*/
System.out.println("instanceof Test");
/*class是object本身类,编译通过,返回true*/
System.out.println(f instanceof ClassF);
/*class是object父类,编译通过,返回true*/
System.out.println(s instanceof ClassF);
/*class是object子类,编译通过,返回false*/
System.out.println(f instanceof ClassS);
/*class与object不存在任何关系,编译报错!!!*/
//System.out.println(f instanceof String);
/*isInstance Test*/
System.out.println("isInstance Test");
/*class是object本身类,编译通过,返回true*/
System.out.println(ClassF.class.isInstance(f));
/*class是object父类,编译通过,返回true*/
System.out.println(ClassF.class.isInstance(s));
/*class是object子类,编译通过,返回false*/
System.out.println(ClassS.class.isInstance(f));
/*class与object不存在任何关系,编译通过,返回false*/
System.out.println(String.class.isInstance(f));
}
}
class ClassS extends ClassF
{
}
class ClassF
{
}
Ps:
- instanceof是关键词,isInstance是Class对象的方法
- 两者用法基本相同,只是当class与object没有关系的时候,instanceof编译报错;isInstance编译通过,返回false!
2.2.5 获取方法的参数信息:
Java8,Method类和Constructor类新增了一个共同的抽象类Executable,Executable类中提供了一系列关于Parameter类的方法:
/*Executable类主要方法*/
/*获取方法或构造器的参数个数*/
public int getParameterCount()
/*获取方法或构造器的参数类型数组*/
public Type[] getGenericParameterTypes()
/*获取方法或构造器的参数数组*/
public Parameter[] getParameters()
Parameter类中也提供了一系列获取具体参数信息的方法(获取参数类型、获取参数修饰符、获取参数名、获取参数泛型类型、参数是否可变参数等等):
2.3 通过反射操作类:
java.lang.reflect包中除了提供了Class类,同时也提供了Package、Method、Field、Constructor、Array、Type、ParameterizedType等类,为获取到的反射数据提供操作能力!
2.3.1 创建对象:
通过反射创建对象有两种方式:Class对象的newInstance方法和Constructor对象的newInstance方法!
public class ReflectTest
{
public static void main(String[] args)
{
/*通过反射创建对象的两种方式*/
/*通过Class对象的newInstance()方法,只能访问public属性的构造器*/
try
{
ReflectPublic r1 = ReflectPublic.class.newInstance();
r1.hello();
}
catch (Exception e)
{
e.printStackTrace();
}
/*通过Constructor对象的newInstance()方法,可以通过setAccessible设置,不进行访问权限检测,访问private属性的构造器*/
Constructor<ReflectPrivate> constructor;
try
{
constructor = ReflectPrivate.class.getDeclaredConstructor();
constructor.setAccessible(true);
ReflectPrivate r2 = constructor.newInstance();
r2.hello();
}
catch (Exception e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
class ReflectPrivate
{
private ReflectPrivate()
{
}
public void hello()
{
System.out.println("private hello");
}
}
class ReflectPublic
{
public ReflectPublic()
{
}
public void hello()
{
System.out.println("public hello");
}
}
Ps:setAccessible()不进行类型访问权限设置,同样可以使用在Method和Field两个类,用来访问private属性的方法和成员!
2.3.2 调用方法:
通过Method类中的invoke方法进行方法调用(Object入参为null,调用静态方法)!
public class MothodTest
{
public static void main(String[] args)
{
try
{
/*通过反射调用类的静态方法*/
Method method = ReflectMothod.class.getMethod("staticfun");
method.invoke(null);
/*通过反射对象的实例方法*/
ReflectMothod r = new ReflectMothod();
Method method1 = ReflectMothod.class.getMethod("fun");
method1.invoke(r);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class ReflectMothod
{
public static void staticfun()
{
System.out.println("staticfun()");
}
public static void fun()
{
System.out.println("fun()");
}
}
2.3.3 访问成员:
代码示例:
public class FieldTest
{
public static void main(String[] args)
{
ReflectField r = new ReflectField();
r.i = 1;
r.s = "hello";
try
{
/*获取普通类型的实例成员,并修改*/
Field field = ReflectField.class.getField("i");
System.out.println(field.getInt(r));
field.setInt(r, 100);
/*获取引用类型的实例成员,并修改*/
Field field1 = ReflectField.class.getField("s");
System.out.println(field1.get(r));
field1.set(r, "hello100");
/*获取类静态成员,并修改*/
Field field2 = ReflectField.class.getField("b");
System.out.println(field2.getBoolean(null));
field2.setBoolean(null, true);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(r.i);
System.out.println(r.s);
System.out.println(ReflectField.b);
}
}
class ReflectField
{
public int i;
public String s;
public static boolean b;
}
结果输出:
2.3.4 操作数组:
java.lang.reflect包中还提供了一个Array类,用来进行数组类型的反射行为!
public class ArrayTest
{
public static void main(String[] args)
{
int[] a = new int[5];
/*通过Array类反射创建数组*/
int[] a1 = (int [])Array.newInstance(int.class, 5);
/*通过Array类反射操作数组*/
Array.set(a1, 0, 1);
System.out.println(Array.get(a1, 0));
}
}
3. 动态代理:
Java基于反射的动态代理就是,将一个接口中的所有方法实现都抽象到InvocationHandler接口中的invoke方法中,再通过Proxy或者其子类创建这个接口的实现类,实现类中通过InvocationHandler接口中的invoke方法来代理原接口中的方法!
public class ReflectProxyTest
{
public static void main(String[] args)
{
/*通过Proxy.newProxyInstance方法,创建ReflectProxy接口的实现类对象*/
ReflectProxy reflectProxy =
(ReflectProxy)Proxy.newProxyInstance(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class}, new InvocationHandlerTest());
System.out.println(reflectProxy.fun(100));
reflectProxy.run();
try
{
/*通过Proxy.getProxyClass方法,创建ReflectProxy接口的实现类的Class对象*/
Class<?> cls = Proxy.getProxyClass(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class});
/*通过Class对象获取构造器,参数必须是InvocationHandler.class*/
Constructor<?> constructor = cls.getConstructor(new Class[]{InvocationHandler.class});
/*通过构造器创建ReflectProxy接口的实现类对象*/
ReflectProxy reflectProxy1 = (ReflectProxy)constructor.newInstance(new Object[]{new InvocationHandlerTest()});
System.out.println(reflectProxy1.fun(500));
reflectProxy1.run();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
interface ReflectProxy
{
int fun(int i);
void run();
}
/*实现InvocationHandler接口中的invoke方法,用于代理ReflectProxy接口中的fun方法和run方法
*invoke的参数说明:
*proxy为动态代理对象
*method当前调用的方法
*args当前调用方法的入参
*/
class InvocationHandlerTest implements InvocationHandler
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if ("fun".equals(method.getName()))
{
System.out.println("do fun() arg is "+args[0]);
return args[0];
}
if ("run".equals(method.getName()))
{
System.out.println("do run()");
}
return null;
}
}
结果输出:
动态代理原理:Proxy.getProxyClass通过反射获取到接口中的所有抽象方法,再通过ProxyGenerator.generateProxyClass()方法生成一个接口的实现类的字节码文件(这个实现类中的有一个入参为InvocationHandler的构造器,并将所有方法的实现都转为InvocationHandler的invoke方法进行代理!),最终返回这个接口实现类的Class对象!
4. 基于动态代理实现AOP:
可以通过Java对接口的动态代理实现对特定方法增加切面,实现面向切面编程!示例如下:
public class ReflectProxyTest
{
public static void main(String[] args)
{
/*通过Proxy.newProxyInstance方法,创建ReflectProxy接口的实现类对象*/
ReflectProxy reflectProxy =
(ReflectProxy)Proxy.newProxyInstance(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class}, new InvocationHandlerTest(new ReflectProxyTemp1()));
System.out.println(reflectProxy.fun(100));
reflectProxy.run();
}
}
interface ReflectProxy
{
int fun(int i);
void run();
}
/*通过实现InvocationHandler接口,来实现对ReflectProxyTemp1类中方法增加切面*/
class InvocationHandlerTest implements InvocationHandler
{
private Object tager;
public InvocationHandlerTest(Object tager)
{
this.tager = tager;
}
private void aopFun1()
{
System.out.println("aopFun1()");
}
private void aopFun2()
{
System.out.println("aopFun2()");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
/*增加Aop切面1*/
this.aopFun1();
/*通过tager将原始实现传入InvocationHandler实现类*/
method.invoke(this.tager, args);
/*增加Aop切面2*/
this.aopFun2();
if ((null != args) && (0 != args.length))
{
return args[0];
}
return null;
}
}
/*原始类型,期望在ReflectProxyTemp1类的fun()方法和run()方法上增加切面*/
class ReflectProxyTemp1 implements ReflectProxy
{
@Override
public int fun(int i)
{
System.out.println("ReflectProxyTemp1 fun() i is " + i);
return 0;
}
@Override
public void run()
{
System.out.println("ReflectProxyTemp1 run()");
}
}
结果输出: