什么是Java的反射

反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。

通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。

Java反射优缺点

  • 优点 : 可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利

  • 缺点 :让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的

反射的应用场景

  • JDBC中,利用反射动态加载了数据库驱动程序。
  • Web服务器中利用反射调用了Sevlet的服务方法。
  • Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
  • 很多框架都用到反射机制,注入属性,调用方法,如Spring。

这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
比如下面是通过 JDK 实现动态代理的示例代码,其中就使用了反射类 Method 来调用指定的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DebugInvocationHandler implements InvocationHandler {

//代理类中的真实对象

private final Object target;

public DebugInvocationHandler(Object target) {
this.target = target;
}


public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("before method " + method.getName());
Object result = method.invoke(target, args);
System.out.println("after method " + method.getName());
return result;
}
}

另外,像 Java 中的一大利器 注解 的实现也用到了反射。

为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?

这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。

如何使用Java的反射?

通过一个全限类名创建一个对象

  • Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了
  • 类名.class; 获取Class<?> clz 对象
  • 对象.getClass();

获取构造器对象,通过构造器new出一个对象

  • Clazz.getConstructor([String.class]);
  • Con.newInstance([参数]);

通过class对象创建一个实例对象(就相当与new类名()无参构造器)

  • Cls.newInstance();

通过class对象获得一个属性对象

  • Field c=cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
  • Field c=cls.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段

通过class对象获得一个方法对象

  • Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的)
  • Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)
  • M.setAccessible(true);(让私有的方法可以执行)

让方法执行

  • 1). Method.invoke(obj实例对象,obj可变参数);—–(是有返回值的)