当前位置: 首页 > 知识库问答 >
问题:

为什么使用“newInstance()”方法创建字符串与使用显式类型“字符串”相比,使用“var”时的行为不同?

利博远
2023-03-14

我正在学习Java中的反射。偶然间,我发现了以下,对我来说意想不到的行为。

下面编写两个测试都成功。

    class NewInstanceUsingReflection {

        @Test
        void testClassNewInstance() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
            final var input = "A string";
            final var theClass = input.getClass();
            final var constructor = theClass.getConstructor();
            final String newString = constructor.newInstance();

            assertEquals("", newString);
        }

        @Test
        void testClassNewInstanceWithVarOnly() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
            final var input = "A string";
            final var theClass = input.getClass();
            final var constructor = theClass.getConstructor();
            final var newString = constructor.newInstance();

            assertEquals("A string", newString);
        }

    }

除了断言之外,唯一的区别是< code>newString变量类型在第一个测试中是显式的,在第二个测试中被声明为< code>var。

我使用的是 java 17 和 junit5 测试框架。

为什么newString的值在第一次测试中是空字符串,而输入字符串值在第二次测试中?

它与字符串池有关吗?

还是另有隐情?

共有1个答案

宰父疏珂
2023-03-14

Java17,同样的问题。解释很清楚:错误。

反编译它,相关部分:

        20: anewarray     #2                  // class java/lang/Object
        23: invokevirtual #35                 // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;
        26: checkcast     #41                 // class java/lang/String
        29: astore        4
        31: ldc           #23                 // String A string
        33: ldc           #23                 // String A string
        35: invokevirtual #43                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z

< code>astore 4是结果所在的位置,它不在任何位置:插槽4不再被使用。相反,同一个字符串常量被加载了两次,这实际上导致了< code >“一个字符串”。equals("A string"),当然< code>true。

var 替换为字符串,重新编译并重新运行 javap

        20: anewarray     #2                  // class java/lang/Object
        23: invokevirtual #35                 // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;
        26: checkcast     #41                 // class java/lang/String
        29: astore        4
        31: ldc           #23                 // String A string
        33: aload         4
        35: invokevirtual #43                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z

除了第二个< code>ldc是正确的< code>aload 4之外,其他方面都相同。

我很难弄清楚这里发生了什么。感觉更像是var以某种方式导致该ldc重复(与错误地认为值保证相同的分析相反,javac故意很少进行此类优化)。

我真的很难弄清楚这是如何在2 LTS版本。令人难忘的发现。

下一步是在最新的JDK (18)上验证,然后归档一个bug。我快速浏览了一下是否已经有报道,但我不确定该用什么搜索词。不过,我在搜索中没有找到任何报告。

注意:反编译跟踪是使用javap-c-v NewInstanceUsingReflection生成的。

编辑:刚刚在ecj上尝试过(适用于Java的Eclipse编译器(TM)v20210223-0522,3.25.0,版权所有IBM公司2000,2020。保留所有权利。- 错误不会发生在那里。

 类似资料:
  • 问题内容: 我知道问题的标题不是很清楚,对此感到抱歉,不知道如何提出。我有一个非常基本的Java实现问题,我想着重于应用程序性能,但是它也涉及Java中的String创建模式。 我了解Java中字符串的不变性概念。我不确定的是,我在某处读到以下内容不会创建两个不同的String对象: 我想知道Java是怎么做到的?它实际上是否在程序存储器中寻找一个String值并检查其是否存在,如果不存在则创建一

  • 使用字符串方式 有时使用 re 模块是个错误。如果你匹配一个固定的字符串或单个的字符类,并且你没有使用 re 的任何象 IGNORECASE 标志的功能,那么就没有必要使用正则表达式了。字符串有一些方法是对固定字符串进行操作的,它们通常快很多,因为它们都是一个个经过优化的 C 小循环,用以代替大的、更具通用性的正则表达式引擎。 举个 用一个固定字符串替换另一个 的例子,如:你可以把 "deed"

  • 问题内容: 我有一个Android应用程序,我想检查安装的应用程序名称是否与传递给包含此代码的函数的字符串匹配。代码和示例如下: 假设您打过电话,并且手机上的应用程序名称与返回的名称相同。但是,它永远不会。我记录了结果,它应该匹配,但事实并非如此。任何人都可以请问我为什么这行不通吗? 问题答案: 使用String的equals()方法代替==运算符来比较字符串: 在Java中,新手遇到的最常见错误

  • 看完这些讨论——问题1,问题2,文章 我对Java字符串常量池有以下理解(如果我错了,请纠正我): 编译源代码时,编译器会在我们的程序中查找所有字符串文字(放在双引号中的那些),并在堆区域中创建不同的(无重复)对象,并在称为字符串常量池(方法区域内的区域)的特殊内存区域中维护它们的引用。任何其他字符串对象都是在运行时创建的。 假设我们的代码有以下语句: 当编译上述代码时, 第1行:在堆中创建一个S

  • 问题内容: 想知道有没有比如下计算给定字符串的字符数更简单的方法? 问题答案: 具有完全的Unicode支持(Java 11+)1的最简单的方法来计算字符串中每个字符的出现次数: 1)答案的结尾是具有完整Unicode支持的Java 8版本。 输出量 更新: 对于Java 8+(不支持补充平面中的字符,例如emoji): 更新2: 同样适用于Java 8+。 我误会了,以为它是在Java 9之前才

  • 本文向大家介绍VBA 使用格式将数字类型转换为字符串并将其格式化为字符串,包括了VBA 使用格式将数字类型转换为字符串并将其格式化为字符串的使用技巧和注意事项,需要的朋友参考一下 示例