Java反射就是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言(百度百科解释)。
另外一种描述:Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。
一、3个主要的反射类:
1、Constructor:类的构造函数反射类
package reflectStudent;
import java.lang.reflect.Constructor; //导入反射包
class Student{
private String school;
private String name;
public Student(String school) { //第一个构造方法
this.setSchool(school);
}
public Student(String school,String name) { //第二个构造方法
this.setSchool(school);
this.setName(name);
}
public void setStudent(String school) {
this.school=school;
}
public void setName(String name) {
this.name=name;
}
public String toString() { //覆写toString()方法
return "学校:"+this.school+" 名字:"+this.name;
}
}
public class ReflectDemo{
public static void main(String args[]) {
Class<?>c=null; //声明Class对象
try {
c=Class.forName("reflectStudent.Student"); //实例化Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace(); //处理异常
}
Constructor<?> cons[]=c.getConstructors(); //取得全部公共构造方法
for(int i=0;i<cons.length;i++) {
System.out.println(cons[i]); //循环输出
}
}
}
输入结果:
Constructor的一个主要方法是newInstance(),通过该方法可以创建一个对象类的实例,相当于new关键字。
2、Method:类方法的反射类
创建类A:
public class A {
public void foo(String name) {
System.out.println("Hello, " + name);
}
}
通过反射调用上面方法:
import java.lang.reflect.Method;
public class TestClassLoad {
public static void main(String[] args) throws Exception {
Class<?> clz = Class.forName("A");
Object o = clz.newInstance();
Method m = clz.getMethod("foo", String.class);
for (int i = 0; i < 3; i++) {
m.invoke(o, Integer.toString(i));
}
}
}
运行结果:
TestClassLoad类上不会有对类A的符号依赖——也就是说在加载并初始化TestClassLoad类时不需要关心类A的存在与否,而是等到main()方法执行到调用Class.forName()时才试图对类A做动态加载;这里用的是一个参数版的forName(),也就是使用当前方法所在类的ClassLoader来加载,并且初始化新加载的类。
其中,Method最主要的方法是invoke(Object obj,Object[] args),其中obj表示操作的目标对象;args为方法入参
3、Field:类的成员变量的反射类
Class<?> c = Class.forName("main.Main$MyClass"); //要包名+类名 Object obj = c.newInstance();
MyClass mc = (MyClass)obj;
Field[] fields = c.getDeclaredFields();//拿到数据成员
Method[] methods = c.getMethods();//拿到函数成员
for(Field f : fields){
System.out.println("该类的内部变量有:"+f.getName());
}
for(Method m : methods) {
System.out.println("该类的方法有:"+m.getName());
}
Field类最主要的方法是set(Object obj,Object value),其中obj表示操作的目标对象,通过value为目标对象的成员变量设置值。
二、得到 Class 的三种方式
1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object类型的对象,而我不知道你具体是什么类,用这种方法
Person p1 = new Person();
Class c1 = p1.getClass();
2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高,这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;
3、通过 Class 对象的 forName() 静态方法来获取,用的最多,但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName("com.ys.reflex.Person");
三、附反射类常见方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。