Java反射机制深入了解

动态语言VS静态语言

区别这两种语言最本质的地方,我个人觉得是类型系统。

静态语言,最典型的代表应该就是java,在你的程序运行之前,编译器就可以检查你的类型有没有错误,所以java是静态语言。

而动态语言,则只有当程序运行起来了之后,才知道具体的类型。

从上可知,java是一门静态语言,但是反射的存在,就让java有了一定的动态性。

反射

在没有反射之前,我们写代码都是靠对应的类名来创建对象,然后借由对象来完成对应的功能。而反射则是通过对象,来获取对应的“类”(更为准确的说应该是类对象),就好像镜子颠倒了一样。

当类被加载到内存后,在堆内存中,会出现类对应的Class对象,且只会存在一个。这个对象就保存了类的所有的信息,所以只需要获取了这个对象,就可以进行操作了。

获取类实例

可以通过以下的方法获取类实例:

  • 类名.class。如果知道类名,最推荐这种方法,它的效率最高,性能最好。
  • 对象.getClass(),继承自Object类的方法,因为所有的类都继承自Object,所以所有的对象都有这个方法。
  • Class.forName(“com.xx.xx”),利用Class这个类的静态方法获取,可能抛出找不到的异常。
  • 基本类型的包装类.TYPE。
  • 通过Classloader获取。

哪些类型有class对象

  • 外部类、内部类、局部内部类、匿名内部类;总之就是所有的类都有
  • 接口
  • 数组,两个不同长度的数组属于同一个类,但是如果类型不同则不是同一个类;两个维度不同的数组也不是同一个类。
  • 枚举
  • 注解
  • 基本类型的包装
  • void
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1.类
Class c1 = Object.class;

// 2.接口
Class c2 = Comparable.class;

// 3.数组
Class c3 = int[].class;
Class c32 = int[][].class;

// 4.枚举
Class c4 = ElementType.class;

// 5.注解
Class c5 = Override.class;

// 6.基本类型的包装
Class c6 = Integer.class;

// 7.void
Class c7 = void.class;

内存分析

在把类加载到内存的时候,java会把对应的class文件给读入内存,并在这个时候为它创建一个Class的对象,这个过程由类加载器完成——所以我们只能获取Class对象。