文章目录
1. 前言
JAVA反射机制能够在运行状态中,对于任意一个类,都能够访问这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态访问成员以及动态调用对象方法的功能称为java语言的反射机制。
2. 非静态成员和非静态方法的访问和调用
首先先举一个类作为例子,后续操作都是对这个类进行反射的测试:
package advance.reflect;
public class NoStaticTest {
private int id;
public String name;
public float score;
public NoStaticTest() {
}
private NoStaticTest(int id, String name, float score) {
this.id = id;
this.name = name;
this.score = score;
}
public void public_fun() {
System.out.println(toString() + " called public function");
}
private void private_fun() {
System.out.println(toString() + " called private function");
}
public int public_fun_namelen(String name) {
System.out.println(toString() + " called public (int)function(String)");
return name.length();
}
private int private_fun_namelen(String name) {
System.out.println(toString() + " called private (int)function(String)");
return name.length();
}
@Override
public String toString() {
return "NoStaticTest{" +
"id=" + id +
", name='" + name + '\'' +
", score=" + score +
'}';
}
}
这个类包含的非静态成员和方法的所有情况,包括private、public(protect的在访问许可范围内参照public,访问许可范围外参照private),数据类型包括普通类型(int和float)、引用类型(String),方法包括有参数、无参数、有返回值、无返回值的所有情况,构造方法也分有参和无参。可以说总结很全面了。
接下来就是使用的例子:
1. 关于构造方法
public static void test1() {
try {
Class cls = Class.forName("advance.reflect.NoStaticTest");
NoStaticTest noStaticTest1 = (NoStaticTest) cls.newInstance();
System.out.println("cls.newInstance() : " + noStaticTest1);
Constructor[] constructors = cls.getConstructors();
System.out.println("public构造方法:");
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("所有构造方法:");
constructors = cls.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
NoStaticTest noStaticTest2 = (NoStaticTest) cls.getConstructor().newInstance();
System.out.println("constructor.newInstance() : " + noStaticTest2);
Constructor private_construct = cls.getDeclaredConstructor(int.class, String.class, float.class);
private_construct.setAccessible(true);
NoStaticTest noStaticTest3 = (NoStaticTest) private_construct.newInstance(1, "ABC", 99.99f);
System.out.println("constructor.newInstance() : " + noStaticTest3);
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
cls.newInstance() : NoStaticTest{id=0, name=‘null’, score=0.0}
public构造函数:
public advance.reflect.NoStaticTest()
所有构造函数:
public advance.reflect.NoStaticTest()
private advance.reflect.NoStaticTest(int,java.lang.String,float)
constructor.newInstance() : NoStaticTest{id=0, name=‘null’, score=0.0}
constructor.newInstance() : NoStaticTest{id=1, name=‘ABC’, score=99.99}
Class类中的方法名 | 作用描述 |
---|---|
getConstructors | 返回值是Constructor[]类型,可以获取类中所有公共构造方法,不需要参数 |
getDeclaredConstructors | 返回值是Constructor[]类型,可以获取类中所有构造方法(包括私有的),不需要参数 |
getConstructor | 返回值是Constructor类型,可以获取类中所有公共构造方法,可以需要参数,有参数时会按照参数指定的构造方法参数表进行查找 |
getDeclaredConstructor | 返回值是Constructor类型,可以获取类中所有构造方法(包括私有的),可以需要参数,有参数时会按照参数指定的构造方法参数表进行查找 |
补充 1:当无法访问时可以通过设置setAccessible(true)的方式修改权限 | |
补充 2:可以需要参数的意思是可以要也可以不要,原因是(拿getConstructor举个例子)getConstructor的参数列表用的是不定长参数 |
public Constructor getConstructor(Class<?>… parameterTypes)
2. 关于成员变量
public static void test2() {
try {
Class cls = Class.forName("advance.reflect.NoStaticTest");
NoStaticTest noStaticTest = (NoStaticTest) cls.getDeclaredConstructor().newInstance();
Field[] fields = cls.getFields();
System.out.println("public成员:");
for (Field field : fields) {
System.out.println(field.getName() + ":" + field.getType());
}
System.out.println("所有成员:");
fields = cls.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + " : " + field.getType() + " : " + field.canAccess(noStaticTest));
}
System.out.println("尝试访问所有成员:");
for (Field field : fields) {
if (!field.canAccess(noStaticTest)) {
field.setAccessible(true);
System.out.println(field.getName() + " is private, I will get access...");
}
if (field.getType().equals(int.class)) {
field.setInt(noStaticTest, 1);
} else if (field.getType().equals(String.class)) {
field.set(noStaticTest, "ABC");
} else {
field.setFloat(noStaticTest, 99.99f);
}
}
System.out.println(noStaticTest);
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
public成员:
name:class java.lang.String
score:float
所有成员:
id : int : false
name : class java.lang.String : true
score : float : true
尝试访问所有成员:
id is private, I will get access…
NoStaticTest{id=1, name=‘ABC’, score=99.99}
Class类中的方法名 | 作用描述 |
---|---|
getFields | 返回值是Field[]类型,可以获取类中所有公共成员(包括继承的) |
getDeclaredFields | 返回值是Field[]类型,可以获取类中所有在这个类中声明或者覆盖的成员(包括私有的) |
补充 1:当无法访问时可以通过设置setAccessible(true)的方式修改权限 | |
补充 2:可以发现两个方法都不能访问到父类的私有成员,那么父类的私有成员能不能访问呢?答案肯定是:能。 |
关于父类的私有成员和私有方法
这个地方把父类的私有方法也一起说了,因为方法非常类似。
使用getSuperclass这个方法可以获得父类的Class对象,由于Java是单继承,所以不存在多个父类的情况。
补充 3:那么该怎么访问实现接口的方法呢?
关于实现接口的方法
getInterfaces方法可以获取所有的实现接口的Class对象并以数组返回,然后后续操作就不用细说了。
关于访问非静态成员
细心的人会发现,当我使用getType方法的时候