当前位置: 首页 > 面试题库 >

带有反射和字符串的Java拼图

子车鸿才
2023-03-14
问题内容

此源输出G'Day Mate.这是怎么回事?

public static void main(String args[]) {
    System.out.println("Hello World");
}

static {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        value.set("Hello World", value.get("G'Day Mate."));
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

如果我们将主要功能更改"Hello World"new String("Hello World")

System.out.println(new String("Hello World"));

它输出Hello world

实际发生了什么?


问题答案:

此源代码打开了一些有趣的Java技术。让我们一一检查。

首先,我们需要了解代码流程。代码的哪一部分将首先执行

静态初始化块。为什么?让我们参考Java语言规范(12.4):

类的初始化包括执行其静态初始化程序和在该类中声明的静态字段(类变量)的初始化程序。

什么时候发生?再次来自JLS(12.4.1):

T是一个类,并调用T声明的静态方法。

因此我们可以得出这样的结论:静态初始化器将首先执行main方法。

现在,这两行正在使用反射:

Field value = String.class.getDeclaredField("value");
value.setAccessible(true);

为了简单起见,我们可以将拳头分为两行:

Class<String> c = String.class;
Field value = c.getDeclaredField("value");

第一行检索Reflected Class
Object
,第二行检索a
Field,它代表类的value字段String

value.setAccessible(true)指示反射的类对象在使用时应禁止Java语言访问检查。(参考)

正在讨论的下一行是

value.set("Hello World", value.get("G'Day Mate."));

如果我们深入研究.set()文档,我们可以看到我们正在调用的set(Object aObject,Object value)版本setvalue.get("G'Day Mate.")返回"G'Day Mate."value字段值实际上是char[]。并通过调用set将该"Hello World"对象的value字段的值替换为"G'Day Mate."object的value字段。

static解释了该块的代码。

让我们潜入主要功能。很简单 它应该输出Hello, world。但它正在输出G'Day Mate。为什么?因为Hello, world我们在static初始化程序中创建的String对象与Hello, world我们在main函数中使用的对象相同。再次与JLS协商将为您提供帮助

而且,字符串文字总是引用类String的相同实例。这是因为使用方法String.intern,对“字符串文字”(或更一般地说,是作为常量表达式的值的字符串(第15.28节))进行了“插入”,以便共享唯一的实例。

因此,由于我们已经将Hello,worldobject的值更改为,因此它显示了不同的值G'Day, Mate

但是,如果您new String("Hello world")在main函数中使用它,它将直接创建一个新实例,String而不是检入其池中。因此Hello worldmain函数将不同于Hello world我们已更改其值的静态初始值设定项。



 类似资料:
  • 这个问题不难,我已经用自己的方法解决了,但我想听听你的意见,也许有什么方法可以让这成为一个改进的选择?Java 8-11。

  • 问题内容: 我正在尝试找到这个问题的第三种解决方案。 我不明白为什么这个不打印。 当然,由于使用字符串实习,被修改的实例与?方法中使用的实例完全相同。 我想念什么? 编辑 @yshavit有趣的一点是,如果您添加该行 在之前,输出为 问题答案: 可以说这是HotSpot JVM错误。 问题在于字符串字面量的内部机制 。 在常量池解析期间,将懒惰地创建字符串文字的实例。 最初,字符串常量在常量池中由

  • 主要内容:使用连接运算符“+”,使用 concat() 方法,连接其他类型数据对于已经定义的字符串,可以对其进行各种操作。连接多个字符串是字符串操作中最简单的一种。通过字符串连接,可以将两个或多个字符串、字符、整数和浮点数等类型的数据连成一个更大的字符串。 String 字符串虽然是不可变字符串,但也可以进行拼接只是会产生一个新的对象。String 字符串拼接可以使用“+”运算符或 String 的 concat(String str) 方法。 “+”运算符优势是可以连接任

  • 问题内容: 我试图理解字符串比较与字符串比较的输出。需要明确的是,我拥有使用==和equals比较两个字符串的类。我试图将==和equals()的输出合并为字符串。equals()的输出会连续显示,但==的输出不会 连续显示。使用Java的装箱功能,将与字符串连接的布尔值联系起来。equals和==都返回布尔值。那么为什么会有这种差异呢?有人可以解释吗? 输出 更新:答案 如果不使用s1 == s

  • 本文向大家介绍Java中拆分和拼接字符串,包括了Java中拆分和拼接字符串的使用技巧和注意事项,需要的朋友参考一下 要在Java中拆分和连接字符串,请使用以下示例中的split和join方法- 示例 输出结果 一个名为Demo的类包含主函数。这里定义了一个字符串对象,并根据直到最后一个单词的值对其进行分割。循环遍历一个for循环,并根据该值分割字符串。同样,使用join函数连接字符串。相关消息显示

  • 如果你使用过python,你会发现字符串和int/float/double便捷的拼接方式;但如果你使用C++,可能你每次需要的时候搜索一下才能知道。本文提供两种简单的方式来完成这个功能。 std::to_string() 通过std::to_string()将数字类型转换成std::string类型,从而可以直接使用+完成字符串的拼接。 # include <iostream> int main