浅析Java反射
本文于2317天之前发表,文中内容可能已经过时。
一、反射概述
能够分析类能力的程序称为反射
JAVA反射机制是在运行状态中:
- 对于任意一个类,都能够知道这个类的所有属性和方法;
1 | * 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 |
反射就是把java类中的各种成分映射成一个个的Java对象
- 例如:一个类有:成员变量、方法、构造方法、包等等信息
- 利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
- (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
- 如图是类的正常加载过程:反射的原理在与class对象。
- 熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
image
若要学习反射,必须了解Class类
二、Class类
- Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
1 | * 也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型) |
- Class 没有公共构造方法。
- Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
返回Class类型实例
Object类中的getClass()方法
1
2
3
4
5
6
7Employee e;
Class c1 = e.getClass(); //获取到Employee类
/*
此时还有一个常用的方法getName()
*/
System.out.println(c1.getName());T.class(),此时T为任意的java类型
1
2
3Class c1 = Random.class;
Class c2 = int.class;
Class c3 = Double[].class;通过Class类中的static方法forName()
1
2
3
4
5
6
7
8
9
10
11
12
13
14String className = "java.util.Random";
try{
Class c1 = Class.forName(className);
System.out.println(c1.getName());
}
catch(ClassNotFoundException e){
e.getMessage();
}
/*
1. forName()方法抛出ClassNotFoundException
2. className必须是类名或者接口
*/
通过反射获取构造方法并使用
自定义Employee类
1 | package reflect; |
获取构造方法并使用
获取public构造器
- Constructor constructors = c1.getConstructors();
获取所有构造器
- Constructor
[] constructors = className.getDeclaredConstructors();
- Constructor
newIntance()方法的使用
调用无参构造器
- Constructor
con = c1.getConstructor(); - con.newInstance();
- Constructor
调用含参构造器
Constructor
paraCons = c1.getConstructor(String.class,double.class,int.class,int.class,int.class); paraCons.newInstance(“调用有参构造器”,600,2018,7,18));
1
2
3public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException返回值为Constructor泛型,参数个数与实际构造器一致,但参数类型为Class
获取构造方法并使用例子程序
1 | public class TestConstructors { |
通过反射获取普通方法并使用
获取所有普通方法
- Method[] method = c1.getDeclaredMethods();
获取单个普通方法
Method m = c1.getDeclaredMethod(“getName”);
1
2public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
throws NoSuchMethodException,SecurityException- 返回值为Method类型,两个参数,第一个参数为String类,即方法名称,第二个参数为Class类型
使用普通方法
1
2
3
4public Object invoke(Object obj,Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException- 返回值为Object,一共两个参数:
- 第一个参数Object是指调用该方法的对象,第二个参数是实参
通过反射获取普通方法并使用例子程序
1 | import java.lang.reflect.InvocationTargetException; |
通过反射获取成员变量
获取所有成员变量信息
- Field[] fields = c1.getDeclaredFields();
获取public成员变量信息
- Field[] fields = c1.getFields();
获取单个成员变量信息
Field f = c1.getDeclaredField(“name”);
1
2public Field getDeclaredField(String name)
throws NoSuchFieldException,SecurityException返回值为Field,有一个参数,为成员变量名字
使用成员变量
1
2
3
4
5
6
7
8
9
10
11Employee emp = (Employee)c1.getConstructor().newInstance();
f.setAccessible(true);//暴力反射,解除私有设定
f.set(emp, "xixixi");
public void set(Object obj,Object value)
throws IllegalArgumentException,
IllegalAccessException- 无返回值,共两个参数,第一个参数是:要设置的对象,第二个参数是要设置的值
- 此时注意private的成员变量不可直接访问,但是
- setAccessible()方法可解除私有设定
通过反射获取成员变量例子程序
1 | public class TestField { |
反射与配置文件结合使用
配置文件pro.txt,注意是要放在工程下面
1
2className = d_1reflect.Employee
methodName = testMethod主程序:从配置文件中获取ClassName生成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
31
32public static void main(String[] args) {
Class c1 = null;
//获取创建的Class对象
try {
c1 = Class.forName(getValue("className"));
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method m;
try {
m = c1.getDeclaredMethod(getValue("methodName"));
m.invoke((Employee)c1.getConstructor().newInstance());
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}配置文件的调用与返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public static String getValue(String str) {
Properties pro = new Properties(); //获取配置文件对象
FileReader in;
try {
in = new FileReader("pro.txt");
pro.load(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return pro.getProperty(str);
}
/*
* 在JDK1.8中输出结果为:
* --------------------------------------------------
* c1.getConstructor().newInstance()被执行,调用了无参构造器
testMeod()方法被执行
--------------------------------------------------
* */