提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
反射,在初期学习中并不会深入的一个知识点,但如果已经学完了JavaSE还说不会反射,不显得丢人嘛
反射概述
反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类(可能在编译期间完全未知)能够调用方法/访问属性,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其属性,它是在运行时根据需要才加载。反射给Java插上动态语言的翅膀,弥补了强类型语言的不足
反射的作用
分析类的能力(获取已装载类的成员变量信息,构造方法信息,成员方法信息)
查看与操作对象(基于反射自由创建对象,调用无法直接被访问的信息,如:类,方法,变量等)
数组扩充(不常用)
实现类似函数指针的功能(将某个成员方法封装为一个method对象,在传递给其他类或者方法)
开发各种通用框架,比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,必须使用到反射,运行时动态加载需要的加载的对象
反射常用类
(1)Java.lang.Class
Class 描述所有java数据类型的类
字节码对象 , 所有的java类型 包括TYPE(类,接口,枚举,注解类型),都是 Class 的一个实例不能通过Class的构造方法来获得每种类型的Class类实例,因为Class的构造方法是私有的Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的 , 所以若类型的字节码已经存在则可以直接获取,若不存在 , 获取字节码对象的操作将导致不存在的类被类加载器加载初始化后才能获取,每一种类对象在内存中只存在一份
-
对于void 或基本类型他们的类对象可以通过其名称.class的形式获得
-
对于接口则可以通过接口名.class或Class.forName(“接口全限定名”)获得
-
对于类类型,因为ava所有类都继承自Object类,而Object类提供了getClass()方法可以使得所有的java类实例除了可以使用上面两种方式还可以通过getClass()方法来获得类类型的字节码对象,当然不是所有类都可以,而是要求该类能创建对象,能被实例化
获取字节码对象的方式
(1)数据类型名
.class数据类型可以是任意java的数据类型
包括TYPE(类,接口,枚举,注解类型),八种基本数据类型,void,数组
void.class 返回void的Class对象
int.class 返回int的Class对象
char.class 返回char的Class对象
Iterator.class 返回Iterator的Class对象
String.class 返回String的Class对象
int[].class 返回int[]的Class对象
int[][].class 返回int[][]的Class对象
同一种元素类型和同维数的数组具有同一数组Class对象
int[].class!=int[][].class
char[]!=int[].class
(2)对象调用getClass方法
只有对象可以调用该方法,即对象被创建之后才能调用,,oid和基本类型及接口,抽象类,构造函数私有化的类因为不是类或不能创建对象, 不能用该方法获得他们的Class对象
(3)调用Class的静态方法forName Class.forName(String className)
className是包括完整包名的类名或接口名即全限定名,
通过全限定名的字符串形式返回Class对象 ,void 或基本类型不能通过该方法获得字节码对象
通过此方式获取类型的字节码对象,可以在内存中还没有加载字节码的前提下,将类的字节码加载到
内存中去,可以不需要创建对象再获取 ,假如调用该方法时对应的字节码对象已经存在于内存中,则
该方法直接去获取内存中的字节码对象并返回,而不是加载同一个分字节码
特殊获取方式
- Class 的getSuperclass() 及 getDeclaringClass()可以通过子类或者被声明类的中的其他Class对象间接获得
- 基本类型的包装类和Void类中都有一个字段常量,TYPE 该字段指向对应的基本类型及void的Class对象如
int.class == Integer.TYPE
char.class == Character.TYPE
void.class== Void.TYPE在这里插入代码片
基本类型的Class对象不等于对应装箱类的Class 对象
int.class==Integer.class;//false
反射应用
-
连接数据库(JDBC)
-
动态执行方法
-
Json和Java对象互转
-
Tomcat的Servlet创建
-
MyBaits的OR/M
-
Spring Framework的Bean容器
-
org.reflections
其余详见
具体实现反射:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
public class Test
{
public String Test_str = "TEST";
private int Test_int = 999;
public Test()
{
System.out.println("执行了无参构造");
}
public Test(String str)
{
System.out.println("执行了有参构造1");
}
public Test(int i)
{
System.out.println("执行了有参构造2");
}
protected Test(boolean T)
{
System.out.println("执行了受保护的有参构造");
}
private Test(char a)
{
System.out.println("执行了私有的有参构造");
}
public void Test1() {
System.out.println("执行了公开的Test1无参方法");
}
public void Test2 (String name) {
System.out.println("执行了公开的Test2有参方法,参数为:"+name);
}
public void Test3(String name,int age) {
System.out.println("执行了公开的Test3多参方法,参数1为:"+name+" 参数2为:"+age);
}
private void Test4(Date d) {
System.out.println("执行了私有的Test4有参方法,参数为:"+d);
}
public static void Test5() {
System.out.println("执行了公开的Test5静态无参方法");
}
public static void Test6(String[] strs) {
System.out.println("执行了公开的Test6静态有参方法,参数长度为:"+strs.length);
}
public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException
{
Class clazz1 = Class.forName("Test");//写法1
//Class clazz = Test.class;//写法2
//获取所有公有构造方法
System.out.println("【1】批量返回构造方法");
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz1.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz1.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("【2】获取指定构造方法,并调用");
Class clazz2 = Test.class;
System.out.print("0:");
Constructor c0 = clazz2.getConstructor(null);
c0.newInstance();
System.out.print("1:");
Constructor c1 = clazz2.getConstructor(String.class);
c1.newInstance("指定");
System.out.print("2:");
Constructor c2 = clazz2.getConstructor(int.class);
c2.newInstance(100);
System.out.print("3:");
Constructor c3 = clazz2.getDeclaredConstructor(boolean.class);
Object obj3 = new Object();
c3.setAccessible(true);//暴力访问
c3.newInstance(true);
System.out.print("4:");
Constructor c4 = clazz2.getDeclaredConstructor(null);
c4 = clazz2.getDeclaredConstructor(char.class);
Object obj4 = new Object();
c4.setAccessible(true);//暴力访问
obj4 = c4.newInstance('a');
System.out.println("【3】获取指定方法,并调用");
Class clazz3 = Test.class;
Test t1 = (Test)clazz3.newInstance();
Method m1 = clazz3.getMethod("Test1",null);
m1.invoke(t1, null);
Test t2 = (Test)clazz3.newInstance();
Method m2 = clazz3.getMethod("Test2",String.class);
m2.invoke(t2, "STR");
Test t3 = (Test)clazz3.newInstance();
Method m3 = clazz3.getMethod("Test3",String.class,int.class);
m3.invoke(t3, "STR" ,999);
Test t4 = (Test)clazz3.newInstance();
Method m4 = clazz3.getDeclaredMethod("Test4",Date.class);
m4.setAccessible(true);//暴力访问
m4.invoke(t4, new Date());
Method m5 = clazz3.getMethod("Test5",null);
m5.invoke(null, null);//静态方法不需要对象访问
Test t6 = (Test)clazz3.newInstance();
Method m6 = clazz3.getMethod("Test6",String[].class);
String[] str = new String[]{"str1","str2","str3"};
m6.invoke(null, (Object)str);
//m6.invoke(null, (Object[])str);
//注:因为 jdk1.4和jdk1.5处理invoke方法有区别
//1.5:public Object invoke(Object obj,Object…args)
//1.4:public Object invoke(Object obj,Object[] args)
System.out.println("【4】反射类中的属性字段");
Class Clazz = Test.class;
Test T1 = (Test)Clazz.newInstance();
Field f1 = Clazz.getField("Test_str");
String new_String1 = (String) f1.get(T1);
System.out.println("初始值:"+new_String1);
f1.set(T1, "modify_TEST");
System.out.println("修改值:"+(String) f1.get(T1));
Test T2 = (Test)Clazz.newInstance();
Field f2 = Clazz.getDeclaredField("Test_int");
f2.setAccessible(true);
int new_int1 = (int)f2.get(T2);
System.out.println("初始值:"+new_int1);
f2.set(T2, 9999);
System.out.println("修改值:"+(int) f2.get(T2));
}
}
反射扩展
通过反射越过泛型检查
通过反射运行配置文件内容
反射main方法
https://blog.csdn.net/a745233700/article/details/82893076
类库详解
(1) Java.lang.reflect.Class类
字节码对象(Class类实例)提供很多操作:
- 获取Class对象
- 获取Class对象的加载器
- 获取Class对象表示的类或接口的成分(包/方法/构造器/字段/)
- 获取Class对象表示的类或接口的成分的字符串表现形式或只或只获取其中的成分名称
- 获取Class对象表示的类或接口的父类或实现接口
- 创建Class对象表示的类的对象
- 类型判断(接口/枚举/注解类/数组类/基本类型或void/)可引用判断
- 相等或子类子接口判断
1) 获取Class对象
forName(String name )
将字符串形式的类或接口的全限定名返回对应的字节码对象,不能用该方法获得
void或基本类型字节码对象 ,此方法等效于:
Class.forName(className, true, currentLoader) forName(String name,boolean initialize, ClassLoader loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象
只有 initialize 参数为 true 且以前未被初始化时,才载入该类并初始化该类。 如果是false时,调用forName方法只是在命令类加载器载入该类,而不初始化该类的静态区块,只有当该类第一次实例化时,静态区块才被调用。当为true时,则载入时就调用静态区块。 调用该方法不会产生类的实例,产生类实例可以通过newInstance方法
2)创建Class对象表示的类的对象
newInstance()
获得此字节码对象所表示的类的新实例,这是通过new以外的另一种创建类
对象的方式,调用该方法要求字节码对象所表示的类是非抽象类的且可以创建对象的类类型,抽象类、接口、数组类、基本类型或 void或者该类没有公共构造方法不能调用该方法 , 否则抛异常,调用此方法时,如果该类尚未初始化,则初始化这个类。
但是调用该方法来获得实例只能通过调用空参数的构造方法来获得,此方法不能获取非空参数的实例 , 如果Class说表示的类没有空参数的构造方法,则调用该方法会抛出异常 ,如果想通过反射调用带参数的构造方法参数实例,可以先获取Constructor实例
再通过Constructor中的newInstance方法来指定调用的含参构造方法
3) 判断
可引用判断 , 相等或子类子接口判断
isInstance(Object obj)
判断此Class对象的所表示的引用类型能否指向obj指定实例,它的作用跟
instanceof运算符等效,如
String s = "abc";
System.out.println(Object.class.isInstance(s));//true
System.out.println(s instanceof Object);//true
isAssignableFrom(Class<?> cls)
判断此类字节码对象是否与要检查的类字节码对象相等或是其子类或子接口void 或基本类型只有相同时返回true , 类和接口在相同时或是该类或接口的子类子接口时返回true
类型判断(接口/枚举/注解类/数组类/基本类型或void/)
isInterface()
判断此类对象是否表示一个接口类型 ,注释类型也是接口
isArray()
判断此类对象是否表示一个数组类
isAnnotation()
如判断此 Class 对象是否表示一个注释类型 ,
isPrimitive()
判断此类对象是否表示一个基本类型或void,是则返回true ,有九种预定义的 Class 对象
基本类型或void的Class对象Boolean.TYPE, Character.TYPE, Byte.TYPE,
Short.TYPE,Integer.TYPE,Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
分别就是基本类型或void的字节码对象 , 故他们调用此方法返回结果也是true
isEnum()
判断是否为枚举类 , 被声明enum的枚举类才会返回true ,Enum 的Class调用此方法返回false
isSynthetic()
判断此类是否是复合类
4) 获取描述的字符串表示
getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
类或接口返回全限定名字符串形式,基本类型和void返回自己的字符串形式
基本类型的数组的返回: “维数个[”+"基本类型名的首字母的大写(boolean 和long分别是Z和J)"类类型或接口的数组类返回 : “(维数个)[”+“L”+“元素类型全限定名”
String.class.getName()//返回"java.lang.String"
int.class.getName()//返回"int"
new String[1][2][3].getClass().getName()//"返回[[[Ljava.lang.String"
(new byte[3][4][5][6][7][8][9]).getClass().getName()//返回"[[[[[[[B"
boolean[][].class.getName();//返回"[[Z"
toString 重写了Object的方法,对于类(包括枚举)和接口(包括注解类)数组类返回形式是
“类型(class/interface )” + "数组维数个[ " + "全限定名"跟getName()方法相比对于类或接口或数组
类该方法仅仅是多了类型声明(class/interface ) ,对于基本类型或void则返回结果相同
注意 Object的toString等效于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
5) 获取Class对象的加载器
getClassLoader() 获得该类的类加载器,若返回null说明该类型的Class实例由引导类加载器加载的
6) 获取Class对象表示的类或接口的成分(包/方法/构造器/字段/)
getComponentType()
如果当前类不是一个数组,则返回 null,如果是一维数组则返回元素类型对
应的Class对象 , 如果是N维数组则返回N-1维该类数组类的Class对象
getFiled(String S)
获得该类或接口的名为S的公共成员字段 , 搜索顺序是:
从该类表示的类搜索带指定名的公共字段 , 若找不到—>从该类的直接父接口按声明顺序搜索一直到顶层父接口, 若找不到—>从该类对象表示的类的直接父类搜索 ,若搜不到继续搜上一个父类,如果到顶层父类都没找到,则抛出NoSuchFieldException
异常
getFileds( )
获取该Class对象表示的类或接口的所有公共字段返回所有公共字段构成是数组,先搜索本类
或接口中的公共字段按声明顺序再获取 , 再搜索其父接口及其所有父接口然后搜索父类直到
顶层父类 , 如果都没搜到任何公共字段或该Class对象表示的是void 或基本类型则返回长度为
0的Field数组.
getDeclaredField(String name)
返回此Class对象所表示的类或接口的名为name所表示的字段(任意权限)
若不存在或该Class对象表示的是void 或基本类型则抛出异常
getDeclaredFields()
返回此 Class 对象所表示的类或接口所声明的所有字段,包括所有权限修饰的字段(包括公共、保护、默认(包)访问和私有字段)构成的数组 , 如果该Class对象表示的类或接口没有声明任何字段或该Class对象表示的是void或基本类型则返回长度为0的Filed数组
getConstructor(Class[])
返回此 Class 对象表示的类的指定的公共构造方法对象。 Class[]表示指定的构造方法的形参的类对象构成的数组
getConstructors()
返回此Class 对象表示的类的所以公共的构造方法构造的数组 , 如果该类没有公共构造方法或该类是数组类或该Class表示的是接口或基本类型或void则返回长度为0的数组
getDeclaredConstructor(Class<?>... parameterTypes)
根据此 Class 对象所表示的类或接口的指定构造方法的形参的类对象构成的数组返回此构造方法
getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。包括公共、保护、默认(包)访问和私有构造方法。返回数组中的元素没有任何特定的顺序。如果该类存在一个默认构造方法,则它包含在返回的数组中。如果此 Class 对象表示接口、基本类型、数组类
或 void,则此方法返回一个长度为 0 的数组。
getMethod(String name, Class<?>... argsTypes)
返回一个此 Class 对象所表示的类或接口的指定公共成员方法。
参数name用来指定方法名称,argsTypes用来指定方法的参数类型它是一个 Class 对象数组 ,如果argsTypes为null则表示空参数 , 查找指定方法的顺序是:
–>从本类开始查找,若没有匹配的–>从其父类中查找,如果没有再往顶层去找,如果都没有则–>从该类父接口查找,一直到顶层接口,如果都没找到则抛出异常
getMethods() 返回此Class对象表示的类或接口(包括父类超父类父接口超父接口)的公共成员方法构成的数组 . 数组类返回Object类继承来的所有公共方法. 返回的数组元素没有特定顺序,如果此Class对象表示的类及其父类接口都没有公共成员方法或表示基本类型或void则返回长度为0的数组
getDeclaredMethod(String name, Class<?>... argsTypes)
返回此Class对象表示的类或接口的任意权限修饰的指定方法对象
getDeclaredMethods()
返回此Class对象表示的类或接口(不包括继承的类或接口)任意权限修饰的Method
对象,返回的数组元素没有特定顺序 , 如果此类或接口没有任何方法或Class对象表示的是基本类型或
数组或void则返回长度为0的Method数组
getInterfaces()
返回此Class对象所表示的类所实现或接口所继承的接口,返回的数组元素顺序与声明的接口
顺序一致 ,如果该Class对象表示的类没有实现任何接口或表示的接口没有继承任何接口,或表示的是
基本类型或void 则返回长度为0 的Class数组
getSuperclass()
返回此Class对象所表示的实体(类、接口、基本类型或 void)的超类的 Class。
如果该Class表示 Object 类、一个接口、一个基本类型或 void,则返回 null
getPackage()
获取此类所在的包
getDeclaringClass()
返回此类的声明类 , 内部类的声明类就是它所在的外部类,内部类实例调用getClass()返回
内部类的Class对象,再调用getDeclaringClass()
返回外部类Class对象
getModifiers()
返回此Class对象表示的类或接口的修饰符的整数形式,若被多个修饰则返回他们的和
(2)Java.lang.reflect.Constructor;//构造方法类
Constructor 描述单个构造方法及访问权限
除了继承AccessibleObject的getAnnotations, isAccessible, isAnnotationPresent, setAccessible方法外 , 提供的主要功能如下
1) 判断
equals(Object o)
如果此Constructor实例与o所指向Constructor的一个实例都是由同一个类型声明的且参数列表相同则他们是同一个构造方法
isSynthetic()
如果此构造方法是一个复合构造方法,则返回 true;否则返回 false
isVarArgs()
如果声明此构造方法可以带可变数量的参数,则返回 true;否则返回 false
2)获取构造方法的各成分
TypeVariable<Constructor<T>>[] getTypeParameters()
按照声明顺序返回一组 TypeVariable 对象,这些对象表示通过此 GenericDeclaration
对象所表示的一般声明来声明的类型变量, 即返回声明的泛型的部分
getDeclaringClass()
返回定义构造方法的类的Class对象
getModifiers()
以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符。
Class<?>[] getParameterTypes()
按照声明顺序返回此 Constructor 对象所表示构造方法的形参类型的 Class 对象构成的数组
Type[] getGenericParameterTypes()
按照声明顺序返回构造方法的形参类型的 Type 对象构成的数组
3) 通过反射方式构造实例
T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,
并用指定的初始化参数初始化该实例。空参数的构造方法反射调用该方法的initargs为null数组长度指定为0 ,跟new一样每调用一次该方法就会产生一个实例,该方法可以反射调用一个类的任意参数列表的构造方法,如果仅仅参数空参数的构造方法的一个对象可以直接调用Class中的newInstance方法反射方式调用类的构造方法创建实例,可以使得现在可以不需要预先知道未来要创建的
实例的类是什么类,而通过一个变量来存放待确定的未来的类的全限定名,将该变量’传给Class的forName方法获得类对象,再通过Class的newInstance或Constructor的newInstance方法来创建实例
4) 描述的字符串表示
toGenericString()
返回描述此 Constructor 的字符串,其中包括类型参数
toString()
返回描述此 Constructor 的字符串
getName()
返回此构造方法的名称
5) 获取声明抛出的异常类型
Class<?>[] getExceptionTypes()
返回声明在构造方法上的抛出异常类型的Class对象构成的数组
Type[] getGenericExceptionTypes()
返回声明在构造方法上的抛出异常类型的Type 对象数组
(6) 复写父类有关操作该Constructor 表示的构造方法上的注解的方法
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释(不包括继承的)。
Annotation[][] getParameterAnnotations()
按照声明顺序返回一组数组,这些数组表示通过此 Constructor 对象表示的方法的形参上的注释
(3)Java.lang.reflect.Field;//属性字段类
Field 用来描述类或接口中的字段常量,静态成员变量,非静态成员变量等
除了具有继承自AccessibleObject 的方法
getAnnotations, isAccessible, isAnnotationPresent, setAccessible, setAccessible之外
提供的主要方法入下:
1) 判断
equals(Object obj)
如果由相同的类声明并且具有相同的名称和类型,那么这两个 Field 对象是相同的
class Ac{public static final String SS = "sss";}
class Ad{public static final String SS = "sss"
Ac a1 = new Ac();
Ac a2 = new Ac();
Ac.class.getFields()[0].getDeclaringClass()==C.class.getFields()[0].getDeclaringClass();//false
a1.getClass().getFields()[0].getDeclaringClass()==a2.getClass().getFields()[0].getDeclaringClass();//true
isEnumConstant()
如果此字段表示枚举类型的元素,则返回 true
2) 获取Filed成分(修饰符,声明类型,注解)
getModifiers()
以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符 , 当同时被多个修饰时返回各个的和
可以通过Modifier类的toString方法将其转换成字符串的表现形式
getType()
返回该 Field 对象表示的字段的声明类型Class对象
getGenericType()
返回此 Field 对象所表示字段的声明类型的Type对象.
Type类型包括原始类型、参数化类型、数组类型、类型变量和基本类型。
getName()
返回此 Field 对象表示的字段的名称。
getAnnotation(注解类型)
返回该元素的指定类型注解
getDeclaredAnnotations()
返回所有该元素上的注解
3) Filed 的字符串表示
toString()
将此Filed对象转化成字符串形式 格式如下:
“修饰符”+" “+“字段类型”+” “+“定义该属性所在的类的全限定名”+”."+“字段名”
toGenericString()
将此Filed对象(包括一般类型)转化成字符串形式 格式如下
“修饰符”+" “+“一般字段类型(包括泛型的<>部分 , 如果有的话)”+” “+“定义该属性所在的类的全限定名”+”."+“字段名”
4) 提供了对指定该Field所在的类的实例的get 和set操作
通用的get 操作:Object get(Object obj)
返回指定对象上此 Field 表示的字段的值 , 适用不同的声明类型
通用的set 操作: set(Object obj, Object value)
将指定对象上此 Field 对象表示的字段设置为指定的新值
适用于基本数据类型的获取操作: get对应包装名(Object obj) 可以获取静态或实例 基本类型的字段值
适用于基本数据类型的设置操作: set对应包装名(Object obj, 基本类型)
如果获得的Field表示所表示的成员变量是私有的,则以上的set或get操作都不允许,调用会抛出异常
但可以通过Field的父类方法setAccessible(true)
来解除这种禁止,使得可以强迫性设置或获取私有变量值
(4)Java.lang.reflect.Method;//方法类
Method 用来描述某类或接口的单个方法的类
通过Class的getMethod(String name , Class<?> class)
方法可以返回一个Class对象表示的类指定方法
通过Method的invoke(Object obj, Object... args)
方法可以调用该Method实例表示的方法 , obj代表指向该方法的实例可以通过newInstance()动态创建Class对象表示的类的实例,如果该Method表示的方法是静态方法则第一个参数可以为null,因为静态不依赖于实例
提供的主要功能如下:
1)判断
equals(Object obj)
如果此Method实例与obj指向的Method实例是由相同的类声明,具有相同的名称、形参类型和返回类型,则两个 Method 相同
判断时依次获取各成分并比较都相等之后返回true
getDeclaringClass()
getName()
getReturnType()
getParameterTypes()
isVarArgs()
判断此方法是否含有可变长度的参数,含有则返回true
isSynthetic()
如果此方法为复合方法,则返回 true;否则,返回 false
isBridge()
如果此方法是 bridge 方法,则返回 true;否则,返回 false
2) 获取各成分
获取修饰符
getModifiers()
以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符
获取泛型方法的泛型声明类型
TypeVariable<Method>[] getTypeParameters()
返回按声明顺序的 TypeVariable 对象(方法泛型声明的占位符)的数组,该类型对象描述了由 GenericDeclaration 对象表示的按声明顺序来声明的泛型类型变量 , 如果所表示的方法参数中没有类型变量,则返回长度为 0 的数组
获取Method表示的方法的返回类型
Class getReturnType()
返回此 Method 对象所表示的方法的正式返回类型的 Class 对象(不包括泛型限定部分:<参数化类型的全限定名>如果有的话)
Type getGenericReturnType()
返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。
如果返回类型是参数化类型 , 则返回的 Type 对象必须表示实际的参数类型返回Type的字符串形式是 : 实际返回类型的全限定名+<参数化类型的全限定名>因为Type包括参数化类型
获取参数列表
Class<?>[] getParameterTypes()
按照声明顺序返回此 Method 对象所表示的方法的形参类型的 Class 对象的数组,如果底层返回是空参数则返回的是长度为0的Class数组,如果参数列表中有参数化类型泛型,则返回的数组中该Class类型不包括参数化的类型
Type[] getGenericParameterTypes()
按照声明顺序返回此 Method 对象所表示的方法的形参类型的 Type 对象的数组。如果底层方法不带参数,则返回长度为 0 的数组。 如果参数列表中有参数化类型泛型,则返回的数组中包括参数化类型的部分
获取方法上声明抛出的异常类
Class<?>[] getExceptionTypes()
返回声明在此 Method 对象表示的底层方法抛出的异常类型 的Class 对象的数组
Type[] getGenericExceptionTypes()
返回声明在此 Method 对象表示的方法抛出的异常类型的 Type 对象数组
获取方法定义所在的类或接口类型
getDeclaringClass()
返回此 Method 对象表示的方法的类或接口的声明类或接口的Class 对象。
获取方法名称
getName()
以 String 形式返回此 Method 对象表示的方法名称
3) 获取方法描述的字符串形式
toString()
返回描述此 Method 的字符串,包括修饰符(如果有),返回类型,声明类,方法名,参数列表.不包括泛型声明部分,返回泛型类型的不包括参数化部分,参数列表中泛型类不包括参数化部分 ,即返回格式为:
toGenericString() 返回描述此 Method 的字符串,与toString方法不同的是,多了泛型类型参数列表(如果有)
如果没有泛型类型参数列表则返回结果和toString一样该方法,返回格式如下:
“修饰符”+“<泛型声明>”+“返回类型”+“<参数化类型全限定名>”+" “+“定义该方法所在的类的全限定名”
+”.“+“方法名”+”(“+“方法的形式参数列表各类型全限定名(泛型类包括泛型限定,基本类型为本身)”+”)"
4) 反射式调用Method表示的方法
invoke(Object obj , Object... args)
通过反射调用指定对象指定参数的此 Method 对象表示的底层方法。
其中指定的形参如果是基本形参,则调用过程会包含自动装箱拆箱,
- 如果调用的方法是空参数, 则invoke的第二个参数为null,
- 如果调用的方法是静态的,则第一个参数为null
调用该方法的返回值:
- 如果Method表示的方法返回类型为基本类型,则该该调用返回过程包括自动装箱过程
- 如果Method表示的方法返回类型为基本类型数组,则该调用直接返回该数组,
- 如果Method表示的方法访问类型为void,则该调用返回null
通过反射调用该方法, 不需要创建一个类的实例就能调用成员方法
5)操作方法上注解的功能(覆盖了父类方法)
getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。该方法覆盖了父类AccessibleObject 中的 getAnnotation
getDeclaredAnnotations()
返回直接存在于此元素上的所有注释(不包括继承的) 如果没有注释直接存在于此元素上,则返回长度为零的一个数组. 该方法覆盖了父类对应的方法
Annotation[][] getParameterAnnotations()
返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注释的那个数组的数组
Object getDefaultValue()
返回由此 Method 实例表示的注释成员的默认值
6) 继承自父类的功能
getAnnotations, isAccessible, isAnnotationPresent, setAccessible
(5)Java.lang.reflect.Modifier//修饰符类
Modifier --修饰符编码解码器 ,将类接口,成员方法,成员变量,构造方法的修饰符封装为 Modifier 类
Modifier 类提供了 static 方法和常量 对类和成员访问修饰符进行解码 , 将修饰符表示为整型数
公共常量字段
PUBLIC = 1;
PRIVATE = 2;
PROTECTED = 4;
STATIC = 8;
FINAL = 16;
SYNCHRONIZED = 32;
VOLATILE = 64;
TRANSIENT = 128;
NATIVE = 256;
INTERFACE = 512;
ABSTRACT = 1024;
STRICT = 2048;
分别描述:
public,private,protected,static,final,synchronized,volatile,transient,native,interface,abstract,strictfp
如果用flag表示一个getModifier()的返回结果
int flag 由12位的二进制数表示
根据编码表
0000 0000 00011--------public
0000 0000 00102--------private
0000 0000 01004--------protected
0000 0000 10008--------static
0000 0001 000016------final
0000 0010 000032------synchronized
0000 0100 000064------volatile
0000 1000 0000128----transient
0001 0000 0000256----native
0010 0000 0000512----interface
0100 0000 00001024–abstract
1000 0000 00002048–strictfp
二进制的每一位如果为1 则代表包含该位所代表的修饰符
假如 flag = 25 ; 其二进制表示 0000 0001 1001
根据标志位为1则含有该修饰符,解码结果为 public static final
Modifier中的非公共的字段描述,其中
复合 SYNTHETIC = 4096;
注解 ANNOTATION = 8192;
枚举 ENUM = 16384;
Modifier提供了通过修饰符对应的整数判断修饰符类型的功能及根据整数返回修饰符字符串形式的方法toString
(6)java.lang.reflect.AccessibleObject
AccessibleObject 类
该类用于在反射对象中设置 accessible 标志 , 允许具有足够特权的复杂应用程序
以某种通常禁止使用的方式来操作对象 , 提供了取消JAVA访问权限的限制。
对于public 或 默认或protected 或private成员,在分别使用 Field、Method
或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查其构造方法供JVM使用’
提供注解有关的获取和判断
getAnnotation(Class<T> annotationClass)
返回该元素的指定类型的注释 ,若不存在则返回null。
getAnnotations()
此元素上存在的(包括继承的注释)所有注释构成的数组,若无, 返回数组长度为0
getDeclaredAnnotations()
返回直接存在(忽略继承的注释)于此元素上的所有注释构成的数组
isAnnotationPresent(annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false
提供accessible标志的设置和获取
setAccessible(AccessibleObject[] array, boolean flag)
静态方法
使用单一安全性检查(为了提高效率)为一组对象设置 accessible 标志。
setAccessible(boolean flag)
设置此对象的accessible 标志值 , 值为 true 则指示反射的对象在使用时应
该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。在flag值为true时 ,如果请求被拒绝 会抛出SecurityException
。
isAccessible()
获取此对象的 accessible 标志的值(boolean值)。
(7) java.lang.reflect包下的Member 接口
成员是一种接口,反映有关单个成员(字段或方法)或构造方法的标识信息
提供的功能
getDeclaringClass()
返回此Method或Field或Constructor所表示的方法或域或构造方法的声明类或接口的 Class 对象。即定义的方法或字段或构造方法所在的类
int getModifiers()
返回此Method或Field或Constructor所表示的方法或域或构造方法的 Java 语言修饰符的整数形式。
如果同时被多个修饰符修饰那么返回的是各个修饰符常量的和, 修饰符的编码解码由Modifier 类描述
getName()
返回此Method或Field或Constructor所表示的方法或域或构造方法的简单名称。
isSynthetic()
如果此成员是编译器引入的,则返回 true;否则,返回 false。
复合方法或复合字段或复合构造方法调用该方法返回true,否则为false