0%

Java反射

java反射

之前学过反射,半知半解,今天重新学习一下Java反射机制,以及能做的事情。

下面是反射获取类Test的的源码:

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
import java.io.IOException;
import java.lang.Runtime;
public class Test {
public static final int h = 5;//字段1,直接赋值
public String s = "test";//字段2
public static final boolean b =new Boolean(false);//字段3,间接赋值
public Test() { //构造函数1
System.out.println("无参构造函数");
}
public Test(int m, double n) throws IOException {//有参构造函数2
System.out.println("有参构造函数");
System.out.println("获取到int="+m);
System.out.println("获取到double="+n);
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
}
public String hello(String s) { //方法1
System.out.println("调用hello");
return "Hello World~";
}
public int hello2(int x,double y) throws IOException { //方法2
System.out.println("获取到int="+x);
System.out.println("获取到double="+y);
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
return 3;
}
}



反射创建对象实例

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
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* author: f19t
* Date: 2023/2/18 21:44
*/
public class Test_Reflect_getConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class c = Class.forName("Test");
Constructor ct1 = c.getConstructor();//不会初始化,无参构造
Test obj = (Test)ct1.newInstance();//初始化执行
obj.hello("test");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Double.TYPE;

Constructor ct2 = c.getConstructor(partypes);//不会初始化,有参构造
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Double(47.0);
Object obj2 = ct2.newInstance(arglist);//有参生成对象
}
}

反射获取类方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.Method;

/**
* author: f19t
* Date: 2023/2/18 19:12
*/
public class Test_Reflect_methods {

public static void main(String[]args) throws ClassNotFoundException {
Class c = Class.forName("java.lang.Runtime");//获取类
Method methods[] = c.getDeclaredMethods();//获取所有方法
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
Class pvec[] =m.getParameterTypes();
// System.out.println("类名=" +m.getDeclaringClass());//获取类名
System.out.println("方法="+m.getName());//获取方法名
for (int q = 0; q < pvec.length; q++) {
System.out.println("参数类型"+pvec[q].getName()); //获取方法参数
}
System.out.println("返回类型="+m.getReturnType());//获取返回类型
System.out.println("-----------------------------");
}
}
}

获取字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
* author: f19t
* Date: 2023/2/18 20:43
*/
public class Test_Reflect_field {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class c = Class.forName("Test");
Field fieldlist[] = c.getDeclaredFields();
for (int i = 0; i < fieldlist.length; i++) {
fieldlist[i].setAccessible(true);
System.out.println("字段名="+fieldlist[i].getName());
System.out.println("字段值="+fieldlist[i].get(c.newInstance()));//get方法需要传入实例对象
System.out.println("字段类型="+fieldlist[i].getType());
int mod = fieldlist[i].getModifiers();
System.out.println("声明类型="+ Modifier.toString(mod));
System.out.println("----------------------------");
}
}
}


运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
字段名=h
无参构造函数
字段值=5
字段类型=int
声明类型=public static final
----------------------------
字段名=s
无参构造函数
字段值=test
字段类型=class java.lang.String
声明类型=public
----------------------------
字段名=b
无参构造函数
字段值=false
字段类型=boolean
声明类型=public static final
----------------------------

修改字段

反射修改注意如果是static final修饰的,需要先去掉final,再次进行修改,还需要注意,static final修饰的直接赋值还是间接赋值,直接赋值只能通过反射获取修改后的数据(编译优化导致)。间接赋值的可以直接获取修改后的数据。

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
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

/**
* author: f19t
* Date: 2023/2/18 22:03
*/
public class Test_Reflect_Set_field {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
Class c = Class.forName("Test");
Field field[] = c.getDeclaredFields();
Test obj = (Test) c.newInstance();
for (int i = 0; i < field.length; i++) {
System.out.println("修改前的值"+field[i].getName()+"="+field[i].get(obj)+" 类型为 "+Modifier.toString(field[i].getModifiers()));
}
System.out.println("------------------");

field[0].setAccessible(true);
Field modifiers = field[0].getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field[0], field[0].getModifiers() & ~Modifier.FINAL);
field[0].set(obj, 10);
System.out.println("反射修改后直接获取"+field[0].getName()+"="+obj.h);
System.out.println("反射修改后反射获取"+field[0].getName()+"="+field[0].get(obj));
System.out.println("--------------------");

field[1].setAccessible(true);
modifiers.setInt(field[1], field[1].getModifiers() & ~Modifier.FINAL);
field[1].set(obj, "hack");
System.out.println("反射修改后直接获取"+field[1].getName()+"="+obj.s);
System.out.println("反射修改后反射获取"+field[1].getName()+"="+field[1].get(obj));
System.out.println("--------------------");

field[2].setAccessible(true);
modifiers.setInt(field[2], field[2].getModifiers() & ~Modifier.FINAL);
field[2].set(obj, true);
System.out.println("反射修改后直接获取"+field[2].getName()+"="+obj.b);
System.out.println("反射修改后反射获取"+field[2].getName()+"="+field[2].get(obj));
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
无参构造函数
修改前的值h=5 类型为 public static final
修改前的值s=test 类型为 public
修改前的值b=false 类型为 public static final
------------------
反射修改后直接获取h=5
反射修改后反射获取h=10
--------------------
反射修改后直接获取s=hack
反射修改后反射获取s=hack
--------------------
反射修改后直接获取b=true
反射修改后反射获取b=true

调用方法

常规类调用方法

常规类调用方法流程为获取类、创建实例、执行方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* author: f19t
* Date: 2023/2/18 21:22
*/
public class Test_Reflect_Get_methods {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class c = Class.forName("Test");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Double.TYPE;
Method meth = c.getMethod("hello2", partypes);
Test test = new Test();
Object arglist[] = new Object[2];
arglist[0] = new Integer(3);
arglist[1] = new Double(3.1);
Object ref = meth.invoke(test, arglist);
System.out.println(ref);
}
}

单例类调用方法

单例模式的特点
  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。
  • 单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。

java.lang.Runtime就是一个单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Runtime {
private static Runtime currentRuntime = new Runtime();

/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}

/** Don't let anyone else instantiate this class */
private Runtime() {}
Runtime的Runtime.exec调用

注意点,invoke作用是执行方法,第一个参数为:

  • 如果是普通方法执行invoke,第一个参数放对象的实例;
  • 如果是静态方法执行invoke,可以放null或类名;

放调用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* author: f19t
* Date: 2023/2/18 21:22
*/
public class Test_Reflect_Get_methods {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {

Class c = Class.forName("java.lang.Runtime");
Method method = c.getDeclaredMethod("exec", String.class);
Method method1 = c.getDeclaredMethod("getRuntime");
Object obj = method1.invoke(null);//因为getRuntime为静态方法,并且return也是Runtime
method.invoke(obj, "open /System/Applications/Calculator.app");
}
}