概述
前言
- Java中的反射可以帮助程序做很多是事,对于运行状态下的类能获取其所有属性和方法。
- 一个类中的公共和私有的变量和方法、构造方法等信息都能通过反射进行获取
Class类:getDeclaredField把类的所有属性反射出来(含共有、私有、静态、final修饰的)。 getDeclaredClasses把类的所有内部类对象反射出来。 getDeclaredMethod把类的所有方法反射出来。 setAccessible(true)关闭java语言访问检查,如果想要获取私有成员需要设置为true,不安全但能提升反射效率(慎用)
通过反射获取Integer类私有属性
- 可以对final属性进行赋值操作
- 这里获取Integer类对象内value属性,并对其进行赋值,最后其执行结果就是固定为我们设定的值
public 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内的缓存值给固定写死,看下面执行的结果出乎意料。
static {
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属性后对其进行某些不可描述操作,其执行结果如下
public 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);
}
--------------
执行打印结果
郑
复制代码
通过反射获取类的私有属性
- 前期类准备
/**
* @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;
}
}
复制代码
public 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)
复制代码
通过反射获取类的构造方法
public 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属性后进行重新赋值,看下面示例:
public 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获取其方法对象,最后进行调用
public 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中反射获取私有属性了,真的实用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复