反射

据我们所知,Java是一种静态语言。但是Java却可以通过Reflection(反射)实现动态语言的特性,反射机制允许在执行期间借助Reflection API取得任何类的内部信息,并且能直接操作任意对象的内部属性及方法。

反射对象相当于是一面镜子,通过镜子,"反射"得到对象的信息:某个类的属性、方法、构造器、实现的接口。

获得反射对象

通过对象获得

1
Class c1 = person.getClass();

通过forname获得

1
Class c2 = Class.forName("cn.icewindy.test.Person");

通过类名.class获得

1
Class c3 = Person.class;

验证一下:

1
System.out.printf("c1:%s,c2:%s,c3:%s\n", c1.hashCode(), c2.hashCode(), c3.hashCode());//output:c1:295530567,c2:295530567,c3:295530567

基本内置类型的包装类都有一个TYPE属性

1
Class c4 = Integer.TYPE;

获得父类类型

1
2
3
Class c4 = student.getClass();
Class c5 = c4.getSuperclass();
System.out.printf("c5:%s\n", c5.hashCode());//output:c5:295530567

拥有Class对象的类型

class 各种类、interface 接口、[] 数组、enum 枚举、annotation 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = Override.class;
Class c6 = ElementType.class;
Class c7 = Integer.class;
Class c8 = void.class;//小写v表示void基本数据类型,大写V表示void的自动装箱类型
Class c9 = Class.class;

System.out.println(c1);//output:class java.lang.Object
System.out.println(c2);//output:class java.lang.Comparable
System.out.println(c3);//output:class [Ljava.lang.String; ,一维数组用一个[
System.out.println(c4);//output:class [[I ,二维数组用两个[
System.out.println(c5);//output:interface java.lang.Override
System.out.println(c6);//output:enum java.lang.annotation.ElementType
System.out.println(c7);//output:class java.lang.Integer
System.out.println(c8);//output:void
System.out.println(c9);//output:class java.lang.Class

类加载过程分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
/*
* 1.加载到内存,产生一个类对应的java.lang.Class对象
* 2.链接JVM,为类变量(静态变量)分配内存并设置为默认初始化值
* 3.初始化类,调用类构造器<clinit>()将代码块合并
* <clinit>(){
* System.out.println("A静态代码块初始化");
* m = 300;
* m = 100;
* }
*/
}
}

class A{
static {
System.out.println("A静态代码块初始化");
m = 300;
}

static int m = 100;

public A(){
System.out.println("A构造函数初始化");
}
}

out:

1
2
3
A静态代码块初始化
A构造函数初始化
100

类的初始化发生

类的主动引用(会发生初始化)
  1. JVM启动,初始化main方法所在的类
  2. new一个类的对象
  3. 调用类的静态成员(除了常量final)和静态方法
  4. 使用java.lang.reflect包的方法对类进行反射调用
  5. 当初始化一个类,如果父类没有被初始化,则先初始化父类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Test {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
Son son = new Son();
/*out:
* Main类被加载 --1
* 父类被加载 --5
* 子类被加载 --2
*/
Class.forName("cn.icewindy.test.Son");
/*out: --4
* Main类被加载
* 父类被加载
* 子类被加载
*/
}
}
class Father{
static int a = 1;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
}
static final int b = 2;
}
类的被动引用(不会发生初始化)
  1. 当访问一个静态域,只有真正申明这个域的类才会被初始化。如:通过子类引用父类的静态变量,不会导致子类初始化
1
2
3
4
5
6
7
8
System.out.println(Father.a);
System.out.println(Son.a);
/* out: --1
* Main类被加载
* 父类被加载
* 1
* 1
*/
  1. 通过数组定义类的引用,不会发生此类初始化
1
Son[] arraySon = new Son[5];//out: Main类被加载
  1. 引用常量不会触发类的初始化
1
2
3
4
5
System.out.println(Son.b);
/* out:
* Main类被加载
* 2
*/

获取类的结构

获取类的名称

  • getName()可以获取包名+类名;

  • getSimpleName()可以获取类名。

获取类的属性

  • Field getField(name)根据name获取某个public的属性(包括父类);
  • Field getDeclaredField(name)根据name获取某个属性(不包括父类);
  • Field[] getFields()获取所有public的属性(包括父类);
  • Field[] getDeclaredFields()获取所有属性(不包括父类)。

获得属性的值

  • Field.get(Object)根据Object实例获取其对应属性的值。

获取类的方法

  • Method getMethod(name, Class...)获取某个public的方法(包括父类)Classs代表参数类型;
  • Method getDeclaredMethod(name, Class...):获取某个方法(不包括父类)Classs代表参数类型;
  • Method[] getMethods()获取所有public的方法(包括父类);
  • Method[] getDeclaredMethods()获取所有方法(不包括父类)。

获取类的构造器

  • getConstructor(Class...):获取某个public的构造器;
  • getDeclaredConstructor(Class...):获取某个构造器;
  • getConstructors():获取public的构造器;
  • getDeclaredConstructors():获取所有构造器。

例子1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
Class s = Class.forName("cn.icewindy.test.Student");
//获得类的名字
System.out.println(s.getName()); //out:cn.icewindy.test.Student
System.out.println(s.getSimpleName());//out:Student
//获得类的属性
Field[] fields = s.getDeclaredFields();//获取所有field(不包括父类)
for (Field field : fields) { //out:
System.out.println(field); //private int cn.icewindy.test.Student.ID
}
Field[] fields2 = s.getFields();//获取所有public的field(包括父类)
for (Field field : fields2) { //output:
System.out.println(field); //public java.lang.String cn.icewindy.test.Person.name
} //public int cn.icewindy.test.Person.age
//获得属性的值
Field field = s.getField("name");
Object value = field.get(new Student());//多态
System.out.println(value); //out:icewindy
//获得类的方法
Method[] methods = s.getMethods();//获取所有public的method(包括父类)
for (Method method : methods) { //output:太长了,省略,包括了Object的方法
System.out.println(method);
}
Method[] methods2 = s.getDeclaredMethods();//获取所有method(不包括父类)
for(Method method : methods2){ //output:
System.out.println(method); //public void cn.icewindy.test.Student.study()
} //private void cn.icewindy.test.Student.talk()
Method method = s.getMethod("say", String.class);//获取指定method
System.out.println(method); //output:public void cn.icewindy.test.Student.say(java.lang.String)
//获取类的构造器
Constructor[] constructors = s.getConstructors();//获取所有public的constructor(包括父类)
for(Constructor constructor : constructors){//output:public cn.icewindy.test.Student()
System.out.println(constructor);
}
}
}
class Person{
public String name = "icewindy";
public int age = 18;
public void sayHello(){
System.out.println("hello");
}
}
class Student extends Person{
public Student(){
System.out.println("I am a Student");
}
private int ID = 114514;
public void study(){
System.out.println("Student is studying");
}
private void talk(){}
public void say(String str){
System.out.println("Student is saying: "+str);
}
}

调用方法

调用构造器

例子2: