反射机制

概念:

反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行状态的时候才动态加载类,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的方法/访问属性。这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。通过使用反射我们不仅可以获取到任何类的成员方法(Methods)、成员变量(Fields)、构造方法(Constructors)等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。

解释:

下图是java运行的一个流程图:

图片预览

类文件会被javac编译成class文件 不过值得注意的是class文件还会自动生成一个Class对象 里面有各种变量和方法

1
2
3
fields[]:存了你定义的各种变量。
methods[]:存了你写的各种方法。
constructors[]:存了构造函数。

一旦你拿到了Class对象你就可以用Class对象中的获取成员变量Field,成员方法Method和构造方法Constructor等方法,再去动态获取一个类或者调用一个类的属性,变量,构造方法等方式。

反射机制本质是带给我们便利,但是便利可能就会带来安全隐患,所以我们可以使用Java的反射机制来绕过一些安全权限机制检查以及一些操作。

获取Class对象的方法

1.通过类名来获取

1
Class p1 = People.class;

2.通过getClass()方法来获取

不过前提是得有一个对象

1
2
Peole p2 = new People();
Class c2 = p2.getClass();

3.通过动态加载类

调用Class类中的forName()方法

1
2
Class c3 = Class.forName("com.reflectdemo.ReflectDemo");
// Class.forName(String className)

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ReflectTemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1. .class
Class c1 = ReflectTemo.class;
System.out.println("c1: " + c1.getName());

// 2. getClass()
ReflectTemo demo = new ReflectTemo();
Class c2 = demo.getClass();
System.out.println("c2: " + c2.getName());

// 3. Class.forName
Class c3 = Class.forName("ReflectTemo");
System.out.println("c3: " + c3.getName());
}
}

获取filed

1
2
3
4
5
6
7
Field[] getFields() :获取所有public修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field getDeclaredField(String name) 获取指定的成员变量

示例代码

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
import java.lang.reflect.Field;

public class FieldTest {
public String name;
public String profession;
protected int age;
private String number;
char sex;

public static void main(String[] args){
try{

Class c1 = Class.forName("FieldTest"); // 创建Class对象

Field[] fieldArray1 = c1.getDeclaredFields(); //获取全部成员变量
Field[] fieldArray2 = c1.getFields();// 获取全部public成员变量

for (Field field : fieldArray1){
System.out.println(field.getName());
}

System.out.println("-------分割线---------");

for (Field field : fieldArray2){
System.out.println(field.getName());
}
System.out.println("-------分割线---------");

Field fieldArray3 = c1.getField("name"); // 获取指定名称的public修饰的成员变量
System.out.println(fieldArray3.getName());
System.out.println("-------分割线---------");

Field fieldArray4 = c1.getDeclaredField("number"); // 获取指定的成员变量
System.out.println(fieldArray4.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}

获取成员方法Method

1
2
3
4
5
6
7
Method getMethod(String name, 类<?>... parameterTypes) //返回该类所声明的public方法

Method getDeclaredMethod(String name, 类<?>... parameterTypes) //返回该类所声明的所有方法

Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法

Method[] getDeclaredMethods() // 获取该类中的所有方法

示例代码

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
import java.lang.reflect.Constructor;
public class ConstructorTest {
public ConstructorTest() {
System.out.println("无参构造函数");
}
public ConstructorTest(String name) {
System.out.println("有参构造函数" + name);
}
private ConstructorTest(boolean n) {
System.out.println("私有构造函数");
}
public static void main(String[] args) {
try {
Class c1 = Class.forName("ConstructorTest");
Constructor[] constructors1 = c1.getDeclaredConstructors();
Constructor[] constructors2 = c1.getConstructors();
for (Constructor c : constructors1) {
System.out.println(c);
}
System.out.println("-------分割线---------");
for (Constructor c : constructors2) {
System.out.println(c);
}
System.out.println("-------分割线---------");
Constructor constructors3 = c1.getConstructor(String.class);
System.out.println(constructors3);
System.out.println("-------分割线---------");
Constructor constructors4 = c1.getDeclaredConstructor(boolean.class);
System.out.println(constructors4);
} catch (Exception e) {
e.printStackTrace();
}
}
}

反射创建类对象

使用Class对象的newInstance()方法来进行创建类对象。

1
2
Class c1 = Class.forName('MethodTest');
Object m1 = c1.newInstance();

invoke()方法 构造形式如下:

1
public Object invoke(Object obj, Object... args)

利用反射调用runtime示例

请使用java 1.8

1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.reflect.Constructor;

public class RuntimeTest {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("java.lang.Runtime");
Constructor m = c1.getDeclaredConstructor();
m.setAccessible(true);
//因为java.lang.Runtime的构造方法是private 使用这个来让我们可以访问 这就是反射的神奇之处
Object runtimeInstance = m.newInstance();
c1.getMethod("exec", String.class).invoke(runtimeInstance, "calc");
}
}

CC1 链