最近几天在看这方面的资料,现在整理一下。
一、反射机制的目的
对于一些在编译过程中无法访问.class文件的类来说,要想在运行时获取其类型以及相关的方法信息时,就需要使用JAVA中的反射的特点。
Java反射机制的目的其实就是获取某个类的函数方法并进行调用。我们想一下要想调用这个类的方法你就得知道这个类的类型、并初
始化一个对象出来、然后获取相关的成员方法并进行调用。
这个调用方法的过程其实就是反射机制的研究内容。
二、反射机制提供的功能
在进行整理相关内容之前我们先创建一个待反射的类
class Person{
private String name;
private int age;
public Person(){
age = 1;
System.out.println("Constructor is invoking");
}
public Person(int age){
this.age = age;
// System.out.println("Constructor is invoking with " + age);
}
public Person(int age, String name){
this.age = age;
this.name = name;
// System.out.println("Constructor is invoking with " + name);
}
private Person(String name){
this.name = name;
// System.out.println("Constructor is invoking with" + name);
}
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;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return " this is a person called " + name+ " with age " + age;
}
}
2.1获取类的类型
每一个类都有一个class对象,在程序运行时由JVM调用加载器时创建的,基于反射机制的操作都是在获取到class类类型的基础进行的。
所以说获取class对象是很重要的内容,目前获取class类型有三种方式:
1)CLassName.class
这种方式获取的类类型,但是不进行类的初始化工作
Class c1 = Boolean.class
System.out.println(c1);
//输出结果
class java.lang.Boolean
2)CLassName.forName("包名+类名")
这种方法装载类,并进行初始化。常见的应用就是你获取到一个变量,这个变量记载了某个内的包之类的信息,就可以使用这种方法
获取类类型
Class c2 = Class.forName("java.lang.Boolean");
System.out.println(c2);
//输出结果
class java.lang.Boolean
3)getclass方法
这种方法是返回运行时的对象,所以说这算是动态的,而其他两个方法算是静态的。即,使用前面两种方法获取到的只是初始
默认值,而采用getclass方法获取到的确实当前的最新值。
Boolean v = true ;
Class c3 = v.getClass();
System.out.println(c3);
//输出结果
class java.lang.Boolean
2.2对象初始化
在获取到类的类型之后就需要初始化一个对象了,初始化分为不带参数构造函数初始化和带参数的构造函数初始化
2.2.1 默认构造函数初始化
Class cls1 = Person.class;
Object p1 = cls1.newInstance();
System.out.println(p1);
//输出为
Constructor is invoking
this is a person called null with age 1
2.2.2 带参数构造函数初始化
在使用newInstance()时,被调用的是默认的构造函数即无参数的构造函数,要想调用含有参数的构造函数就需要获取构造函数和
调用构造函数两个步骤
步骤一:获取构造函数
public Constructor <?>[] getConstructors() | 返回所有的Public构造器 |
public Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回指定的public构造器,参数格式如new Class[]{ int.class} |
public Class<T> getDeclaringClass() | 返回所有的构造器,包含私有的 |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
| 返回指定的构造器 |
1)
getConstructors()返回所有的public构造函数
Constructor con1[] = cls1.getConstructors();
for (Constructor c:con1) {
System.out.println(c);
}
//输出为
public com.Blog.java.Person(int)
public com.Blog.java.Person(int,java.lang.String)
public com.Blog.java.Person()
2)getConstructor(Class<?>... parameterTypes) 返回public中指定的
Constructor con2 = cls1.getConstructor(new Class[]{int.class,String.class});
System.out.println(con2);
Constructor con21 = cls1.getConstructor(new Class[]{int.class});
System.out.println(con21);
//输出为
public com.Blog.java.Person(int,java.lang.String)
public com.Blog.java.Person(int)
3)
getDeclaringClass()返回所有的构造器,包含私有的
Constructor con3[] = cls1.getDeclaredConstructors();
for (Constructor c:con3) {
System.out.println(c);
}
//输出
public com.Blog.java.Person(int)
public com.Blog.java.Person(int,java.lang.String)
private com.Blog.java.Person(java.lang.String)
public com.Blog.java.Person()
4)getDeclaredConstructor()返回指定的构造器
Constructor con4 = cls1.getDeclaredConstructor(new Class[]{String.class});
System.out.println(con4);
//输出
private com.Blog.java.Person(java.lang.String)
步骤二:调用构造函数初始化
在获取到相应的带有参数的构造函数之后,要做的工作的就是初始化对象。对象的初始化是调用含有参数的newiIstance函数
con4.setAccessible(true);
Object o4 = con4.newInstance(new Object[]{"Times_4"});
System.out.println(o4);
//输出为
this is a person called Times_4 with age 0
2.3调用成员函数和成员变量
同上面一样,要想调用先得获取。获取成员函数或者成员变量的方法同样也是四种,根据有没有参数而定。
2.3.1调用成员变量
获取任意指定名字的成员 | |
public Field[] getDeclaredFields()
| 获取所有的成员变量 |
获取任意public成员变量 | |
public Field[] getFields()
| 获取所有的public成员变量 |
在获取到成员变量之后就可以进行相关的赋值操作了
Field nameV = cls1.getDeclaredField("name");
nameV.setAccessible(true);
System. out.println(o4);
nameV.set(o4, "WJY");
System. out.println(o4);
//输出为
this is a person called Times_4 with age 0
this is a person called WJY with age 0
2.3.2调用成员函数
public Method[] getMethods()
| 获取所有的共有方法的集合 |
获取指定公有方法 参数1:方法名 参数2:参数类型集合 | |
public Method[] getDeclaredMethods()
| 获取所有的方法 |
获取任意指定方法 | |
同样在获取到成员函数之后也可以调用其方法
Method fg = cls1.getMethod("getAge", null);
Object age = fg.invoke(o4, null);
System.out.println("we invoke method get age " +age);
Method fs = cls1.getMethod("setAge", new Class[]{int.class});
fs.invoke(o4, 20);
System.out.println(o4);
//输出为
we invoke method get age 0
this is a person called WJY with age 20
三、总结
到这边差不多就是整理的内容了,其实回头看看,反射机制的使用主要就获取到class类型,然后调用一些API就是了