前言
- Java中的反射可以帮助程序做很多是事,对于运行状态下的类能获取其所有属性和方法。
- 一个类中的公共和私有的变量和方法、构造方法等信息都能通过反射进行获取
Class类:getDeclaredField把类的所有属性反射出来(含共有、私有、静态、final修饰的)。 getDeclaredClasses把类的所有内部类对象反射出来。 getDeclaredMethod把类的所有方法反射出来。 setAccessible(true)关闭java语言访问检查,如果想要获取私有成员需要设置为true,不安全但能提升反射效率(慎用)
通过反射获取Integer类私有属性
- 可以对final属性进行赋值操作
- 这里获取Integer类对象内value属性,并对其进行赋值,最后其执行结果就是固定为我们设定的值
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public static void main (String[] args) throws Exception { Class<Integer> aClass = Integer.class; Field cache = aClass.getDeclaredField("value"); cache.setAccessible(true); Integer a = 10, b = 10; cache.set(a, 16); System.out.println(a); cache.set(b, 12); System.out.println(b); } ------------------ 执行结果 16 12 复制代码
离职小技巧
- 通过静态代码块把Integer内的缓存值给固定写死,看下面执行的结果出乎意料。
复制代码
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
38static { try { final Class<?>[] declaredClasses = Integer.class.getDeclaredClasses(); Class<?> integerClass = declaredClasses[0]; Field cache = integerClass.getDeclaredField("cache"); cache.setAccessible(true); Integer[] integer = (Integer[]) cache.get(integerClass); for (int i = 0; i < integer.length; i++) { integer[i] = 3; } } catch (NoSuchFieldException | IllegalAccessException e) { } } public static void main (String[] args) throws Exception { // new Integer()相当于在堆内存中重新开辟了一个空间,并没有使用其内部的缓存对象 // 而Integer.valueof()其内部使用缓存对象 System.out.println(new Integer(2)); System.out.println(Integer.valueOf(2)); // 自动拆箱,相当于Integer.valueof() Integer a = 0; System.out.println(a); Integer c = 127; System.out.println(c); Integer d = 128; System.out.println(d); Integer e = 129; System.out.println(e); } -------------- 执行结果 2 3 3 3 128 129 复制代码
通过反射获取String私有属性
- 在JDK8内字符串是以char数组形式保存其字符内容,那通过反射获取value属性后对其进行某些不可描述操作,其执行结果如下
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13public static void main (String[] args) throws Exception { String a = "a"; Class<?> stringClass = String.class; Field field = stringClass.getDeclaredField("value"); field.setAccessible(true); char[] chars = (char[]) field.get(a); chars[0] = '郑'; System.out.println(a); } -------------- 执行打印结果 郑 复制代码
通过反射获取类的私有属性
- 前期类准备
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/** * @Author: ZRH * @Date: 2021/11/19 15:09 */ @Data public class TestModel { private Integer id; private String name; public TestModel () { } public TestModel (String name, Integer id) { this.name = name; this.id = id; } private String sendFun (String name) { return "OK - " + name; } } 复制代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public static void main (String[] args) throws Exception { TestModel model = new TestModel(); Class<?> aClass = TestModel.class; Field nameField = aClass.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(model, "zrh"); Field idField = aClass.getDeclaredField("id"); idField.setAccessible(true); idField.set(model, 10000); System.out.println(model.toString()); } --------------- 执行结果 TestModel(id=10000, name=zrh) 复制代码
通过反射获取类的构造方法
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static void main (String[] args) throws Exception { // 获取当前类对象 Class aClass = TestModel.class; // 获取当前类指定的构造方法 Constructor constructor = aClass.getConstructor(String.class, Integer.class); // 实例化构造方法,获取类实例对象 TestModel model = (TestModel) constructor.newInstance("222", 3); System.out.println(model); // 通过当前类默认无参的构造方法,获取实例对象 model = (TestModel) aClass.newInstance(); model.setId(2); model.setName("111"); System.out.println(model); } ---------------------- 执行结果 TestModel(id=3, name=222) TestModel(id=2, name=111) 复制代码
通过反射获取LinkedBlockingQueue的capacity私有属性
- 之前的一篇《线程池调优之动态参数配置》文章中描述了如果想要动态配置线程池的队列大小,需要对其进行复制重写,并把其capacity属性的setCapacity操作放开。
- 其实还可以通过反射获取capacity属性后进行重新赋值,看下面示例:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static void main (String[] args) throws Exception { final LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<>(3); for (int i = 0; i < 5; i++) { queue.offer(i); } System.out.println("before size = " + queue.size()); final Class<LinkedBlockingQueue> queueClass = LinkedBlockingQueue.class; final Field field = queueClass.getDeclaredField("capacity"); field.setAccessible(true); field.set(queue, 5); for (int i = 0; i < 8; i++) { queue.offer(i); } System.out.println("after size = " + queue.size()); } --------------- 执行结果 before size = 3 after size = 5 复制代码
- 当前队列初始化大小只有3个,然后通过反射并对其capacity重新赋值为5后,往队列重新插入元素,最后其大小为5个。
通过反射获取类的私有方法
- 先获取当前类对象,然后getDeclaredMethod获取其方法对象,最后进行调用
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public static void main (String[] args) throws Exception { // 获取类实例对象 final TestModel model = new TestModel(); // 获取实例的类对象 final Class<?> aClass1 = model.getClass(); // 获取类的方法对象 final Method sendFun = aClass1.getDeclaredMethod("sendFun", String.class); // 私有方法需要禁止java语言访问检查 sendFun.setAccessible(true); // 手动调用,可以解耦,也类似于方法增强 final Object zrh = sendFun.invoke(model, "zrh"); System.out.println(zrh); } --------------- 执行结果 OK - zrh 复制代码
说明:本文限于篇幅,故而只展示部分的文档截图,完整的 Java面试学习文档小编已经帮你整理好了,私信领取反射、Java、大厂面试学习资料哦!
最后
- 虚心学习,共同进步 -_-
链接:https://juejin.cn/post/7037424005032181773
最后
以上就是踏实小白菜最近收集整理的关于终于有人能说清楚Java中反射获取私有属性了,真的实用的全部内容,更多相关终于有人能说清楚Java中反射获取私有属性了,真内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复