定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射机制的相关类
与Java反射相关的类如下:
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
示例
//实体类
public class Test {
private int num;
public String no;
protected String str;
private static String s = "this is a private static member";
public Test()
{
num = 0;
no = "The object has been created successfully";
str = "test";
}
public Test(int num, String no, String str)
{
this.num = num;
this.no = no;
this.str = str;
}
private Test(Test test)
{
this.num = test.num;
this.no = test.no;
this.str = test.str;
}
@Override
public String toString()
{
return no + " and the num is " + num;
}
public String func1(String str)
{
System.out.println("this is a public function");
return str;
}
private void func2()
{
System.out.println("this is a private function");
}
public static void main(String[] args)
{
System.out.println("This is a main function");
}
}
实体类就是一些简单public private的属性、方法以及无参和带参的构造函数
下面是反射的方法测试
我们要使用反射首先需要获得这个类的Class对象,获取方式有三种
* 1、利用Object的getClass()方法获取 * 2、通过静态class属性获取(任何的数据类型都有一个静态的class属性) * 3、通过Class类的forName()方法获取 * 注:在运行期间一个类只会有一个Class对象生成
//第一种方式
Test test = new Test();
Class testClass = test.getClass();
System.out.println(testClass.getName());
//第二种方式
Class testClass2 = Test.class;
System.out.println(testClass.equals(testClass2));
//第三种方式
try {
Class testClass3 = Class.forName("Test");
System.out.println(testClass==testClass3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
* 注:在运行期间一个类只会有一个Class对象生成,所以在第三种返回的==,结果是true
1、获取、使用构造函数
* 获取构造方法 * 1、getDeclaredConstructors()获取所有的构造方法,包括private和protected * 2、getConstructors()获取所有的public构造方法 * 3、getConstructor(null)获取无参的public构造方法 * 注:前两种方法都是返回Constructor对象数组,第三种是返回Constructor对象,因为无参构造函数只可能有一种嘛
Constructor[] constructors = testClass.getDeclaredConstructors();
//Constructor[] constructors = strClass.getConstructors();
//Constructor constructor1 = strClass.getConstructor(null);
for(Constructor constructor : constructors)
{
System.out.println(constructor);
}
* 调用构造函数 * 在这里是无法调用private方法的(会告诉你权限不够IllegalAccessException),这里我就调用无参的构造函数了 * 要想调用需要使用constructor.setAccessible(true)
Object object = constructors[2].newInstance();
System.out.println(object);
2、获取成员变量
* 1、getFields()获取所有的public变量 * 2、getDeclaredFields()获取所有的变量 * 3、getField(String name)获取指定名称的变量(只能获取public,若要获取private使用getDeclaredField(String name))
Field[] fields = testClass.getDeclaredFields();
for(Field field : fields)
{
System.out.println(field);
}
修改成员变量的值我们可以调用Field类的set方法,如我们修改public成员变量no的值
Field field = testClass.getField("no");
field.set(object,"the no has been changed");
Test test1 = (Test)object;
System.out.println(test1.no);
如果要修改private成员变量的值也需要先获取权限
Field field1 = testClass.getDeclaredField("num");
field1.setAccessible(true);
field1.set(object,1);
test1 = (Test)object;
System.out.println(test1);
3、获取、调用方法(不包括构造函数)
* 1、getMethods()获取所有的public方法 * 2、getDeclaredMethods()获取所有的方法 * 3、getMethod(String name,Class pramaType)获取指定名称的方法,同样的,要获取private要是用getDeclaredMethod
System.out.println("********************获取所有的方法***********************");
Method[] methods = testClass.getDeclaredMethods();
for(Method method : methods)
{
System.out.println(method);
}
System.out.println("********************调用public方法***********************");
Method method = testClass.getMethod("func1", String.class);
method.invoke(object,"test");
System.out.println("********************调用private方法***********************");
method = testClass.getDeclaredMethod("func2");
/**
* 同样的这里需要提权
*/
method.setAccessible(true);
method.invoke(object);
System.out.println("********************调用main方法***********************");
method = testClass.getMethod("main", String[].class);
/**
* main方法是static的,所以不需要对象也能运行,所以第一个参数可以为null
* 第二个参数也就是String数组args,但是jdk1.5之后是作为一个可变参数传进去的,所以这里要强制转为Object
*/
method.invoke(null,(Object) new String[]{});
* 解释一下可变参数 * 像add中的num就是可变参数,它的个数是不确定的,所以可变参数只能放在最后面,要不然程序也无法判断哪些是可变参数 * 特点: * (1)只能出现在参数列表的最后; * (2)...位于变量类型和变量名之间,前后有无空格都可以; * (3)调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。 * 适用场景: * 适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。
例如我写一个累加的函数
public static int add(int...num)
{
int sum = 0;
for(int i = 0; i < num.length; i++)
{
sum+=num[i];
}
return sum;
}
调用就可以这么调用
add(1,2,3);
参数列表的长度是不固定的,只要是int型的就可以