说明:反射是通过对类的字节码(.class)文件进行解析,实现对javaBean对象操作的技术。使用反射的好处是,所有的javaBean组成都是相同的(成员变量、成员方法、构造器),通过反射解析.class文件,可以把多种类型的对象同时解析出来,实现用同一个配置文件(如properties)实例化多个不同类型对象的效果。另外,反射还可以无视权限修饰符,访问javaBean中的任意成员。
总结,使用反射的好处:(1)通用,创建不同的对象可以动态变化;(2)不受成员权限修饰符的限制
一、获取Class对象
方式一:类名.class
// 方式一:类名.class
Class<Student> studentClass = Student.class;
System.out.println(studentClass);
方式二:static Class forName(String fullNameWithPackage)
需要注意的是,forName()的参数是类的全类名;最前面的Class后面的泛型可去掉
// 方式二:Class forName(String fullNameWithPackage)
Class studentClass = Class.forName("com.essay.Student");
System.out.println(studentClass);
方式三:new Object().getClass()
// 方式三:new Object().getClass()
Class<? extends Student> studentClass = new Student().getClass();
System.out.println(studentClass);
小结
这三种方式获取方式,推荐使用第二种
另外值得一提的是,这三种获取方式获取到的Class对象,都是同一个,比较三者的地址值,都是true
// 方式一:类名.class
Class<Student> studentClass1 = Student.class;
// 方式二:Class forName(String fullNameWithPackage)
Class studentClass2 = Class.forName("com.essay.Student");
// 方式三:new Object().getClass()
Class<? extends Student> studentClass3 = new Student().getClass();
System.out.println(studentClass1 == studentClass2);
System.out.println(studentClass1 == studentClass3);
二、通过Class对象获取Constructor构造器对象
这里使用到的Student对象类代码如下:
public class Student {
private String name;
private int age;
private String sex;
public Student() {
}
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
private Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
2.1、getConstructors():获取所有公共构造器对象
// 获取学生类的Class对象(用第二种获取Class对象的方式)
Class studentClass = Class.forName("com.essay.Student");
// getConstructors():获取所有公共构造器对象
Constructor[] constructors1 = studentClass.getConstructors();
System.out.println("--------------公共构造器对象如下--------------");
for (Constructor constructor : constructors1) {
System.out.println(constructor);
}
2.2、getDeclaredConstructors():获取所有构造器对象(公共+非公共的)
// 获取学生类的Class对象(用第二种获取Class对象的方式)
Class studentClass = Class.forName("com.essay.Student");
// getDeclaredConstructors():获取所有构造器对象
Constructor[] constructors = studentClass.getDeclaredConstructors();
System.out.println("--------------所有构造器对象(公共+非公共)如下--------------");
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
2.3、getConstructor(Class<?>... parameterTypes):获取一个指定的公共构造器对象
// 获取学生类的Class对象(用第二种获取Class对象的方式)
Class studentClass = Class.forName("com.essay.Student");
// getConstructor(Class<?>... parameterTypes):获取一个指定的带两个参数的公共构造器对象
Constructor constructor = studentClass.getConstructor(String.class, String.class);
System.out.println("--------------指定获取Student类带两个参数的公共构造器对象--------------");
System.out.println(constructor);
2.4、getDeclaredConstructor(String.class, int.class, String.class):获取一个指定的私有构造器对象
需要注意的是,这种方式当然也可以获取指定的私有构造器对象
// 获取学生类的Class对象(用第二种获取Class对象的方式)
Class studentClass = Class.forName("com.essay.Student");
// getDeclaredConstructor(Class<?>... parameterTypes):获取一个指定的带三个参数的私有构造器对象
Constructor constructor = studentClass.getDeclaredConstructor(String.class, int.class, String.class);
System.out.println("--------------指定获取Student类私有的带三个参数的构造器对象--------------");
System.out.println(constructor);
三、通过用获取到的Constructor构造器,实例化对象
3.1、获取公共无参构造,并通过其创建所属类(Student)的对象
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
Constructor constructor = studentClass.getConstructor();
// 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
// 这里就相当于不用反射技术的:new Student();
Object o = constructor.newInstance();
// 打印对象,调用对象的toString()方法
System.out.println(o);
3.2、反射获取公共一个参数构造,并通过其创建所属类(Student)的对象
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
Constructor constructor = studentClass.getConstructor(String.class, String.class);
// 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
// 这里就相当于不用反射技术的:new Student("张三", "男");
Object o = constructor.newInstance("张三", "男");
// 打印对象,调用对象的toString()方法
System.out.println(o);
3.3、反射获取私有全参构造,并通过其创建所属类(Student)的对象
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
Constructor constructor = studentClass.getDeclaredConstructor(String.class, int.class, String.class);
// 对于私有的成员,想要操作,需要先暴力反射。否则会报非法访问异常:IllegalAccessException
constructor.setAccessible(true);
// 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
// 这里就相当于不用反射技术的:new Student("张三", "男");
Object o = constructor.newInstance("张三", 29, "男");
// 打印对象,调用对象的toString()方法
System.out.println(o);
3.4、对于3.1 获取公共无参构造,并通过其创建所属类(Student)的对象的情况,可以直接使用Class提供的方法
但idea在方法上有横线提示,这种方法已过时,不推荐使用
// 获取学生类的Class对象(用第二种获取Class对象的方式)
Class studentClass = Class.forName("com.essay.Student");
// Class对象提供了便捷创建所属类对象的方法:newInstance()
Object o = studentClass.newInstance();
// 打印对象,调用对象的toString()方法
System.out.println(o);
小结
对于私有的成员,想要操作,需要先暴力反射。否则会报非法访问异常:IllegalAccessException
四、通过Class对象获取Field成员变量对象
4.1、getDeclaredFields():获取所有成员变量对象(公共+非公共)
// 获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// getDeclaredFields():获取所有成员变量对象(公共+非公共)
Field[] fields = studentClass.getDeclaredFields();
System.out.println("--------------Student对象的所有成员变量对象如下--------------");
// 遍历打印
for (Field field : fields) {
System.out.println(field);
}
4.2、getField(String name):获取指定的公共成员变量对象
博主这里先把Student类中的name属性的权限修饰符设置为public
// 将name的修饰符设置为public
public String name;
private int age;
private String sex;
// 获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// getField(String name):获取指定的公共成员变量对象
Field name = studentClass.getField("name");
System.out.println("--------------Student对象成员变量name对象如下--------------");
System.out.println(name);
4.3、getDeclaredField(String name):获取指定的任意一个(公共或私有等)成员变量对象
// 获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// getDeclaredField(String name):获取指定的任意一个(公共或私有等)成员变量对象
Field age = studentClass.getDeclaredField("age");
System.out.println("--------------Student对象成员变量age对象如下--------------");
System.out.println(age);
五、使用获取到的Field对象为成员变量赋值或者取值
5.1、获取公共的成员变量name并使用
需要注意,在4.2那里,我将Student类name属性权限修饰符改为了public
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的属性Field对象
Field name = studentClass.getField("name");
// 3.1 准备一个学生对象
Object o = studentClass.newInstance();
// 3.2 为成员变量赋值
// void set(Object 所属类的对象, Object 要赋的值)
name.set(o, "张三");
// 3.3 获取对象的值
// get(Object object)
System.out.println(name.get(o));
5.2、获取私有的成员变量age并使用
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的属性Field对象
Field age = studentClass.getDeclaredField("age");
// 3.1 准备一个学生对象
Object o = studentClass.newInstance();
// 暴力反写(因为age属性权限修饰符为private,故少了此行代码,程序会报非法访问异常:IllegalAccessException)
age.setAccessible(true);
// 3.2 为成员变量赋值
// void set(Object 所属类的对象, Object 要赋的值)
age.set(o, 30);
// 3.3 获取对象的值
// get(Object object)
System.out.println(age.get(o));
小结
公共和私有变量获取使用的区别有以下两点:
获取方法不同:公共变量获取方法是getField();私有变量获取方法是getDeclaredField()
访问方式不同:公共变量访问不需要暴力破解;私有变量需要加一行代码(变量名.setAccessible(true); )
六、通过Class对象获取Method成员方法对象
我在Student类中添加了四个方法,两个私有,两个公开
public class Student {
// 将name的修饰符设置为public
public String name;
private int age;
private String sex;
public Student() {
}
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
private Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 添加以下四个方法
private void add(){
System.out.println("add.......");
}
private void delete(int id){
System.out.println("delete.......");
}
public void update(){
System.out.println("update.......");
}
public void find(int id){
System.out.println("find.......");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
6.1、getMethods() 获取所有公共的成员方法
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
Method[] methods = studentClass.getMethods();
System.out.println("--------------Student对象的所有公共的成员方法对象如下--------------");
for (Method method : methods) {
System.out.println(method);
}
需要注意的是,这里包括了继承自Object类的一些公共方法
6.2、getDeclaredMethods() 获取所有的成员方法
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
Method[] methods = studentClass.getDeclaredMethods();
System.out.println("--------------Student对象的所有成员方法对象如下--------------");
for (Method method : methods) {
System.out.println(method);
}
需要注意的是,这里不包含继承自Object类的方法,是Student类中的所有成员方法(含私有的)
6.3、getMethod(String methodName, Class... args) 获取指定的某个公共的成员方法
值得一提,没有参数的方法可以获取,getMethod()方法的参数二空着就行
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
Method method = studentClass.getMethod("find", int.class);
System.out.println("--------------Student对象的指定名称和参数的公共的方法对象如下--------------");
System.out.println(method);
6.4、getDeclaredMethod(String methodName, Class... args):获取指定的某个私有的成员方法
当然,这种方式也可获取到非私有方法对象
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
Method method = studentClass.getDeclaredMethod("delete", int.class);
System.out.println("--------------Student对象的指定名称和参数的私有的方法对象如下--------------");
System.out.println(method);
小结
getMethods():获取所有公共的成员方法,包含了继承自Object类的方法
getDeclaredMethods():获取所有的成员方法,不包含继承自Objcet类的方法,是类的成员方法(私有+公共的)
getMethod(String methodName, Class... args):获取指定的某个公共的成员方法,只能是公共的
getDeclaredMethod(String methodName, Class... args):获取指定的某个私有的成员方法,私有&公共都可以
七、使用获取到的Method对象反射调用成员方法
使用invoke()方法调用成员方法,需要注意两点: (1)私有成员,使用前需要暴力破解,否则会报非法访问异常:IllegalAccessException; (2)反射调用成员方法前,需要先准备一个当前类的对象
// 1.获取当前类(Student)的Class对象
Class studentClass = Class.forName("com.essay.Student");
// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
Method method = studentClass.getDeclaredMethod("delete", int.class);
// 3.通过当前类(Student)的方法Method对象的invoke方法调用方法
// 私有成员,使用前需要暴力反射,否则报错非法访问异常:IllegalAccessException
method.setAccessible(true);
// 3.1 准备一个当前类(Student)的对象
Object o = studentClass.newInstance();
// 3.2 反射调用成员方法
method.invoke(o, 10);
总结
程序执行过程中会有许多运行时异常,需要抛出,建议在方法上直接抛出 Exception