大家都知道Java的反射机制,是框架的灵魂所在,所以由此而知,学好反射是我们通往技术大牛的必经之路。
一.什么是反射?
反射是Java中的一种动态调用技术,允许程序在运行过程中动态调用类的方法,从而提高代码的灵活性。
正常情况:我们事先知晓我们要调用哪个方法,然后再去编写代码去调用该方法,再经过编译后运行。(静态调用)
反射情况:我们事先不用知晓我们要调用哪个方法,而是在运行过程中通过其它变量等方式确定要调用的方法,再使用反射技术去调用。(动态调用技术)
下图为静态调用与动态调用技术的图解:
二.获取Class对象的三种方式:
Class:一个类被加载到内存后,JVM会创建一个对应的Class对象,且全局唯一,该对象的类型就是Class类型。Class对象是反射核心,因为可以通过Class对象获取类中所有的信息。
Class对象的三种获取方式
1.类名.class
2.对象名.getClass()
3.Class.forName("类全路径");
代码示例:
package com.bailiban.demo4;
public class Demo1 {
/**
* 获取Class对象的三种方式
*/
public static void main(String[] args) throws ClassNotFoundException {
//1、类名.class
Class<Demo1> clazz1 = Demo1.class;
//2、对象名.getClass()
Class<? extends Demo1> clazz2 = new Demo1().getClass();
//Class.forName("类的全路径")
//Class.forName:加载某个类到内存中
Class<?> clazz3 = Class.forName("com.bailiban.demo4.Demo1");
}
}
三.通过Class对象获取类中的属性
一、通过Class对象获取类的构造方法
1.clazz.getConstructor(参数类类型) //获取指定参数的公共的构造方法
2.clazz.getConstructors(); //获取所有的公共构造方法
3.clazz.getDeclaredConstructor() //获取所有的指定参数的构造方法
4.clazz.getDeclaredConstructors() //获取所有的构造方法
如果是想调用无参构造,则不需要先获取Constructor对象,直接通过Class对象调用无参构造即可clazz.newInstance();
1、获取指定参数类型的公共的构造方法
public class Demo2 {
private Demo2(int a){
}
public Demo2(String a){
}
public static void main(String[] args) throws NoSuchMethodException {
//1、获取Class对象
Class<Demo2> clazz = Demo2.class;
//2、获取构造方法
//1、获取指定参数类型的公共的构造方法
Constructor<Demo2> constructor = clazz.getConstructor(String.class);
// Constructor<Demo2> constructor = clazz.getConstructor(int.class);
System.out.println(constructor);
}
}
注意:此方法只能获取权限修饰符为public的构造方法,不能获取private的构造方法,否则出出现报错。
2、获取所有的公共的构造方法
public class Demo2 {
private Demo2(int a){
}
public Demo2(String a){
}
public static void main(String[] args) throws NoSuchMethodException {
//1、获取Class对象
Class<Demo2> clazz = Demo2.class;
//2、获取构造方法
//2、获取所有的公共的构造方法
Constructor<?>[] constructors = clazz.getConstructors();
System.out.println(Arrays.toString(constructors));
}
}
注意:此方法只能获取权限修饰符为public的构造方法,所以此方法只能获取参数类型为String的构造方法。
运行结果:
3、获取指定所有参数类型的构造方法(所有)
public class Demo2 {
private Demo2(int a){
}
public Demo2(String a){
}
public static void main(String[] args) throws NoSuchMethodException {
//1、获取Class对象
Class<Demo2> clazz = Demo2.class;
//2、获取构造方法
//3、获取指定所有参数类型的构造方法(所有)
Constructor<Demo2> constructor = clazz.getDeclaredConstructor(String.class);
Constructor<Demo2> constructor1 = clazz.getDeclaredConstructor(int.class);
System.out.println(constructor);
System.out.println(constructor1);
}
}
注意:此方法可以获取权限修饰符为private的构造方法,即为所有。
运行结果:
4、获取所有的构造方法
public class Demo2 {
private Demo2(int a){
}
public Demo2(String a){
}
public static void main(String[] args) throws NoSuchMethodException {
//1、获取Class对象
Class<Demo2> clazz = Demo2.class;
//2、获取构造方法
//4、获取所有的构造方法
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
System.out.println(Arrays.toString(constructors));
}
}
运行结果:
5、如果是想调用无参构造,则不需要先获取Constructor对象,直接通过Class对象调用无参构造即可clazz.newInstance();
public class Demo2 {
// private Demo2(int a){
// }
//
// public Demo2(String a){
// }
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1、获取Class对象
Class<Demo2> clazz = Demo2.class;
//2、获取构造方法
//5、获取无参构造方法
Constructor<Demo2> constructor = clazz.getDeclaredConstructor();
//反射调用无参构造方法
Demo2 demo2 = constructor.newInstance();
System.out.println(demo2);
//直接通过class对象调用无参构造方法
Demo2 demo21 = clazz.newInstance();
System.out.println(demo21);
}
}
运行结果:
四、通过Class对象获取类中的方法
我们也可以通过API获取对应的成员方法,常用API如下:
Method[] getDeclaredMethods()
: 获取当前类声明的所有方法,包括private
的方法。
Method[] getMethods()
: 获取当前类声明的所有的公共(public)方法,包括继承过来的。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
: 获取当前类声明的某个方法,包括private
的方法 。
Method getMethod(String name, Class<?>... parameterTypes)
: 获取当前类声明的某个公共(public)方法,包括继承过来的 。
代码示例:
class Student{
public void study(){
System.out.println("好好学习,天天向上。");
}
private int exam(String name){
System.out.println(name+"同学,认真考试");
int score = 90 ;
return score ;
}
}
public class Demo04Reflect {
public static void main(String[] args) throws Exception {
// 获取对应的Class对象
Class clazz = Student.class ;
// 获取对象
Student s = (Student) clazz.newInstance();
// 获取当前类定义的所有的属性
Method[] methods = clazz.getDeclaredMethods();
// 遍历所有的方法
for (Method m: methods) {
// 打印方法名称
System.out.println(m.getName());
}
// 获取方法名为study的方法
Method study = clazz.getDeclaredMethod("study");
// 通过invoke方法调用这个s对象的study方法
study.invoke(s);
// 获取方法名为exam的方法,参数类型要一致
Method exam = clazz.getDeclaredMethod("exam",String.class);
// 私有方法,必须要设置访问权限
exam.setAccessible(true);
// 通过invoke方法调用这个s对象的exam方法,接收方法调用的结果
Integer result = (Integer) exam.invoke(s,"blb");
System.out.println("考试分数为: "+result);
}
}
tips:
方法的调用依赖于某个对象,表示调用哪个对象方法。
调用私有的方法需要设置权限
setAccessible