1 java反射机制介绍

定义介绍: Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。

1.1 java代码的三种状态

这里以一个Person类为例,具体代码如下:

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
public class Person {
private String name;
private Integer age;
private String gend;
public String a;
protected String b;
String c;

public Person() {
}

public Person(String name, Integer age, String gend) {
this.name = name;
this.age = age;
this.gend = gend;
}
private Person(String name, String gend){
this.name = name;
this.gend = gend;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gend='" + gend + '\'' +
'}';
}
private void laugh(){
System.out.println("person is laughing...");
}

public void eat(){
System.out.println("person is eating...");
}
}

分析图

1.2 获取class的3种方法

  1. Class.forName("全类名"),对应的是上图中的第一阶段(java源码阶段),如:Class.forName("com.reflect.entity.Person")
  2. 类名.class,对应的是上图中的第二阶段(class类对象阶段),因为字节码文件已经加载带了内存,但是还没有调用,如:ReflectTest.class
  3. 对象.getClass(),对应的是上图中的第三阶段,也就是Runtime阶段,因为此时已经创建了一个对象,如:person.getClass()

注意: 同一个*.class文件被重复或多次加载到内存中时,不会重复加载,只会加载一次

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");
Class cls2 = Person.class;
Class cls3 = new Person().getClass();

System.out.println(cls1 == cls2);//true
System.out.println(cls1 == cls3);//true

1.3 class内部的属性

  • 构造方法数组Constructor[]

    • Constructor getConstructor(Class<?>… parameterTypes)
    • Constructor<?>[] getConstructors() 获取所有由public修饰的构造方法
    • Constructor getDeclaredConstructor(Class<?>… parameterTypes)
    • Constructor<?>[] getDeclaredConstructors() 获取所有构造方法
  • 成员属性Field[]

    • Field getField(String name) 获取一个:只能获取由public修饰的成员属性
    • Field[] getFields() 获取所有 :只能获取类中定义的由public修饰的成员属性
    • Field[] getDeclaredFields() 获取所有属性:只要类中声明的,都会获取到
    • Field getDeclaredField(String name) 获取一个:只要类中声明的,都会获取到
  • 成员方法Method[]

    • Method[] getMethods() 获取全部由public修饰的成员方法
    • Method getMethod(String name, Class<?>… parameterTypes)
    • Method[] getDeclaredMethods() 获取所有
    • Method getDeclaredMethod(String name, Class<?>… parameterTypes)
  • 获取类名

    • String getName() 获取全类名
    • String getSimpleName() 仅仅获取类名

2 举例

2.1 获取成员属性

(1)Field[] getFields()

得到所有由public声明的成员属性

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Field[] fields = cls1.getFields();
for (Field field : fields){
System.out.println(field);
}

运行结果:
public java.lang.String com.reflect.entity.Person.a

(2)Field getField(String name)

得到某一个具体的由public声明的成员属性

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Field field = cls1.getField("a");
System.out.println(field);

运行结果:
public java.lang.String com.reflect.entity.Person.a

(3) Field[] getDeclaredFields()

得到所有的类中已经声明的成员属性,不管修饰符

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Field[] fields = cls1.getDeclaredFields();
for (Field field : fields){
System.out.println(field);
}

运行结果:
private java.lang.String com.reflect.entity.Person.name
private java.lang.Integer com.reflect.entity.Person.age
private java.lang.String com.reflect.entity.Person.gend
public java.lang.String com.reflect.entity.Person.a
protected java.lang.String com.reflect.entity.Person.b
java.lang.String com.reflect.entity.Person.c

(4) Field getDeclaredField(String name)

得到某一个具体的类中已经声明的成员属性,不管修饰符

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Field field = cls1.getDeclaredField("name");
System.out.println(field);

运行结果:
private java.lang.String com.reflect.entity.Person.name

2.2 获取构造方法

(1) Constructor<?>[] getConstructors()

得到所有的由public声明的构造方法

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Constructor[] constructors = cls1.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor);
}

运行结果:
public com.reflect.entity.Person()
public com.reflect.entity.Person(java.lang.String,java.lang.Integer,java.lang.String)

(2) Constructor getConstructor(Class<?>… parameterTypes)

得到某一个具体的由public声明的构造方法

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Constructor constructor = cls1.getConstructor(String.class, Integer.class, String.class);
System.out.println(constructor);

运行结果:
public com.reflect.entity.Person(java.lang.String,java.lang.Integer,java.lang.String)

(3) Constructor getDeclaredConstructor(Class<?>… parameterTypes)

得到某一个具体的类中已经声明的任意构造方法,无论用什么修饰符修饰的都可以

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Constructor constructor = cls1.getDeclaredConstructor(String.class,String.class);
System.out.println(constructor);

运行结果:
private com.reflect.entity.Person(java.lang.String,java.lang.String)

(4) Constructor<?>[] getDeclaredConstructors()

得到所有类中已经声明的构造方法,不管修饰符

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Constructor[] constructors = cls1.getDeclaredConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor);
}

运行结果:
public com.reflect.entity.Person()
private com.reflect.entity.Person(java.lang.String,java.lang.String)
public com.reflect.entity.Person(java.lang.String,java.lang.Integer,java.lang.String)

2.3 获取成员方法

(1)Method[] getMethods()

只能得到所有由public修饰的成员方法

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Method[] methods = cls1.getMethods();
for (Method method : methods){
System.out.println(method + " ");
}

运行结果:
public java.lang.String com.reflect.entity.Person.toString()
public void com.reflect.entity.Person.eat()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

(2)Method getMethod(String name, Class<?>… parameterTypes)

只能得到某一个由public修饰的方法

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Method method = cls1.getMethod("eat");
System.out.println(method + " ");

运行结果:
public void com.reflect.entity.Person.eat()

(3) Method[] getDeclaredMethods()

可以获取类中所有声明的方法

1
2
3
4
5
6
Class cls1 = Class.forName("com.reflect.entity.Person");

Method[] methods = cls1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method + " ");
}

运行结果:
public java.lang.String com.reflect.entity.Person.toString()
private void com.reflect.entity.Person.laugh()
public void com.reflect.entity.Person.eat()

(4)Method getDeclaredMethod(String name, Class<?>… parameterTypes)

得到一个指定的类中声明的任何方法

1
2
3
4
Class cls1 = Class.forName("com.reflect.entity.Person");

Method method = cls1.getDeclaredMethod("laugh");
System.out.println(method + " ");

运行结果:
private void com.reflect.entity.Person.laugh()

3 用java反射机制写框架

框架功能介绍:

  • 通过修改配置文件,修改要运行的类和类中的方法
  • 当写好配置文件之后,将配置文件配置好的类和类中的方法运行

3.1 项目结构目录

结构目录

3.2 具体代码

(1)Person.java
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
package com.reflect.entity;

public class Person {
private String name;
private Integer age;
private String gend;

public Person() {
}

public Person(String name, Integer age, String gend) {
this.name = name;
this.age = age;
this.gend = gend;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gend='" + gend + '\'' +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getGend() {
return gend;
}

public void setGend(String gend) {
this.gend = gend;
}
}

(2)Student.java
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
package com.reflect.entity;

public class Student {
private String name;
private Integer age;
private String gend;

public Student(String name, Integer age, String gend) {
this.name = name;
this.age = age;
this.gend = gend;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gend='" + gend + '\'' +
'}';
}

public Student() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getGend() {
return gend;
}

public void setGend(String gend) {
this.gend = gend;
}

public void study(){
System.out.println("学生在学习...");
}
}
(3)pro.properties
1
2
className=com.reflect.entity.Student # 要运行的类
methodName=study #要运行的该类中的方法
(4)ReflectTest.java
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
import com.reflect.entity.Person;


import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
public static void main(String[] args) throws Exception {

/*
利用反射机制,编写一个框架
*/
//创建一个配置文件的接收者
Properties pro = new Properties();
//获取配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
//加载配置文件
pro.load(is);
//得到配置文件中的配置信息
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");

//类加载
/*
获取class类的方法有三种:
1.Class.forName("全类名")
2.类名.getClass()
3.类名.class
*/
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
//调用方法
method.invoke(obj);


}
}

写在最后

欢迎大家关注鄙人的公众号【麦田里的守望者zhg】,让我们一起成长,谢谢。
微信公众号