【问题标题】:In Java, why can we use the String class as if it were a primitive?在 Java 中,为什么我们可以使用 String 类,就好像它是一个原始类一样?
【发布时间】:2017-08-27 13:20:27
【问题描述】:

在 Java 中我们通常这样做:

Class myObject = new Class();

因为new 关键字返回一个地址。

但是为什么我们可以这样做呢?:

String myString = "Hello";

好像String 是一个原始人?

我问过我的老师,他回答说这是因为引号中的内容相当于一个地址,但他不确定。你可否确认?

“Hello”是否存储在 String 类的实例变量中?

【问题讨论】:

  • 表面上看,这是因为 Java 在这方面很混乱。将其视为该语言的例外。 Cf C++ 没有这种特殊处理扩展到“标准”对象。我很高兴你问这样的问题。投赞成票!
  • 本身不是重复的,因为建议的重复是关于 c#
  • @Ousmane 这不是 Java 问题
  • 注意:“具有文字形式”!=“是原始类型”
  • 相当于一个地址”!地址的概念在 Java 语言规范(SE 8 版)中或多或少是陌生的:我只在 final 字段的语义 下看到它(在这个意义上)。字符串文字只是 String 类型的表达式,正如 T.J.克劳德的回答。

标签: java string class


【解决方案1】:

...好像String 是一个原始人?

作为Jon points out in a comment,“具有文字形式”!=“是原始类型。” :-) 字符串在 Java 中具有文字形式,因为 the spec defines one for themString 仍然是一个对象类型。

有些语言的其他对象类型也有字面量形式(例如,JavaScript 有正则表达式、数组和非数组对象的字面量形式[它的字符串字面量形式确实定义了它所谓的字符串原语而不是字符串对象——JavaScript 有字符串的原始版本和对象版本])。我认为字符串是Java中唯一的字符串(除了null,它是“无对象”的文字),当然还有数组初始化器,它们是相似的 em> 但与文字不太一样。

【讨论】:

  • 由于自动装箱,其他文字形式也可能显示为对对象实例的评估:Boolean b = true;Number n = 42;...
  • @Holger:但是,文字会产生一个原语;拳击是分开进行的。 (你知道,但为潜伏者标记它。)
  • 现在我有了第二个想法:类文字。从 Java 1.1 开始,就有了类文字。 Class<?> cl = Long.class; 这些绝对是合格的,即使 JLS 作者忘记在 Literals section 中命名它们。他们在their own section...
  • @Holger 好一个。我不知道为什么那些对我的感觉与普通文字不同。他们确实如此,但我无法立即想到一个好的理由......
【解决方案2】:

您可以使用 literal 表达式这一事实并不意味着该表达式会产生原始类型!这只是您的误解

你看:

 Integer[] numbers = { 1, 2, 3 };

也是一个文字(嗯,“几乎”;因为你只能将它用于这种数组初始化语句);但它不是原始类型!

并在您的问题中问 为什么 部分:机会是 - 只是为了方便。在创建 Java 时,它的本意是要比当时的 C 和 C++“更好”。猜猜看:在这些语言中处理字符串非常烦人且容易出错。

从这个意义上说:引入字符串字面量可以看作是unique selling point,以将 Java 与竞争对手区分开来!

【讨论】:

    【解决方案3】:

    其他答案还不错。一些具体点:

    我问过我的老师,他回答说这是因为引号中的内容相当于一个地址,但他不确定。你能确认一下吗?

    是的。他是对的。正如其他人指出的那样,Java 语言规范可以识别字符串文字,即包含在一对 "s 中的有效 Unicode 字符序列。当 Java 编译器(javac 程序)遇到这样的文字时(例如 @987654324 @) 在您的 Java 源文件中,它字面意思将其放在已编译的class file 内的特定部分中。该部分称为运行时常量池。它然后创建一个名为 ldc 的特定指令,它将其放置在存储用于初始化的编译代码的类文件中。例如,以下 Java 源代码中的 main 方法的主体:

    public class StringAsPrimitive {
        public static void main(String[] args) {
            String s = "Hello";
        }
    }
    

    编译为:

         0: ldc           #2                  // String Hello
         2: astore_1
         3: return
    

    (这里没有魔法。只需使用javac 程序编译您的代码并使用javap 程序查看类文件。您甚至可以使用十六进制查看器查看.class 文件的内容,您将看到字符串Hello 字面意思)。

    当您要求java 程序运行这个类文件时,JVM 会解释这段代码。

    JVM 的ldc 指令记录在here 中。这就是 JVM 在解释 #2 时所做的事情,#2 是对文本字符串 "Hello" 存储在计算机内存 (RAM) 中的实际位置的引用:

    否则,如果运行时常量池条目是对 表示字符串字面量(第 5.1 节)的类 String 的实例,然后是 对该实例的引用 value 被压入操作数堆栈。

    所以,你的老师说的是对的,尽管我们不是这么说的。在 Java 中,有两种类型:primitive 和 reference。因此,将 String 文字的值说成是引用(而不是地址)会更合适。

    “Hello”是否存储在 String 类的实例变量中?

    没有。初始化为字符串字面量的字符串变量可以是任何东西,static 或类变量、实例变量或局部变量(我上面的代码)。它存储在类文件中:StringAsPrimitive.class,稍后它可以在特定内存位置供 JVM 使用。当 JVM 加载类时会发生这种情况。

    【讨论】:

      【解决方案4】:

      所有文字都不是原语。

      来自JLS 3.10

      3.10。字面量

      文字是原始值的源代码表示 类型(第 4.2 节)、字符串类型(第 4.3.3 节)或 null 类型(第 4.1 节)。

      字面意思:

      整数字面量

      FloatingPointLiteral

      布尔字面量

      字面量

      字符串字面量

      空字面量

      所以String 文字不是原语而是对象。

      JLS 引用了它,您也可以推断它,因为String 实例有方法,而基元不能有方法。

      字符串字面量 (String myString = "Hello") 很可能是由该语言引入的,以简化 String 的声明,该类型与基本类型(例如 intboolean)一样常见。 想象一下String 连接,例如:

      new String("hello ") + new String (nameInput) + new String (" and welcome!");
      

      这显然比 :

      更冗长,可读性更差,因此更容易出错
       "hello " + nameInput +" and welcome!";
      

      【讨论】:

      • 谢谢!但是字符串“Hello”是否存储在 String 类的 istance 变量中?
      • @AlessandroF,不,字符串“Hello”存储在您定义的Java源文件的.class文件内的所谓“运行时常量池”(特定位置)中变量如:String myString = "Hello".
      • 它仍然存储为 String 类的变量
      • @Walfrat,没有任何东西被存储为作为变量。变量是可以存储值的位置,但它不是唯一的位置。当您在程序中看到1"hello" 时,这些是constant 表达式——其值被编译到程序的字节码中的表达式。表达式的值1 当然是一个原始的int 值。 "hello" 的值是对在加载类文件时创建的 String 类的实例的引用。任何一个值都可以赋值给变量,也可以直接使用,不涉及任何变量。
      • @jameslarge 我知道,我不认为提出这个问题的 AlessandroF 是在寻找那个级别的细节。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      • 2021-10-25
      相关资源
      最近更新 更多