什么是反射?
Java反射是可以让我们在运行时获取类的函数、属性、父类、接口等Class内部信息的机制。通过反射还可以让我们在运行期实例化对象,调用方法,通过调用get/set方法获取变量的值,即使方法或属性是私有的也可以通过反射形式调用,这种”看透class”的能力被称为内省,这种能力在开放框架中尤为重要。有些情况下,我们要使用的类要在运行时才会确定,这个时候我们不能再编译期间使用它,因此只能通过反射的形式使用运行时才存在的类(该类符合某种特定的规范,例如JDBC)。这是反射用的比较多的场景。
还有一个比较常用的场景就是我们编译时我们对于类的内部信息不可知,必须得到运行时 才能获取类的具体信息。比如ORM框架,在运行时才能够获取类的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。这也是反射比较经典的应用场景之一。
当我们编写完一个Java项目之后,所有的Java文件都会被编译成一个.class文件,这些Class对象承载了这个类型的父类、接口、构造函数、方法、属性等原始信息,这些class文件在程序运行时会被ClassLoader加载到虚拟机中。当一个类被加载后,Java虚拟机就会在内存中自动产生一个Class对象。我们通过new的形式创建对象实际上就是通过这些Class来创建,只是这个过程对于我们是不可见的。
反射就是把java类中的各种成分映射成一个个的Java对象。
下面的章节中我们会为大家演示反射的一些常用api,从代码的角度理解反射。
示例演示代码:
package com.liangxq.bean;
public class Student {
private String name;
private int age;
String sex;
protected int height;
public double weight;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this(name);
this.age = age;
}
private Student(int age, String name) {
// this(name);
this.name = name;
this.age = age;
}
public Student(String name) {
this.name = name;
}
public Student() {
}
public void Study(){
System.out.println(“name==”+name+”\nage==”+age);
}
}
package com.liangxq.bean;
public class Teacher {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Teacher() {
}
public Teacher(String name, String age) {
this.name = name;
this.age = age;
}
void teachEnglish(){
System.out.println("老师交英语");
}
protected void teachMathematics(){
System.out.println("老师交数学");
}
public void teachPhysical(String name){
System.out.println("老师交物理"+name);
}
private void teachChemical(int age){
System.out.println("老师交化学"+age);
}
}
2、反射Class以及构造函数
获取Class对象
在你想检查一个类的信息之前,你首先需要获取类的Class对象,Java中的所有包括所有基本类型,即使是数组都有与之关联的Class对象。如果你在编译的时候知道一个类的名字的话,那么你可以使用如下的方式获取一个类的Class对象。
Class
4、getDeclaredMethods()
package com.liangxq.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MethodDemo {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) {
try {
Class teacherClass = Class.forName("com.liangxq.bean.Teacher");
Constructor constructor = teacherClass.getConstructor();
Object object = constructor.newInstance();
// 获取所有公共方法
Method[] methods = teacherClass.getMethods();
for (Method method : methods) {
System.out.println("所有的公共的方法"+method);
}
// 获取所有的方法,包括私有的
System.out.println("===================================\n");
Method[] allMethods = teacherClass.getDeclaredMethods();
for (Method method : allMethods) {
System.out.println("所有的方法"+method);
}
// 获取指定的公有的方法
Method teachPhysical = teacherClass.getMethod("teachPhysical",
String.class);
Object object1 = teachPhysical.invoke(object, "我是物理老师");
System.out.println("object=====" + object);
System.out.println("object1=====" + object1);
// 获取指定的私有的方法
Method teachChemical = teacherClass.getDeclaredMethod(
"teachChemical", int.class);
teachChemical.setAccessible(true);// 解除私有限定
teachChemical.invoke(object, 100);//调用方法
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4、反射获取类中的属性
要获取当前类中定义的所有属性可以通过Class中的getDeclaredFileds函数,它会获取到当前类中的public、default、protected、private的所有属性。而getDeclaredFiled则是获取某个指定的属性。
//返回一个包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段。
1、Field[] getFields()
//返回一个包含某些Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段。
2、Field getField(String fieldName)
//返回一个Field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段。
3、Field getDeclaredField(String fieldName)
//返回Field对象的一个数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段。
4、Field getDeclaredFields()
package com.liangxq.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
*
*
*
*
*/
public class FieldTest {
public static void main(String[] args) {
try {
Class studentClass = Class.forName("com.liangxq.bean.Student");
//返回所有public修饰的成员变量的集合
Field []fields=studentClass.getFields();
for (Field field : fields) {
System.out.println("公共"+field);
}
System.out.println("\n\n\n");
//返回所有成员变量(private、默认、protected、public)
Field[] allFields = studentClass.getDeclaredFields();
for (Field field : allFields) {
System.out.println("所有"+field);
}
/*==========================================================*/
Constructor constructor=studentClass.getConstructor();
Object object=constructor.newInstance();
//获取public成员变量
Field field=studentClass.getField("weight");
System.out.println(field);
field.set(object, 200);
System.out.println("\n"+field.get(object));
//获取private成员变量
Field fieldName=studentClass.getDeclaredField("name");
fieldName.setAccessible(true);//忽略私有属性的修饰符
fieldName.set(object, "liangxq");
System.out.println("\n"+fieldName.get(object));
//获取protected成员变量
Field fieldheight=studentClass.getDeclaredField("height");
fieldheight.setAccessible(true);//忽略私有属性的修饰符
fieldheight.set(object, 198);//设置属性值
System.out.println("\n"+fieldheight.get(object));//获取该对象的属性值
//获取默认成员变量
Field fieldsex=studentClass.getDeclaredField("sex");
fieldsex.setAccessible(true);//忽略私有属性的修饰符
fieldsex.set(object, "男");
System.out.println("\n"+fieldsex.get(object));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5、获取父类与接口
//返回表示此Class所表示的实体(类、接口、基本类型或void)的超类的Class
Class