Java Relfect

相关文章:
Java Relfect
Java RelfectUtils
反射一:基本类周边信息获取
反射二:泛型相关周边信息获取
反射三:类内部信息获取

一、使用反射机制步骤如下


使用反射机制步骤如下

  1. 导入 java.lang.relfect 包
  2. 获得你想操作的类的 java.lang.Class 对象
  3. 调用诸如 getDeclaredMethods 的方法
  4. 使用反射API 来操作这些信息

获取class对象的3种方法

  1. 已经得到一个类的实例,可以使用如下方式来得到Class对象:
    Class c = 对象名.getClass();

  2. 如果在编译期知道类的名字,可以使用如下方法:
    Class c = java.lang.String.class;
    Class c = Integer.TYPE;

  3. 如果类名在编译期不知道, 但是在运行期可以获得, 可以使用下面的方法:
    Class c = Class.forName(str); // 注意:str是类的全路径

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class TestClass {
static {
System.out.println("static");
}
private String name = "先小涛";
private String address = "南京";
public void print() {
System.out.println("name:" + name + " ,address:" + address);
}
}
// 测试代码
private void test() throws Exception {
TestClass testObj = new TestClass();
// 同过反射机制得到类的对象
Class <? extends TestClass> clazzClass = testObj.getClass();
System.out.println("clazzClass:" + clazzClass);
// 调用无参构造方法,创建一个对象
TestClass testObj2 = (TestClass) clazzClass.newInstance();
System.out.println("gctObj==gctOb2 :" + (testObj == testObj2));
System.out.println("gctObj.getClass() == gctOb2.getClass() :" +
(testObj.getClass() == testObj2.getClass()));
testObj2.print();
}

这样获得 Class 类对象的方法,其实是利用反射 API 把指定字符串的类加载到内存中,所以也叫类加载器加载方法。这样的话,它会把该类的静态方法和静态属性,以及静态代码全部加载到内存中。但这时候,对象还没有产生。所以为什么静态方法不能访问非静态属性和方法。因为静态方法和属性产生的时机在非静态属性和方法之前。

在进行 testObj.getClass() 的时候,实际上是对指定类进行类加载,这时候,会把静态属性、方法以及静态代码块都加载到内存中。所以这时候会打印出”静态代码块运行”。但这时候,对象却还没有产生。所以”构造方法运行”这几个字不会打印。当执行 clazzClass.newInstance() 的时候,就是利用反射机制将 Class 对象生成一个该类的一个实例。这时候对象就产生了。所以打印”构造方法运行”。当执行到 TestClass testObj = new TestClass(); 语句时,又生成了一个对象。但这时候类已经加载完毕,静态的东西已经加载到内存中,而静态代码块只执行一次,所以不用再去加载类,所以只会打印”构造方法运行”,而”静态代码块运行”不会打印。

反射机制不但可以例出该类对象所拥有的方法和属性,还可以获得该类的构造方法及通过构造方法获得实例。也可以动态的调用这个实例的成员方法。

二、获得其他类中的全部构造函数


Java 通过反射机制获取获得其他类中的全部构造函数,步骤所用方法如下:

  1. forName():返回给定串名相应的Class对象。
  2. getConstructors():返回当前Class对象表示的类的所有公有构造子对象数组。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Class<?> testClazz = null;
try {
testClazz = Class.forName("java.lang.String");
} catch (Exception e) {
e.printStackTrace();
}
Constructor<?> cons[] = testClazz.getConstructors();
for (int i = 0; i < cons.length; i++) {
int mo = cons[i].getModifiers();
StringBuilder sb = new StringBuilder();
// 构造函数修饰符
sb.append(Modifier.toString(mo)).append(" ");
// 构造函数名
sb.append(cons[i].getName()).append("(");
// 构造函数参数
Class<?> p[] = cons[i].getParameterTypes();
for (int j = 0; j < p.length; ++j) {
sb.append(p[j].getName()).append(" arg").append(j);
if (j < p.length - 1) {
sb.append(",");
}
}
sb.append("){}");
print(sb.toString());
}

三、实例化一个类的对象


Java 通过反射机制实例化一个类的对象,步骤所用方法如下:

  1. forName() 返回给定串名相应的Class对象。
  2. newInstance() 创建类的新实例。
  3. getConstructors() 返回当前Class对象表示的类的所有公有构造子对象数组。
  4. getName() 返回Class对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
}
public User(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
// 测试代码
private void test() throws Exception {
Class<?> class1 = Class.forName("com.xxt.xtest.User");
// 第一种方法,实例化默认构造方法,调用set赋值
User user = (User) class1.newInstance();
user.setAge(20);
user.setName("先小涛");
print(user);
// 结果 User [age=20, name=先小涛]
// 第二种方法 取得全部的构造函数 使用构造函数赋值
Constructor<?> cons[] = class1.getConstructors();
// 查看每个构造方法需要的参数
for (int i = 0; i < cons.length; i++) {
Class<?> clazzs[] = cons[i].getParameterTypes();
print("cons[" + i + "] (");
for (int j = 0; j < clazzs.length; j++) {
if (j == clazzs.length - 1)
print(clazzs[j].getName());
else
print(clazzs[j].getName() + ",");
}
print(")");
}
// 结果
// cons[0] ()
// cons[1] (int,java.lang.String)
// cons[2] (java.lang.String)
user = (User) cons[2].newInstance("先小涛");
print(user);
// 结果 User [age=0, name=先小涛]
user = (User) cons[1].newInstance(20, "先小涛");
print(user);
// 结果 User [age=20, name=先小涛]
}

四、获取某个类的全部属性


Java反射获取某个类的全部属性,步骤所用方法如下:

  1. forName():返回给定串名相应的 Class 对象。
  2. getDeclaredFields():返回当前 Class 对象表示的类或接口的所有已说明的域对象数组。
  3. getFields():返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组。
  4. getModifiers():返回该类或接口的 Java 语言修改器代码。
  5. getName():返回 Class 对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void test() throws Exception {
Class<?> clazz = Class.forName("com.xxt.xtest.User");
System.out.println("===============本类属性===============");
// 取得本类的全部属性
Field[] field = clazz.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();
String prev = Modifier.toString(mo);
// 属性类型
Class<?> type = field[i].getType();
System.out.println(prev + " " + type.getName() + " " + field[i].getName() + ";");
}
System.out.println("==========实现的接口或者父类的属性==========");
// 取得实现的接口或者父类的属性
Field[] filed1 = clazz.getFields();
for (int j = 0; j < filed1.length; j++) {
// 权限修饰符
int mo = filed1[j].getModifiers();
String prev = Modifier.toString(mo);
// 属性类型
Class<?> type = filed1[j].getType();
System.out.println(prev + " " + type.getName() + " " + filed1[j].getName() + ";");
}
}

输出结果:

五、操作某个类的属性


Java 通过反射机制操作某个类的属性,步骤所用方法如下:

  1. forName():返回给定串名相应的Class对象。
  2. getDeclaredField():返回当前 Class 对象表示的类或接口的指定已说明的一个域对象。

示例:

1
2
3
4
5
6
7
8
9
10
private void test() throws Exception {
Class<?> clazz = Class.forName("com.xxt.xtest.User");
Object obj = clazz.newInstance();
// 可以直接对 private 的属性赋值
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "Java 反射机制");
print(field.get(obj));
// 输出结果:Java 反射机制
}

六、获取某个类的全部方法


Java 通过反射机制获取某个类的全部方法,步骤所用方法如下:

  1. forName():返回给定串名相应的Class对象。
  2. getMethods():返回当前Class对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承的方法。
  3. getModifiers():返回该类或接口的Java语言修改器代码。
  4. getName():返回Class对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void test() throws Exception {
Class<?> clazz = Class.forName("com.xxt.xtest.User");
Method methods[] = clazz.getMethods();
StringBuilder sb = new StringBuilder();
for (Method method : methods) {
Class<?> returnType = method.getReturnType();
Class<?> paras[] = method.getParameterTypes();
int temp = method.getModifiers();
sb.append(Modifier.toString(temp)).append(" ");
sb.append(returnType.getName()).append(" ");
sb.append(method.getName()).append(" ").append("(");
for (int i = 0; i < paras.length; ++i) {
sb.append(paras[i].getName()).append(" arg").append(i);
if (i < paras.length - 1) sb.append(", ");
}
Class<?> exceptions[] = method.getExceptionTypes();
if (exceptions.length > 0) {
sb.append(") throws ");
for (int j = 0; j < exceptions.length; ++j) {
sb.append(exceptions[j].getName()).append(" ");
if (j < exceptions.length - 1) {
sb.append(", ");
}
}
} else {
sb.append(")");
}
sb.append("\n");
}
print(sb);
}

七、调用某个类的方法


Java通过反射机制调用某个类的方法,步骤所用方法如下:

  1. forName():返回给定串名相应的 Class 对象。
  2. getMethod():返回当前 Class 对象表示的类或接口的指定的公有成员方法对象。
  3. newInstance():创建类的新实例。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.xxt.xtest.TestReflect");
// 调用 TestReflect 类中的 reflect1 方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用 TestReflect 的 reflect2 方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// Java 反射机制 - 调用某个类的方法2.
// age -> 20. name -> 张三
}
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
}

八、取得并修改数组的大小等信息


Java 通过反射机制取得并修改数组的大小等信息,步骤所用方法如下:

  1. getClass():取得该类已经被实例化了的对象的该类的引用。
  2. getComponentType():如果当前类表示一个数组,则返回表示该数组组件的Class对象,否则返回null。
  3. newInstance():创建类的新实例。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class TestReflect {
public static void main(String[] args) throws Exception {
int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] newTemp = (int[]) arrayInc(temp, 15);
print(newTemp);
String[] atr = { "a", "b", "c" };
String[] str1 = (String[]) arrayInc(atr, 8);
print(str1);
}
// 修改数组大小
public static Object arrayInc(Object obj, int len) {
Class<?> arr = obj.getClass().getComponentType();
Object newArr = Array.newInstance(arr, len);
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArr, 0, co);
return newArr;
}
// 打印
public static void print(Object obj) {
Class<?> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("数组长度为: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
System.out.println();
}
}

参考链接:反射技术