如以下代码所示,在注释处可以添加N行代码,但必须保证s引用的指向不变,最终输出结果为abcd。
package interview.day01;
/**
* @author: 邹祥发
* @date: 2022/1/19 21:31
*/
public class ReflexDemo {
public static void main(String[] args) {
String s = new String("abc");
//在这中间可以添加N行代码,但必须保证s引用的指向不变,最终将输出变成abcd
System.out.println(s);
}
}
也许你第一时间想到的就是利用StringBuilder中的append()方法,但是显然是不行的。
public class ReflexDemo {
public static void main(String[] args) {
String s = new String("abc");
//在这中间可以添加N行代码,但必须保证s引用的指向不变,最终将输出变成abcd
StringBuilder builder = new StringBuilder(s);
builder.append("d");
System.out.println(s);
}
}
也许你又会想到的就是利用String类中的replace()方法,但是其实也是不行的。
public class ReflexDemo {
public static void main(String[] args) {
String s = new String("abc");
//在这中间可以添加N行代码,但必须保证s引用的指向不变,最终将输出变成abcd
s.replace("abc","abcd");
System.out.println(s);
}
}
正确的做法是通过反射的方式来修改String中的value属性,这样既能保证s引用的指向不变,也能将结果输出为abcd。
代码如下:
public class ReflexDemo {
public static void main(String[] args) throws Exception {
String s = new String("abc");
//在这中间可以添加N行代码,但必须保证s引用的指向不变,最终将输出变成abcd
Field value = s.getClass().getDeclaredField("value");
value.setAccessible(true);
value.set(s, "abcd".toCharArray());
System.out.println(s);
}
}
value.setAccessible(true);:将此对象的 accessible 标志设置为指示的布尔值。
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查;
值为 false 则指示反射的对象应该实施 Java 语言访问检查。
实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。
注:在JDK11下执行该代码会抛出IllegalArgumentException的异常。
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by interview.day01.ReflexDemo (file:/D:/users/idea-workspace/JaveSE/out/production/JaveSE/) to field java.lang.String.value
WARNING: Please consider reporting this to the maintainers of interview.day01.ReflexDemo
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Exception in thread "main" java.lang.IllegalArgumentException: Can not set final [B field java.lang.String.value to [C
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.set(UnsafeQualifiedObjectFieldAccessorImpl.java:83)
at java.base/java.lang.reflect.Field.set(Field.java:780)
at interview.day01.ReflexDemo.main(ReflexDemo.java:15)
简述:在通过反射修改String 的final字段的时候,出现该IllegalArgumentException异常。
IllegalArgumentException - 如果指定对象不是声明底层字段(或者其子类或实现者)的类或接口的实例,或者解包转换失败。
因为JVM在编译时期, 就把final类型的String进行了优化, 在编译时期就会把String处理成常量。

评论区 0