疯狂-反射
2017-08-14 22:34:43 59 举报
AI智能生成
疯狂java讲义,反射这一章内容,看开源框架,反射肯定有,需要系统的学习
作者其他创作
大纲/内容
疯狂-反射
类的加载、连接和初始化
JVM和类
当系统出现以下情况JVM将终止:1,程序运行到最后正常结束2,System.exit()或Runtime.getRuntime().exit()3,程序执行中,遇到未捕获的异常或错误4,程序所在平台强制结束JVM进程
类的加载
系统会通过加载、连接、初始化三个步骤对类进行初始化。类加载: 将类的class文件读入内存,并创建一个java.lang.Class对象。
类的加载是由类加载器完成的,JVM提供的这些类加载器被叫做类加载器。开发者也可以继承ClassLoader基类来创建自己的类加载器。可以从以下来源加载类的二进制数据:1,从本地文件系统加载class文件。2,从JAR包加载class文件3,通过网络加载class文件4,将java源文件动态编译,并执行加载java虚拟机规范允许系统与现在加某些类,而并不一定等到“首次使用”时才加载
类的连接
当加载完类后,系统生成一个对应的Class文件,接着进入连接阶段,负责把类的二进制数据合并到JRE中。类连接分为如下三个阶段:1,验证:校验加载的类是否有正确的结构,并和其他类协调一致2,准备:负责为类的类变量分配内存,并设置默认初始值3,解析:将类的二进制数据中的符号应用替换成直接引用
类的初始化
虚拟机负责对类进行初始化,主要就是对类变量进行初始化。在java类中对类变量指定初始值有两种方式:1,申明类变量时指定初始值 2,使用静态初始化块为类变量指定初始化值
JVM初始化一个类包含如下几个步骤1,如果还没加载该类,则程序先加载并连接该类2,如果该类的直接父类还没有被初始化,则先初始化其直接父类3,如果该类中有初始化语句,则系统依次执行这些初始化语句
类初始化的时机
当首次通过下面的方式来使用某个类或接口时,系统就会初始化该类或接口1,创建实例:new类、通过反射来创建、反序列化创建。2,调用某个类的类方法(静态方法)3,访问某个类或接口的类变量,或为该类变量赋值。4,通过反射方式创建类或接口的java.lang.Class对象。5,初始化某个类的子类6,用java.exe命令运行某个主类
ClassLoader#loadClass()只是加载某个类,并不会初始化该类Class#forName()会初始化该类。
类加载器
类加载器简介
在JVM中,用类的全包名作为唯一标识
在JVM启动时,会有三个类加载器:1,Bootstrap ClassLoader : 根类加载器2,Extension ClassLoader : 扩展类加载器3,System ClassLoader : 系统类加载器
Extension Classloader 被称为扩展类加载器,会加载扩展目录(%JAVA_HOME%/jre/lib/ext 或由 java.ext.dirs系统属性指定的目录)System Classloader系统类加载器,加载 java命令的 -classpath选项、java.class.path系统属性或CLASSPATH环境变量所指定的JAR包和类路径
类加载机制
1,全盘负责:当加载某个class时,该class所依赖的和引用的其他class也将由该类加载器负责载入,除非显示指定另外一个类加载器来载入。2,父类委托:先让parent类加载器试图加载该class,只有父加载器无法加载该类时,才尝试从自己的类路径中加载该类。3,缓存机制:加载过的class都会被缓存,当需要使用某个class时,先从缓存中搜寻该class,只有当缓存不命中时,才会读取二进制数据。
创建并使用自定义的类加载器
loadClass执行步骤:1,用findLoadedClass()检查是否已经加载类,如果已经加载则直接返回2,调用父加载器的loadClass()方法,如果父类加载器为null,则直接用bootStarp加载器加载3,调用findClass()方法
URLClassLoader类
通过反射查看类信息
java许多对象都有两种类型:编译时类型和运行时类型例如: Person p = new Student();p的编译时类型是Person,运行时类型是Student程序需要运行时发现对象和类的真实信息。一般有一下两种做法:1,如果在编译和运行时都知道类型的具体信息,可以先使用instanceof判断下,在强转2,编译时不知道该对象和类可能属于哪些类,只能依靠运行时信息来发现该对象和类的真实信息,这就需要反射
获得Class对象
从Class中获取信息
获取构造函数:Constructor<T> getConstructor(Class<?>...parameterTypes):返回参数对应的public构造函数Constructor<?>[] getConstructors():获得所有的public构造器Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回参数对应的构造函数Constructor<?>getDeclaredConstructors():返回所有的构造函数
获取成员变量:Field getField(String name) : 获取指定名称的public字段Field[] getFields(): 返回所有的public字段Field getDeclaredField(String name) : 返回指定名称字段Field[] getDeclaredFields() : 返回所有的字段
获取内部类:Class<?>[] getDeclaredClasses() : 返回包含的额全部内部类获取外部类:Class<?> getDeclaringClass() : 返回外部类
获取类实现的接口:Class<?>[] getInterfaces() : 返回该类实现的所有接口获取类所继承的父类Class<? super T> getSuperclass() : 返回父类的Class对象
获取类的修饰符、所在包、类名等基本信息int getModifiers():返回修饰符Package getPackage() : 获取此类的包名String getName() : 返回class的类名String getSimpleName() : 返回class简称的类名boolean isAnnotation():该class对象是否是注解(@interface)boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):该class对象是否使用了Annotation修饰boolean isAnonymousClass():该class对象是否是一个匿名类boolean isArray():该class对象是否表示一个数组类boolean isEnum(): 该class对象是否表示一个枚举类boolean isInterface():该class对象是否表示一个接口boolean isInstance(Object obj): 判断obj是否是此Class对象的实例
8新增的方法参数反射
Executable 派生了 Constructor、method方法int getParameterCount() : 获取构造器或方法的形参个数Parameter[] getParameters() : 获取构造器或方法的所有形参
Parameter是8新增的,代表方法或构造器的一个参数getModifiers() : 获取修饰符String getName() : 获取形参名Type getParameterizedType() : 获取带泛型的形参类型Class<?> getType() : 获取形参类型boolean isNamePresent() : class文件是否包含了方法的形参名信息boolean isVarArgs() : 返回该参数是否是个数可变的形参ps : 使用javac命令编译的java源文件,生成的Class文件不包含方法的形参名信息, javac -parameters 源文件名 : 生成的Class文件则包含方法的形参信息
使用反射生成并操作对象
创建对象
调用方法
访问成员变量值
操作数组
使用反射生成JDK动态代理
Proxy和InvocationHandler创建动态代理
动态代理和AOP
泛型和反射
泛型和Class类
public static <T> T getInstance(Class<T> cls)
使用反射来获取泛型信息
获取成员变量f的类型:Class<?> a = f.getType();获取成员变量f的泛型类型Type gType = f.getGenericType();ParameterizedType pType = (ParameterizedType) gType;Type rType = pType.getRawType(); (原始类型)Type[] tArgs = pType.getActualTypeArguments(); (泛型参数信息)
0 条评论
回复 删除
下一页