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

有没有办法创建没有初始化的原始数组?

汪明德
2023-03-14
问题内容

众所周知,Java总是在创建时初始化数组。即new int[1000000]总是返回一个所有元素=
0的数组。我知道这对于对象数组是必须的,但是对于原始数组(可能是布尔型),在大多数情况下,我们并不关心初始值。

有人知道避免这种初始化的方法吗?


问题答案:

我已经做了一些调查。没有合法的方法在Java中创建未初始化的数组。甚至JNI
NewXxxArray也会创建初始化的数组。因此,不可能确切知道数组清零的成本。尽管如此,我还是做了一些测量:

1)创建具有不同数组大小的1000字节数组

        long t0 = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
//          byte[] a1 = new byte[1];
            byte[] a1 = new byte[1000000];
        }
        System.out.println(System.currentTimeMillis() - t0);

在我的PC上,它对于字节[1]给出了<1毫秒,对于字节[1000000]给出了〜500毫秒。听起来对我印象深刻。

2)JDK中没有用于填充数组的快速(本机)方法,Arrays.fill太慢,因此让我们至少看看本机System.arraycopy可以对1000万个大小的数组进行1000次复制。

    byte[] a1 = new byte[1000000];
    byte[] a2 = new byte[1000000];
    for(int i = 0; i < 1000; i++) {
        System.arraycopy(a1, 0, a2, 0, 1000000);
    }

这是700毫秒。

这使我有理由相信a)创建长数组是昂贵的b)由于无用的初始化,它似乎是昂贵的。

3)让我们来看看sun.misc.Unsafe http://www.javasourcecode.org/html/open-
source/jdk/jdk-6u23/sun/misc/Unsafe.html
。它可以防止外部使用,但不要过多

    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe)f.get(null);

这是内存分配测试的成本

    for(int i = 0; i < 1000; i++) {
        long m = u.allocateMemory(1000000);
    }

如果您还记得的话,新字节[1000000]花费的时间少于1毫秒,花费了500毫秒。

4)不安全的方法没有直接使用数组的方法。它需要知道类字段,但是反射不显示数组中的任何字段。关于数组内部的信息不多,我想这是特定于JVM
/平台的。但是,它像其他Java对象一样是header +字段。在我的PC / JVM上,

header - 8 bytes
int length - 4 bytes
long bufferAddress - 8 bytes

现在,使用Unsafe,我将创建byte [10],分配一个10字节的内存缓冲区,并将其用作数组的元素

    byte[] a = new byte[10];
    System.out.println(Arrays.toString(a));
    long mem = unsafe.allocateMemory(10);
    unsafe.putLong(a, 12, mem);
    System.out.println(Arrays.toString(a));

它打印

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[8, 15, -114, 24, 0, 0, 0, 0, 0, 0]

您可以看到thay数组的数据未初始化。

现在,我将更改数组长度(尽管它仍然指向10个字节的内存)

    unsafe.putInt(a, 8, 1000000);
    System.out.println(a.length);

它显示了1000000。这只是为了证明这个想法可行。

现在进行性能测试。我将创建一个空字节数组a1,分配一个1000000个字节的缓冲区,将此缓冲区分配给a1并设置a1.length = 10000000

    long t0 = System.currentTimeMillis();
    for(int i = 0; i < 1000; i++) {
        byte[] a1 = new byte[0];
        long mem1 = unsafe.allocateMemory(1000000);
        unsafe.putLong(a1, 12, mem);
        unsafe.putInt(a1, 8, 1000000);
    }
    System.out.println(System.currentTimeMillis() - t0);

需要10毫秒。

5)C ++中有malloc和alloc,malloc只是分配内存块,calloc也会将其初始化为零。

cpp

...
JNIEXPORT void JNICALL Java_Test_malloc(JNIEnv *env, jobject obj, jint n) {
     malloc(n);
}

爪哇

private native static void malloc(int n);

for (int i = 0; i < 500; i++) {
    malloc(1000000);
}

结果malloc-78毫秒;Calloc-468毫秒

结论

  1. 似乎由于无用的元素归零,Java数组的创建很慢。
  2. 我们无法更改它,但是Oracle可以更改。无需更改JLS中的任何内容,只需将本地方法添加到java.lang.reflect.Array之类的

公共静态本机xxx [] newUninitialziedXxxArray(int size);

适用于所有原始数字类型(字节-双精度)和char类型。它可以在整个JDK中使用,就像在java.util.Arrays中一样

    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = Array.newUninitializedIntArray(newLength);
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        ...

或java.lang.String

   public String concat(String str) {
        ...   
        char[] buf = Array.newUninitializedCharArray(count + otherLen);
        getChars(0, count, buf, 0);
        ...


 类似资料:
  • 在我的xml文件中有七个文本视图(textview0….textview6),在我的java文件中,我想循环浏览这些视图,但我遇到了一个问题,我无法使用findViewById函数,因为我无法在我想要的类似名称中使用索引(I)

  • 问题内容: 我对Swift类有疑问。我有一个UITableViewController类和UITableViewCell类的快捷文件。我的问题是UITableViewCell类和插座。此类存在错误 类别“ HomeCell”没有初始化程序 ,并且我不理解此问题。 感谢您的回复。 问题答案: 您必须使用隐式展开的可选变量,以便Swift可以在初始化阶段处理循环依赖关系(在这种情况下,UI组件的父级<

  • 问题内容: 我有一个看起来像这样的错误: 无法初始化代理-没有会话 我正在使用java,hibernate和spring。尝试生成PDF文档时会出现此错误,我正在按照以下步骤即时生成它并存储在数据库中。 我通过POST方法向应用发送了请求。这将即时生成PDF并显示给用户。 在该请求之后,我发送了另一个请求,但是通过ajax发送了一个请求。这将生成相同的PDF,但会将其保存在数据库中。 该错误表明由

  • 问题内容: 当我这样做时,从编译器得到投诉 但是,如果我只添加 ? 在如下所示的 AppDelegate 末尾,错误消失了。 除非我错了,否则我看不到与此错误相关的关键字。 问题答案: 该错误可以得到改善,但是第一个版本的问题是您有一个成员变量,该成员变量没有默认值。Swift中的所有变量必须始终具有一个值。这意味着您必须在没有的初始化程序中进行设置,也可以在线提供默认值。 当您将其设为可选时,默

  • 我使用的是Spring框架和hibernate,我在其中映射了@OneToMany,当我加载类别来创建新产品时,我得到一个错误:在hibernate中用映射惰性地初始化集合失败,我以前看到过一些说明,请删除FectType。懒惰和我这样做了,但仍然没有效果 类别JAVA Product.java 我在用JPA 这是控制器的代码 product-form.jsp 但我得到错误 "我不知道哪里错了,我