【问题标题】:Java source code -- value assignments for class types [duplicate]Java源代码-类类型的值分配[重复]
【发布时间】:2013-08-02 20:28:42
【问题描述】:

我希望在 Java 源代码中看到会发生什么 当一个变量被声明并赋值时。

我无法在 java.lang.Class 中发现这一点。

特别是看看会发生什么

String s1 = "abc";
String s2 = "abc";

String 是不可变的,因此根据 "s1 == s2" 的结果,这两个引用 - s1 s2 指向 同一个对象,当

String s2 = "abc";

发出,Java 正在发现对象的位置 已创建的 "abc" 并且 s1 正在引用并分配此位置 到 s2 (?)

我希望了解在 Java 中如何在幕后进行处理。

//============================================

编辑:

这里的问题是——Java 如何在其源代码中处理这个问题。

What is the Java string pool and how is "s" different from new String("s")? 正在回答这个部分。我希望在源代码中看到这一切——如果它不是那些原生代码之一。

我知道这是一个天真的问题,但没想到会有这些反应。

【问题讨论】:

  • A String 是不可变的,与 java 用于字符串文字的内部字符串池没有任何关系
  • 如果Strings 不是不可变的,他们就不能被拘留。
  • @chrylis 是的,但仅仅因为某些东西 不可变并不意味着它已被拘留。 Java 可以在没有实习的情况下拥有一个不可变的字符串。事实上,这正是您使用 new String() 所得到的
  • 当然可以。这将是一个糟糕的想法,因为它会导致难以跟踪的错误(和安全漏洞);但完全有可能拥有“相同字符串的两个字符串常量将始终返回相同的可变 String 对象”的规则。
  • @BrianRoach 哦,当然可以,但事实上Strings 是不可变的,这使得实习成为可能......呃(@yshavit),实用。

标签: java string jvm variable-assignment


【解决方案1】:

这取决于 JVM。实现可能会有所不同。

【讨论】:

    【解决方案2】:

    一个心智模型:

    1. 在编译时,所有String literals 都写入“constants table”中类定义的字节码。特别是字符串实例将被存储到内部字符串池中(在加载期间?)。
    2. 在运行时,当要引用字符串字面量时,会通过 ldc 加载从常量表中检索它,该常量表是一个内部字符串对象。

    在你的例子中......

    String s1 = "abc";
    String s2 = "abc";
    

    可能会变成这样:

    String s1 = ldc #1
    String s2 = ldc #1
    

    地点:

    constant #1 = "abc".intern();
    

    我无法在 java.lang.Class 中发现它。

    我不确定您为什么要查看java.lang.Class,如果有的话,我会查看ClassLoader,但即使是类加载也是native。如果您想查看某种“代码”,您可以使用javap 检查已编译类的字节码。有一个old guide 在某种程度上解释了读取字节码指令。您会注意到所有对 String 字面量的引用都是 ldc 指令,用于加载常量。

    【讨论】:

      【解决方案3】:

      我希望在源代码中看到这一切——如果它不是那些原生代码之一。

      它几乎是原生的——它由 JVM 处理,它有一个用于“加载这个字符串文字”的字节码操作。

      获取此代码:

      public class StringLiterals {
        public static void main(String[] args) {
          String s = "hello, world";
        }
      }
      

      如果你编译它然后运行javap -c StringLiterals,你会得到这个:

      Compiled from "StringLiterals.java"
      public class StringLiterals extends java.lang.Object{
      public StringLiterals();
        Code:
         0:   aload_0
         1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
         4:   return
      
      public static void main(java.lang.String[]);
        Code:
         0:   ldc #2; //String hello, world
         2:   astore_1
         3:   return
      
      }
      

      第二个代码01对应String s = "hello, world";代码0 对应于字符串文字"hello, world"。它说要在.class 文件中加载const #2,并暗示它是字符串文字hello, world。如果您运行javap -c -verbose StringLiterals,您将看到.class 文件中定义的所有常量,它会确认第二个是字符串文字:

      Compiled from "StringLiterals.java"
      public class StringLiterals extends java.lang.Object
        SourceFile: "StringLiterals.java"
        minor version: 0
        major version: 50
        Constant pool:
      const #1 = Method   #4.#13; //  java/lang/Object."<init>":()V
      const #2 = String   #14;    //  hello, world
      const #3 = class    #15;    //  StringLiterals
      ...
      

      JVM 可以随意处理这个问题,但 openjdk 本身就是这样做的,因此您不会在 Java 源代码中看到任何相关代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-14
        • 2011-10-12
        • 1970-01-01
        • 1970-01-01
        • 2018-06-30
        • 1970-01-01
        • 1970-01-01
        • 2012-10-19
        相关资源
        最近更新 更多