java的反射机制:在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性,这种动态获取信息,以及动态调用对象的方法的功能称为java语言的反射机制。
什么是类:具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。类是对象的模版,对象是类的实例,但是 类也是对象---类是java.lang.Class类的实例对象。例如 Son son = new Son(); new Son()是Son类的对象,但是Son类也是Class类的对象。
任何一个类都是Class的实例对象 这个实例对象有三种表示方式:
第一种 Class c1 = Son.class; //任何一个类都有一个隐含的静态成员变量
第二种 Class c2 = son.getClass();//该类的对象 通过getClass方法
第三种 Class c3=Class.forName("Son");//动态加载类
c1 c2 c3此时表示的是Son类的类类型。
Class类API
public void test1(){
Developer developer = new JavaDeveloper("docuxu");
//要获取类的信息 首先要获取类的类类型
Class c = developer.getClass();
//获取类的名称
String className = c.getName();
System.out.println(className);
}
//获取方法信息
//获取的事的所有public的函数 包括父类继承来的
Method[] methods = c.getMethods();
//获取的是所有该类自己声明的方法 不论访问权限 父类继承来的没有
Method[] methods = c.getDeclaredMethods();
for (Method method:methods){
//获取方法名字
System.out.println(method.getName());
//获取方法返回值类型的类类型
System.out.println(method.getReturnType());
//获取方法返回值类型
System.out.println(method.getReturnType().getName());
//获取参数列表中参数类类型
Class[] types = method.getParameterTypes();
for(Class type:types){
//获取参数类型
System.out.println(type.getName());
}
}
//获取变量信息
//获取public的成员变量的信息
Field[] fields = c.getFields();
//获取的是该类自己声明的成员变量的信息
Field[] fields = c.getDeclaredFields();
for (Field field:fields){
//获取方法名字
System.out.println(field.getName());
//得到成员变量的类类型
Class fieldType =field.getType();
System.out.println(fieldType);
//得到成员变量的类型名字
String typeName=fieldType.getName();
System.out.println(typeName);
}
//获取构造函数信息
//获取所有的public的构造函数
Constructor[] constructors = c.getConstructors();
//获取所有的构造方法 包括私有
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor:constructors){
//获取构造函数的名字
System.out.println(constructor);
//获取构造函数的参数的类类型
Class[] types = constructor.getParameterTypes();
for(Class type:types){
// 获取类型名字
System.out.println(type.getName());
}
}
方法的反射
如何获取某个方法,方法的名称和方法的参数列表才能唯一决定某个方法,method.invoke(对象,参数列表)。
如果是private修饰的方法 method.setAccessible(Boolean.TRUE);// 将私有访问限制改为public 不然会报以下错误
java.lang.IllegalAccessException: Class com.example.demo.TestReflect can not access a member of class com.example.demo.JavaDeveloper with modifiers "private"
@Test
public void test8() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Developer developer = new JavaDeveloper();
Class c = developer.getClass();
// 获取指定public方法 getMethod(方法名,参数类类型)
Method method = c.getMethod("print",int.class,int.class);
// 调用指定方法
Object obj = method.invoke(developer,1,2);
System.out.println(obj);
}
@Test
public void test9() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Developer developer = new JavaDeveloper();
Class c = developer.getClass();
// 获取指定方法 getMethod(方法名,参数类类型) 包括private
Method method = c.getDeclaredMethod("print",int.class,int.class);
// 将私有访问限制改为public
method.setAccessible(Boolean.TRUE);
// 调用指定方法
Object obj = method.invoke(developer,1,2);
System.out.println(obj);
}
编译时刻加载类是静态加载
运行时刻加载类是动态加载
new创建对象是静态加载类,在编译时刻就需要加载所有的可能使用到的类。但是动态加载类是在运行时刻进行加载需要用到的时候才会去加载,这样即可实现动态加载任何实现了Object接口的类,而不需要重新编译可以实现热部署。因此功能性的类尽可能的使用动态加载类而不是静态加载类这样方便重新升级的时候不用重新编译所有的代码。
java动态代理示例
https://www.jianshu.com/p/95970b089360
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html