1. 反射的应用场景:
当我们想在早期开发的项目中使用后期新增的功能,这是早期开发的项目是无法知道的后期的功能类名,也是无法创建创建后期的类对象,导致在早期开发的项目中无法使用后期的类。如果需要使用,就必须使用Java给我们提供的反射技术。
可以在早期开发的项目中为后期的扩展预留部分接口,然后要求后期扩展的功能类必须实现早期预留的接口。同时在早期开发的项目中要求后期实现这个接口的类必须把自己的类名配置到指定的文件中。那么早期开发的项目就可以在启动的时候到指定的文件中加载配置的类名,有就去使用这个类,没有就不使用。
2. 了解Class类:
Java中可以把所有的事物用类来描述,当我们书写的Java源代码,编译完之后统一都会生成一个class文件(字节码文件)。
这个class文件也是Java世界中的一类事物,那么Java对其也有对应的类描述。描述Java中所有的class文件的那个类Class。
3.Class的API描述:
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
以上说明:在Java中所有的类型都是Class的实例。每个实例都有已经静态的成员变量class。
4.获取Class对象(三种方法):
方法一:
对象.getClass();
例如:Person person = new Person();
p.getClass();
方法二:
在所有的java源文件编译后都会生成对应的class文件,所有的class文件都属于一种自己定义的类型。
包括Java提供好的类,或者基本数据类型,所有的类型对应的Class对象用都有一个静态的成员变量,class变量。
当我们拿到任何一个类型之后,都可以使用这个类型 . class 就可以得到这个类型对应的Class的实例对象。
通过类型的静态成员变量class就可以得到对应的Class实例
类型.class;
例如:int.class;
方法三:
在Class类中有:
static Class<?> forName(String className)
需要我们指定一个字符串,然后会返回这个字符串描述的那个类对应的class文件对象。
className:是当前对应的class文件的全名称,包名+类名
Class.forName(String className);
例如:Class.forName("java.lang.Object");
当在程序中使用forName方法之后,其实这个时候JVM会根据传递的这个类名称,到指定的目录下去找对应的class文件
找到对应的class文件之后,就会把这个class文件加载内存中。然后创建对应的class文件对象(Class的实例)。
5.反射技术获取类中的构造函数:
获取非私有的构造函数:
Class.forName(String className).getConstructor(Class<?>... parameterTypes);
例如:Class.forName("java.lang.Object").getConstructor(String.class,int.class);
在Constructor类中有个newInstance(Object... initargs) 可以创建当前这个构造方法对应的类的实例。
例如:Class.forName("java.lang.Object").getConstructor(String.class,int.class).newInstance("zhangsan", 18);
获取私有的对象:
当我们想通过反射技术强制访问类中的私有的成员时: getDeclaredXxxxxx(Class<?>... parameterTypes)
拿到这个类中私有的成员。
在访问类中私有的成员时,首先需要获取到这个私有的成员,然后还要打开访问权限。
这个访问权限定义ccessibleObject类中。
setAccessible(boolean flag)当flag为true的时候,就可以让Java取消权限的检查。
例如:
// 先获取Class对象
Class clazz = Class.forName("domain.Person");
//获取类中私有的构造方法对象
Constructor con = clazz.getDeclaredConstructor(String.class);//调无参的构造方法,不传
//设置取消Java的权限限制
con.setAccessible(true);
//通过构造方法对象来创建实例对象
Object obj = con.newInstance("zhangsan");//调无参的构造方法,不传
6.反射获取类中的成员变量:
获取非私有非静态的成员变量:
// 获取Class对象
Class clazz = Class.forName("domain.Person");
// 获取到类中的公开的非静态的成员变量对象
Field f = clazz.getField("sex");
System.out.println(f);
// 通过反射技术获取到一个对象这个对象就是Person对象
Object obj = clazz.newInstance();
// 给成员变量设置值
f.set(obj, "男");
System.out.println(f.get(obj));
获取私有的成员变量:
// 获取Class对象Class clazz = Class.forName("cn.xu.domain.Person");
// 通过反射技术获取到一个对象这个对象就是Person对象
Object obj = clazz.newInstance();
Field f = clazz.getDeclaredField("name");
//设置访问权限
f.setAccessible(true);
f.set(obj, "zhangsan");
System.out.println(f.get(obj));
获取静态的成员变量:
// 获取Class对象Class clazz = Class.forName("domain.Person");
/*
* 获取类中的静态成员变量和获取类中非静态的成员方法一样
*/
Field f = clazz.getDeclaredField("pay");
//设置访问权限
f.setAccessible(true);
//由于获取到得是类中的静态的成员变量,这个成员变量在设置值的时候不需要对象,可以把对象设置null
f.set(null, 3.4);
System.out.println(f.get(null));
7.反射获取类中的成员方法:
获取非私有非静态的成员方法:
无参:
/*
* getMethod(name, parameterTypes)
* name是方法的名字,parameterTypes方法上的参数类型
* 在Method类中
* invoke(Object obj, Object... args)
* 它可以让一个方法运行起来。
* obj使用哪个对象来调用方法,
* args方法要接受的参数,如果方法不接受参数,可以不用设置
*/
public static void method() throws Exception {
// 获取Class对象
Class clazz = Class.forName("domain.Person");
//获取类中的成员方法
Method m = clazz.getMethod("show",null);
//需要一个对象
Object obj = clazz.newInstance();
//让方法执行
m.invoke(obj, null);
}
有参:
public static void method() throws Exception {// 获取Class对象
Class clazz = Class.forName("domain.Person");
//获取类中的成员方法
Method m = clazz.getMethod("show",int[].class);
//需要一个对象
Object obj = clazz.newInstance();
int[] arr ={1,2,3};
//让方法执行
m.invoke(obj, arr);
}