反射
反射,从字面意思的理解就是反过来映射,它的功能也是如此,一般我们要在程序的运行过程中获取一个类的内部信息,那么得先生成一个这个类的对象,然后再使用这个类对外提供的方法来获取,这个类对外提供了什么样方法我们就只能获得到什么信息。
在程序的过程中我们无法像直接翻看源代码一样查看到某个类的信息,但是通过反射机制,能让我们在程序运行阶段就能直接获取某个类中的所有信息,就算这个类的信息有些不对外开发,但是我们依然能获取到。
class类是一个特殊的类,Class类表示正在运行的Java应用程序中的类和接口。
一个类在被JVM加载后,会在内存中生成对应Class对象,而我们可以通过获取对应类的Class对象,来获取这个类的信息。
获取方式
Class类对象只有三种可以获取方式,因为Class中的构造方法被private修饰了,所以我们无法通过构造方法来创建Class类的对象。
1、Class.forName(“全类名”)
通过这个静态方法我们可以获取某个类的Class对象,全类名指的是这个类在什么位置。
例如:创建test包下的student类的Class对象。
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException {
Class claz = Class.forName("test.student");
}
}
2、类名.class
Class studentClass = student.class;
3、对象.getClass()
Object类是所有类的父类,在Object类中有一个方法:getClass方法,这个方法可以获取一个对应的Class对象。所以我们可以使用这个方法获取。
常用功能
Class类提供了很多的方法供我们使用,总得来说常用功能可以分为三大类:
- 访问构造方法
- 访问成员变量
- 访问成员方法
针对不同的需求可以使用不同的方法。
1、访问构造方法
访问构造方法是用Constructor类来进行的。
获取构造方法的常用方法
Constructor[] getConstructors():获取所有公共(public)构造方法。
Constructor[] getDeclaredConstructors():获取所有声明的构造方法,包括公共和非公共的。
Constructor getConstructor(Class<?>… parameterTypes):获取具有指定参数类型的公共构造方法。
Constructor getDeclaredConstructor(Class<?>… parameterTypes):获取具有指定参数类型的声明的构造方法,包括公共和非公共的。
需要注意的是,如果获取指定的构造方法,那么需要根据该构造方法来进行传参。
示例
首先创建一个student进行示例说明,该类中拥有两个属性与多个构造方法,分别使用不同的权限修饰符进行修饰。
public final class student {
public String name;
public int age;
public student(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
}
然后我们使用不同的获取方法进行获取这个类的构造方法。
package test;
import java.lang.reflect.Constructor;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class claz = Class.forName("test.student"); //获取Class对象
Constructor con = claz.getConstructor(); //获取单个的公共构造方法
Constructor[] cons = claz.getConstructors(); // 获取所有公共的构造方法
Constructor[] pcons = claz.getDeclaredConstructors(); //获取所有的构造方法
Constructor targteCon = claz.getDeclaredConstructor(String.class); // 获取指定形参的构造方法
System.out.println("单个的公共构造方法:");
System.out.println(con);
System.out.println("----------------------------------------");
System.out.println("所有公共的构造方法:");
for (Constructor constructor : cons) {
System.out.println(constructor);
}
System.out.println("----------------------------------------");
System.out.println("获取所有的构造方法");
for (Constructor pcon : pcons) {
System.out.println(pcon);
}
System.out.println("----------------------------------------");
System.out.println("获取指定的构造方法");
System.out.println(targteCon);
}
}
运行结果:
2、访问成员变量
访问成员变量是使用Field类来进行的。
获取成员变量的常用方法:
Field getField(Object obj):获取指定对象的成员变量。
Field[] getFields():获取该类的所有公共(public)成员变量。
Field[] getDeclaredFields():获取该类的所有成员变量,包括公共和非公共的。
Field getDeclaredField(String name):获取具有指定名称的成员变量,包括公共和非公共的。
FIeld类中常用方法
对获取出来的成员变量进行操作的话,需要使用Field类,以下是常用的方法,具体详见Java1.8api文档。
示例
package test;
public final class student {
private String name;
public int age;
public student(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
}
获取成员变量
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
Class claz = Class.forName("test.student"); //获取Class对象
Field age = claz.getField("age"); //获取指定变量名的公共成员变量
Field[] fields = claz.getFields(); //获取所有公共的成员变量
Field name = claz.getDeclaredField("name");//获取指定变量的成员变量(可获取被private修饰的)
Field[] pfields = claz.getDeclaredFields(); // 获取所有的成员变量
// 下列仅获取成员变量名
System.out.println("获取指定成员变量");
System.out.println(age.getName());
System.out.println("-----------------------------");
System.out.println("获取所有公共的成员变量");
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("-----------------------------");
System.out.println("获取指定的成员变量(可获取私有的)");
System.out.println(name.getName());
System.out.println("-----------------------------");
System.out.println("获取所有的成员变量");
for (Field pfield : pfields) {
System.out.println(pfield.getName());
}
System.out.println("-----------------------------");
}
}
运行结果:
3、访问成员方法
访问某个类的成员方法是使用Method对象来进行操作的。
常用的方法有下图所示,具体详见Java1.8Api文档
获取Method对象常用的方法有:
Method[] getMethods():获取所有公共(public)成员方法,包括从Object类继承的方法。
Method[] getDeclaredMethods():获取所有声明的成员方法,不包括从父类继承的方法。
Method getMethod(String name, Class<?>… parameterTypes):获取具有指定名称和参数类型的公共成员方法。
Method getDeclaredMethod(String name, Class<?>… parameterTypes):获取具有指定名称和参数类型的声明的成员方法。
示例:
给student类创建几个成员方法用于演示。
package test;
public final class student {
private String name;
public int age;
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(){}
private student(String name){
this.name=name;
}
protected student(int age){
this.age=age;
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
private void show(){
System.out.println("芜湖");
}
}
获取成员方法
需要注意的是,如果使用getMethods方法来获取成员方法,那么它会返回本类的公共成员方法,也会返回从父类继承的成员方法。而使用getDeclaredMethods方法来获取的话,那么就不会返回父类的方法。
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo_1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
Class claz=Class.forName("test.student");
Method[] ms = claz.getMethods(); //获取所有公共的成员方法(包括从父类继承的方法)
Method getAge = claz.getMethod("getAge"); // 获取指定名称与形参的公共方法,无形参则省略
Method[] pms = claz.getDeclaredMethods(); //获取所有成员方法,不包括从父类继承的方法
Method show = claz.getDeclaredMethod("show"); // 获取指定名称与形参的方法(包括私有化的)
System.out.println("取所有公共的成员方法(包括从父类继承的方法)");
for (Method m : ms) {
System.out.println(m); // 获取方法名称
}
System.out.println("------------------------------------------------");
System.out.println("获取指定名称与形参的公共方法,无形参则省略");
System.out.println(getAge);
System.out.println("------------------------------------------------");
System.out.println("获取所有的成员方法,不包括从父类继承的");
for (Method pm : pms) {
System.out.println(pm);
}
System.out.println("------------------------------------------------");
System.out.println("获取指定名称与形参的方法(包括私有化的)");
System.out.println(show);
}
}
执行结果