Java反射技术
什么是反射?
Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称为反射机制。
所谓反射其实是获取类的字节码文件,也就是.class文件,那么我们可以通过Class类的对象进行获取。
其实这个知识点在Java基础学习中已经有所涉及,知识没有深入开展讲解。比如加载数据库JDBC驱动时Class.forName("com.mysql.jdbc.Driver")
关于Class类
Class类的实例表示正在运行的Java应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象(包括基本数据类型)
Class类没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
注意在运行期间,一个类只有一个Class对象产生。
下面我们通过创建一个实体类Fruit来感受一下Java的反射机制。
public class Fruit { private String name; private Double price; public Fruit() { } public Fruit(String name, Double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } @Override public String toString() { return "Fruit{" + "name='" + name + '\'' + ", price=" + price + '}'; } public String print(){ return "The price of "+name+" is "+price+" yuan."; } }
反射的三种方式
-
第一种方式:
Object——>getClass(),因为Object类中存在getClass()方法,而所有类都继承了Object类,所以可以调用Object类来获取。Fruit fruit = new Fruit(); Class fruitclass1 = fruit.getClass(); System.out.println(fruitclass1);
但是第一种方式下,对象都有了还要什么反射,所以几乎不用该方法。
-
第二种方式:
任何数据类型(包括基本数据类型)都有一个“静态”的class属性,我们可以据此获得。Class fruitclass2 = Fruit.class; System.out.println(fruitclass2);
第二种方式需要导入类的包,依赖性太强,所以该方法用得不多。
-
第三种方式:
通过Class类的静态方法forName(String className)。
Class fruitclass3 = Class.forName("Fruit"); System.out.println(fruitclass3);
反射的使用
-
获取构造方法
-
批量的方法
Constructor[] cons = fruitclass.getConstructors(); //获取所有“公有的”构造方法 Constructor[] cons2 = fruitclass.getDeclaredConstructors(); //获取所有的构造方法,包括私有、受保护、默认、公有 for(Constructor con:cons){ System.out.println(con); } System.out.println("--------------------------"); for(Constructor con2:cons2){ System.out.println(con2); }
-
单个的方法
Constructor c = fruitclass.getConstructor(String.class,Double.class); //获取单个的“公有的”构造方法 Constructor c2 = fruitclass.getDeclaredConstructor(String.class,Double.class); //获取单个的构造方法,可以是私有、受保护、默认、公有 Object obj = c.newInstance("Apple",5.5); Object obj2 = c2.newInstance("Orange",7.0); System.out.println(obj.toString()); System.out.println(obj2.toString());
newInstance是Constructor类的方法(管理构造函数的类),用来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化实例。
-
-
获取成员变量
-
批量的方法
Field[] fields = fruitclass.getFields(); //获取所有“公有的”成员变量 Field[] fields2 = fruitclass.getDeclaredFields(); //获取所有的成员变量(包括私有、受保护、默认、公有) for(Field field:fields2){ System.out.println(field); }
-
单个的方法
Field f = fruitclass.getDeclaredField("price"); f.setAccessible(true); //暴力反射,解除私有限定 f.set(obj,6.2); //修改实例obj成员变量price的值 System.out.println(((Fruit)obj).getPrice());
-
-
获取成员方法
-
批量的方法
Method[] methods = fruitclass.getMethods(); //获取所有"公有的"成员方法(包含了父类的方法也包含Object类) Method[] methods2 = fruitclass.getDeclaredMethods(); //获取所有的成员方法,包含私有的(不包括继承的) for (Method m : methods){ System.out.println(m); } System.out.println("--------------------------"); for (Method m : methods2){ System.out.println(m); }
-
单个的方法
Method m = fruitclass.getMethod("print",null); //获取单个“公有的”成员方法 Method m2 = fruitclass.getDeclaredMethod("setPrice", Double.class); //获取某个成员方法,可以是私有、受保护、默认、公有 m.invoke(obj,null); m2.invoke(obj2,7.5); System.out.println(((Fruit)obj).print()); System.out.println(((Fruit)obj2).print());
invoke是Method类的一个方法,第一个参数是要调用方法的对象,后面参数是调用方法时所传递的实参
-