本文主要是针对初学者首先是对反射概念的描述,然后介绍反射中关键类Class相关介绍与代码演示,最后介绍反射的应用案例。
1. 反射机制概念
如果在正常的情况下,如果要使用一个类,则需下列步骤:
1)使用import导入类所在的包(类:java.lang.Class)
2)通过“对象.方法()”调用类中方法
3)产生对象可以使用“对象.属性”进行类中属性的调用
4)通过关键字new进行类对象实例化
5)明确使用类名称或接口名称定义对象
而反射的过程呢?,不需要有明确类型的对象,所有的对象使用Object表示。
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码对象的方式有以下几种方式:
1)Class clazz1 = Class.forName("全限定类名"); //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
2)Class clazz2 = Student.class; //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3)Class clazz3 = s.getClass(); //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。
2. CLASS类API信息
2.1 获取实例对象
注意:Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象。
通过newInstance方法获取实例对象。代码如下:
class Demo1{
Demo1(){
System.out.println("反射调用无参构造方法");
}
}
public class Main {
public static void main(String []args) throws Exception {
Class<?> demoCls = Class.forName("reflexDemo.Demo1");
Object object = demoCls.newInstance();
}
}
首先获取全部的构造函数,然后初始化对象。代码如下:
class Demo1{
Demo1(String para){
System.out.println("反射调用有1个参构造方法 string");
}
Demo1(String para,int a){
System.out.println("反射调用有2个参构造方法string int");
}
public Demo1(String para,String a){
System.out.println("反射调用有2个参构造方法,string string");
}
}
public class Main {
public static void main(String []args) throws Exception {
Class<?> demoCls = Class.forName("reflexDemo.Demo1");
//getConstructors()方法只能获取反射类的公共构造函数(public)
Constructor constructors[] =demoCls.getConstructors();
System.out.println("getConstructors方法获取的方法数:"+constructors.length);
//getDeclaredConstructors()方法获取所有的构造函数
Constructor declaredConstructors[] = demoCls.getDeclaredConstructors();
System.out.println("getDeclaredConstructors()方法获取的方法数:"+declaredConstructors.length);
System.out.println(demoCls.getSimpleName()+"的方法有如下几个");
for (int i=0;i<declaredConstructors.length;i++){
Constructor constructor = declaredConstructors[i];
Class[] paraTypes = constructor.getParameterTypes();
System.out.print(constructor.getName()+"(");
for (int j = 0; j < paraTypes.length; j++) {
Class paraType = paraTypes[j];
if (j==(paraTypes.length-1)){
System.out.print(""+paraType.getSimpleName()+")");
break;
}
System.out.print(""+paraType.getSimpleName()+",");
}
System.out.println();
}
Constructor constructor = demoCls.getDeclaredConstructor(String.class,int.class);
Demo1 demo1 = (Demo1) constructor.newInstance("wxt",123456);
}
}
//代码效果:getConstructors方法获取的方法数:1
//getDeclaredConstructors()方法获取的方法数:3
//Demo1的方法有如下几个
//reflexDemo.Demo1(String)
//reflexDemo.Demo1(String,int)
//reflexDemo.Demo1(String,String)
//反射调用有2个参构造方法string int
2.2 获取方法和成员变量并使用
注意:获取任何信息的时候,类中的API都有两种选择,分别是带有Declared与不带此关键字的方法,区别在于带有的可以获取所有的变量或者方法。对私有的变量赋值需先调用setAccessible(true)设置访问权限,对公有变量不需要此操作。
代码如下:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
class Demo1{
public String para1;
public int para2;
private int privatePara1;
private String privatePara2;
Demo1(String para){
System.out.println("反射调用有1个参构造方法 string");
}
public Demo1(int privatePara1, String privatePara2) {
this.privatePara1 = privatePara1;
this.privatePara2 = privatePara2;
}
@Override
public String toString() {
return "para1:"+para1 +",para2:"+para2+
",privatePara1:"+privatePara1+",privatePara2:"+privatePara2;
}
}
public class Main {
public static void main(String []args) throws Exception {
Class<?> demoCls = Class.forName("reflexDemo.Demo1");
//getConstructors()方法只能获取反射类的公共构造函数(public)
Constructor constructors[] =demoCls.getConstructors();
System.out.println("getConstructors方法获取的方法数:"+constructors.length);
//getDeclaredConstructors()方法获取所有的构造函数
Constructor declaredConstructors[] = demoCls.getDeclaredConstructors();
System.out.println("getDeclaredConstructors()方法获取的方法数:"+declaredConstructors.length);
System.out.println(demoCls.getSimpleName()+"的方法有如下几个");
for (int i=0;i<declaredConstructors.length;i++){
Constructor constructor = declaredConstructors[i];
Class[] paraTypes = constructor.getParameterTypes();
System.out.print(constructor.getName()+"(");
for (int j = 0; j < paraTypes.length; j++) {
Class paraType = paraTypes[j];
if (j==(paraTypes.length-1)){
System.out.print(""+paraType.getSimpleName()+")");
break;
}
System.out.print(""+paraType.getSimpleName()+",");
}
System.out.println();
}
//getFields()方法获取所有的公共变量(public);
Field fields[] = demoCls.getFields();
System.out.println(demoCls.getSimpleName()+"类有"+fields.length+"公共变量");
//getDeclaredFields()获取所有的变量
Field declaredFields[] = demoCls.getDeclaredFields();
System.out.println(demoCls.getSimpleName()+"类有"+declaredFields.length+"个变量");
for (int i = 0; i <declaredFields.length ; i++) {
Field field = declaredFields[i];
System.out.println(Modifier.toString(field.getModifiers())+
" "+ field.getType().getSimpleName() +" "+field.getName());
}
Constructor constructor = demoCls.getDeclaredConstructor(int.class,String.class);
Demo1 demo1 = (Demo1) constructor.newInstance(123,"wxt");
System.out.println("反射前得到的实例对象是:"+demo1.toString());
Field publicField = demoCls.getDeclaredField("para1");
publicField.set(demo1,"liming");
System.out.println("反射后,对公有变量赋值后得到的实例对象是:"+demo1.toString());
Field privateFiled = demoCls.getDeclaredField("privatePara1");
privateFiled.setAccessible(true);
privateFiled.set(demo1,1);
System.out.println("反射后,对私有变量赋值后得到的实例对象是:"+demo1.toString());
}
}
代码效果:
3. 反射机制的应用举例
注意:只写了一个用例,后续还会补充。感谢!
3.1. 在泛型为int的arryaList集合中存放一个String类型的对象(原理:合中的泛型只在编译器有效,而到了运行期,泛型则会失效)
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class reflexExample {
public static void main(String []args) throws Exception {
List<Integer> integerList = new ArrayList<>();
integerList.add(123);
integerList.add(23);
integerList.add(44);
Class listCls = integerList.getClass();
Method method = listCls.getDeclaredMethod("add", Object.class);
method.invoke(integerList,"1add");
System.out.println(integerList);
}
}
运行结果: