【问题标题】:What does the `new` keyword do`new` 关键字有什么作用
【发布时间】:2016-11-14 22:30:36
【问题描述】:

我正在在线关注 Java 教程,尝试学习该语言,它在使用数组的两种语义之间来回切换。

long results[] = new long[3];
results[0] = 1;
results[1] = 2;
results[2] = 3;

和:

long results[] = {1, 2, 3};

本教程从未真正提到为什么它在两者之间来回切换,所以我搜索了一些关于该主题的内容。我目前的理解是 new 运算符正在创建一个“长数组”类型的对象。我理解的是我为什么要这样做,这样做的后果是什么?

  • 是否有某些特定于“数组”的方法在数组上不起作用,除非它是“数组对象”?
  • 有什么是我不能用“数组对象”做的,而我可以用普通数组做的吗?
  • Java VM 是否必须清理使用 new 运算符初始化的对象,而通常不需要这样做?

我来自 C,所以我的 Java 术语在这里可能不正确,所以如果有什么不明白的地方,请要求澄清。

【问题讨论】:

  • long[] results = {1, 2, 3} 只是 Java 中的一种特殊语法,它是 new long[] {1, 2, 3} 的缩写,它本身就是 long[] results = new long[3]; results[0] = 1; results[1] = 2; results[2] = 3; 的缩写

标签: java new-operator


【解决方案1】:

在Java中,所有的数组和对象都分配在堆上,所以从某种意义上说,所有的数组都是“数组对象”。在 Java 中,唯一在堆栈上分配的东西是对象引用和原语。其他一切都是在堆中定义和分配的对象,包括数组,无论您使用哪种语法来声明它。 (您的两个示例在最终结果中是等效的,请参阅JLS §10.3 及其链接部分,了解有关每个示例如何实际分配和分配的更多信息。)

这与 C/C++ 相反,在 C/C++ 中,您可以显式控制堆栈和堆分配。

请注意,Java 在短期对象分配/释放方面非常快。由于其基于生成的垃圾收集器,它非常高效。所以回答你的问题:

是否有某些特定于“数组”的方法不能在数组上工作,除非它是一个“数组对象”?有什么我不能用普通数组做的“数组对象”吗?

没有数组不是对象,所以没有。但是,方法不适用于原始数组。采用Object[] 的方法不会接受long[],除非先将其转换为Long[]。这是由于 Java 5 及更高版本中自动装箱的一些实现细节。

Java VM 是否必须对使用 new 运算符初始化的对象进行清理,而这通常不需要这样做?

new 分配的任何东西最终都必须被垃圾回收,所以就做任何它通常不会做的事情而言?不。但是,请注意,在 C/C++ 中,使用 malloc/new 分配数组意味着您还必须使用 free/delete [] 它,这是您不要必须在 Java 中执行,因为它会为您回收数组。

请注意,如果您的long[] 在方法中声明,并且您从不将其存储在方法之外的某个引用中,则会在方法调用结束时自动将其标记为垃圾回收。垃圾收集器将等待回收其空间,直到它需要它,但您不必自己通过delete [](或delete 和对象的析构函数)进行任何回收。

编辑:承诺的一些参考:

【讨论】:

  • 这很有趣......不知道关于对象的分配。所以我们不必因为 Java VM 的自动清理而“释放”分配给堆的对象,对吗?
  • @Mike 正确,垃圾收集器将自动释放不再引用它的任何内容。
  • @Mike 绝对正确。查看我的最新更新。您必须通过 delete 在 C++ 中自己回收空间。您不需要在 Java 中执行此操作,因为它的自动垃圾收集器使用reference graph 来确定哪些变量仍然可以通过垃圾收集器中的某个“根”访问,这些“根”将永远不会被回收(存在于“永久代”)。如果您有兴趣阅读更多有关它的信息,我会看看是否可以找到一个很好的参考。
  • @Mike 我添加了几个参考,看看。
  • +1 关于垃圾收集的优秀文章和一个很好的答案。谢谢!
【解决方案2】:

Java 中的new 关键字创建一个新对象。在这种情况下,它正在创建一个数组......这是一个对象。

这两种形式是等价的。第二个只是第一个的方便简写。它是语法糖

是否有某些特定于“数组”的方法不适用于数组,除非它是“数组对象”?

所有数组都是对象。期间。

有什么我不能用“数组对象”做的,而我可以用普通数组做的吗?

见上文。

Java VM 是否必须对使用 new 运算符初始化的对象进行清理,而这通常不需要这样做?

没有。就JVM而言,以不同方式创建的对象没有区别。

【讨论】:

  • 是的,所有数组都是 Java 中的对象这一事实使得其余问题有点悬而未决。当不使用 new 关键字时,我假设数组存在“静态”分配。
【解决方案3】:

就创建的数组的行为而言,两者是相同的。从技术上讲,所有数组都是 java 中的对象;这些只是初始化它们的两种不同方式。也可以像这样将两者结合起来:

long[] results = new long[]{1,2,3};

【讨论】:

    【解决方案4】:

    两者都是一样的。第二个选项是隐式创建数组对象,只是为了方便用户。

    【讨论】:

      【解决方案5】:

      来自JLS#Chapter 10. Arrays

      在 Java 编程语言中,数组是对象(第 4.3.1 节),是动态创建的,并且可以分配给 Object 类型的变量(第 4.3.2 节)。 Object 类的所有方法都可以在数组上调用。

      来自10.3. Array Creation

      数组由数组创建表达式(第 15.10 节)或数组初始化程序(第 10.6 节)创建

      来自15.10. Array Creation Expressions

      数组创建表达式创建一个对象,该对象是一个新数组,其元素属于PrimitiveTypeClassOrInterfaceType 指定的类型。

      来自10.6. Array Initializers

      数组初始值设定项可以在声明中指定(第 8.3 节、第 9.3 节、第 14.4 节),或作为数组创建表达式的一部分(第 15.10 节)来创建数组并提供一些初始值。

      两者都是初始化数组,不同的是第二个用一些值初始化。

      【讨论】:

      • +1 对 JLS 的良好参考。我也会确保在那里寻找答案。
      【解决方案6】:

      您展示的两种创建方式是等效的。两者都是“数组对象” - 请记住,Java 中的所有内容(除了intdouble 等基本数字类型之外)都是对象。第二个只是第一个的简写,就像 C 对堆栈分配的整数数组有类似的简写一样。

      【讨论】:

        【解决方案7】:

        以下两个代码 sn-ps 在编译级别上是相等的。 我写了一个 Demo 类,比如:

        public class NewArray {
            public static void main(String[] args) {
                long results[] = new long[3];
            }
        }
        

        public class NewArray {
            public static void main(String[] args) {
                long results[] = {0,0,0};
            }
        }
        

        'javap -c NewArray' 的输出完全相同:

        public static void main(java.lang.String[]);
          Code:
           0:   iconst_3
           1:   newarray long
           3:   astore_1
           4:   return
        
        }
        

        long results[] = new long[]{1,2,3};和长结果[] = {1,2,3};也完全一样。

        所以,虽然有时你没有使用新的关键字,但编译会认为它们是相等的。

        【讨论】:

        • +1 关于构造函数提供的默认值的优点。在 C 中,long results[3] 会有未定义的元素,很高兴在创建数组对象时知道它是 0。
        【解决方案8】:

        'new' 关键字创建一个数组。现在,根据数组的数据类型,其中的值会有所不同。如果您将数组声明为整数并使用“new”关键字,则它将包含值 0,除非您更改其中的值。对于字符串,它将包含值“null”。在每一个空间。

        【讨论】:

          【解决方案9】:

          在这两种情况下,您都创建了一个对象。

          在第一个版本中:

          long results[] = new long[3];
          results[0] = 1;
          results[1] = 2;
          results[2] = 3;
          

          您在第一行中说数组大小为 3。然后将值放入数组中。

          在第二个版本中:

          long results[] = {1, 2, 3};
          

          您创建相同的数组并在同一行中对其进行初始化。 Java 计算,您提供了 3 个参数并在没有您的帮助的情况下生成 new long[3] :)

          【讨论】:

            猜你喜欢
            • 2012-03-01
            • 1970-01-01
            • 2016-05-14
            • 2011-08-17
            • 2010-12-11
            • 2019-09-10
            相关资源
            最近更新 更多