Java语法进阶15-反射
远离颠倒梦想 人气:0反射
类加载
类在内存中的生命周期:加载-->使用-->卸载
当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化
类的加载又分为三个阶段:
(1)加载:load
就是指将类型的class字节码数据读入内存
(2)连接:link
①验证:校验合法性等
②准备:准备对应的内存(方法区),创建Class对象,为类变量赋默认值,为静态常量赋初始值。
③解析:把字节码中的符号引用替换为对应的直接地址引用
(3)初始化:initialize(类初始化)即执行<clinit>类初始化方法,大多数情况下,类的加载就完成了类的初始化,有些情况下,会延迟类的初始化。
类初始化
1、哪些操作会导致类的初始化?
(1)运行主方法所在的类,要先完成类初始化,再执行main方法
(2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化
(3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化
(4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类
(5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化
2、哪些使用类的操作,但是不会导致类的初始化?
(1)使用某个类的静态的常量(static final)
(2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化。
(3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化
类加载器
(1)引导类加载器(Bootstrap Classloader)又称为根类加载器
它负责加载jre/rt.jar核心库,它本身不是Java代码实现的,也不是ClassLoader的子类,获取它的对象时往往返回null
(2)扩展类加载器(Extension ClassLoader)
它负责加载jre/lib/ext扩展库,它是ClassLoader的子类
(3)应用程序类加载器(Application Classloader)
它负责加载项目的classpath路径下的类,它是ClassLoader的子类
(4)自定义类加载器
当你的程序需要加载“特定”目录下的类,可以自定义类加载器;
加载器的双亲委托模式
下一级的类加载器,如果接到任务时,会先搜索是否加载过,如果没有,会先把任务往上传,如果都没有加载过,一直到根加载器,如果根加载器在它负责的路径下没有找到,会往回传,如果一路回传到最后一级都没有找到,那么会报ClassNotFoundException或NoClassDefError
类加载器之间不是继承关系,是组合的方式实现的。
Class
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
简单理解为JVM运行时会在方法区记录所有class文件中所有类的信息(类名,属性,方法),并将所有类又做为Class类的对象。当调用某个类时就会将其先加载到内存中,
也就是将这个类作为Class类的对象被创建出来。在Class类中定义了许多供操作(此类)的方法(创建对象,调用属性和方法),从而可以动态的修改程序结构
Class对象是反射的根源,所有Java类型都可以获取它的类型对象。
Class
类的对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass方法自动构造,在方法区创建的,不是由程序员创建的,Class
没有公共构造方法。
获取Class对象的四种方式
(1)类型名.class
要求编译期间已知类型
(2)对象.getClass()
获取对象的运行时类型
(3)Class.forName(类型全名称)
可以获取编译期间未知的类型
(4)ClassLoader的类加载器对象.loadClass(类型全名称)
可以用系统类加载对象或自定义加载器对象加载指定路径下的类型
获取类型的详细信息
可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)
public ClassLoader getClassLoader() | 【返回该类的类加载器】 |
public String toString() | 【将对象转换为字符串】 |
public Package getPackage() | 【获取此类的包】 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法 |
public Constructor<?>[] getDeclaredConstructors() throws SecurityException | 【返回此 Class 对象表示的类声明的所有构造方法】 |
public native int getModifiers(); |
【 返回此类或接口以整数编码的 Java 语言修饰符,用二进制的某一位1,来代表一种修饰符】 |
public String getName() |
【以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称】 |
public native Class<? super T> getSuperclass(); |
【返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class】 |
public Type getGenericSuperclass() |
【返回此 Class 所表示的实体(类、接口、基本类型或 void) 的直接超类的 Type】 |
public Class<?>[] getInterfaces() | 【确定此对象所表示的类或接口实现的接口】 |
public Field getField(String name) | 【返回此 Class 对象所表示的类或接口的指定公共成员字段】 |
public Field[] getFields() throws SecurityException | 【返回此 Class 对象所表示的类或接口的所有可访问公共字段】 |
public Field getDeclaredField(String name) | 【返回此 Class 对象所表示的类或接口的指定已声明字段】 |
public Field[] getDeclaredFields() throws SecurityException | 【返回此 Class 对象所表示的类或接口所声明的所有字段】 |
public Method getMethod(String name, Class<?>... parameterTypes) | 【返回此 Class 对象所表示的类或接口的指定公共成员方法】 |
public Method[] getMethods() throws SecurityException |
【返回此 Class 对象所表示的类或接口(包括那些由该类或接口 声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法】 |
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 【返回此 Class 对象所表示的类或接口的指定已声明方法】 |
public Method[] getDeclaredMethods() throws SecurityException |
【此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法】 |
public T newInstance() | 【创建此 Class 对象所表示的类的一个新实例】 |
public Annotation[] getAnnotations() | 【返回此元素上存在的所有注释】 |
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) | 【如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null】 |
public T[] getEnumConstants() | 【如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null】 |
public boolean isMemberClass() | 【当且仅当底层类是成员类时返回 true】 |
public native boolean isInterface(); | 【判定指定的 Class 对象是否表示一个接口类型】 |
创建任意引用类型的对象
1、直接通过Class对象来实例化(要求必须有无参构造)
- (1)获取该类型的Class对象(2)创建对象 newInstance()
2、通过获取构造器对象来进行实例化
- (1)获取该类型的Class对象(2)获取构造器对象(3)创建对象 newInstance(Object... initargs)
如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
操作任意类型的属性
(1)获取该类型的Class对象
Class clazz = Class.forName("com.guigu.bean.User");
(2)获取属性对象
Field field = clazz.getDeclaredField("username");
(3)设置属性可访问
field.setAccessible(true);
(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();
(4)设置属性值
field.set(obj,"chai");
(5)获取属性值 Object value = field.get(obj);
如果操作静态属性变量,那么实例对象可以省略,用null表示
调用任意类型的方法
(1)获取该类型的Class对象
Class clazz = Class.forName("com.atguigu.service.UserService");
(2)获取方法对象
Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,"chai","123);
如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
如果方法是静态方法,实例对象也可以省略,用null代替
获取泛型父类
1、获取子类的Class对象
2、调用getGenericSuperClass()获取泛型父类
3、强转为ParameterizedType类型
4、调用getActualTypeArguments()获取实际类型参数
读取注解信息
获取类上的注解:
1、获取Class对象
2、调用getAnnotation()方法得到注解对象
3、调用注解对象的配置参数的方法获取配置参数值
获取属性上的注解:
1、获取Class对象
2、获取某个属性Field对象
3、调用getAnnot ation()方法得到注解对象
4、调用注解对象的配置参数的方法获取配置参数值
获取方法上的注解:
1、获取Class对象
2、获取某个方法method对象
3、调用getAnnot ation()方法得到注解对象
4、调用注解对象的配置参数的方法获取配置参数值
获取内部类或外部类信息
public Class<?>[] getClasses():
【返回所有公共内部类和内部接口。包括从超类继承的公共类和接口成员以及该类声明的公共类和接口成员。】
public Class<?>[] getDeclaredClasses():
【返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口。包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口】
public Class<?> getDeclaringClass():
【如果此 Class 对象所表示的类或接口是一个内部类或内部接口,则返回它的外部类或外部接口,否则返回null。】
动态创建和操作任意类型的数组
在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array类来动态的创建数组,操作数组元素等。
Array类提供了如下几个方法:
public static Object newInstance(Class<?> componentType, int... dimensions):
【创建一个具有指定的组件类型和维度的新数组。】
public static void setXxx(Object array,int index,xxx value):
【将array数组中[index]元素的值修改为value。此处的Xxx对应8种基本数据类型,如果该属性的类型是引用数据类型,则直接使用set(Object array,int index, Object value)方法。】
public static xxx getXxx(Object array,int index,xxx value):
【将array数组中[index]元素的值返回。此处的Xxx对应8种基本数据类型,如果该属性的类型是引用数据类型,则直接使用get(Object array,int index)方法。】
Field
String getName() | 返回此 Field 对象表示的字段的名称 |
Object get(Object obj) | 返回指定对象上此 Field 表示的字段的值 |
int getModifiers() | 以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符 |
boolean equals(Object obj) | 将此 Field 与指定对象比较 |
Type getGenericType() | 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型 |
boolean getBoolean(Object obj) | 获取一个静态或实例 boolean 字段的值 |
int getInt(Object obj) | 获取 int 类型或另一个通过扩展转换可以转换为 int 类型的基本类型的静态或实例字段的值 |
void set(Object obj, Object value) | 将指定对象变量上此 Field 对象表示的字段设置为指定的新值 |
void setShort(Object obj, short s) | 将字段的值设置为指定对象上的一个 short 值 |
void setInt(Object obj, int i) | 将字段的值设置为指定对象上的一个 int 值 |
Method
boolean equals(Object obj) | 将此 Method 与指定对象进行比较 |
String getName() | 以 String 形式返回此 Method 对象表示的方法名称 |
Object invoke(Object obj, Object... args) | 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法 |
Class<?> getReturnType() | 返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型 |
Class<?>[] getParameterTypes() | 按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型 |
int getModifiers() | 以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符 |
Type getGenericReturnType() | 返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象 |
Type[] getGenericParameterTypes() | 返回一个 Type对象的数组, Type以声明顺序表示由该对象表示的可执行文件的形式参数类型 |
Type[] getGenericExceptionTypes() | 返回一个 Type对象的数组, Type此可执行对象声明抛出的异常 |
Class<?>[] getExceptionTypes() | 返回 Class 对象的数组,这些对象描述了声明将此 Method 对象表示的底层方法抛出的异常类型 |
Class<?> getDeclaringClass() | 返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象 |
Annotation[] getDeclaredAnnotations() | 返回直接存在于此元素上的所有注释 |
Constructor
boolean equals(Object obj) | 将此 Constructor 对象与指定的对象进行比较 |
String getName() | 以字符串形式返回此构造方法的名称 |
Class<T> getDeclaringClass() | 返回 Class 对象,该对象表示声明由此 Constructor 对象表示的构造方法的类 |
int getModifiers() | 以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符 |
T newInstance(Object... initargs) | 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例 |
Class<?>[] getParameterTypes() | 按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型 |
Type[] getGenericParameterTypes() | 按照声明顺序返回一组 Type 对象,这些对象表示此 Constructor 对象所表示的方法的形参类型 |
加载全部内容