Java的Integer和Double对象是否存在不必要的开销?

4
我正在使用Java 1.3版本,因此它不支持泛型。我想出了一个可疑的解决方法。我想知道整数和双精度对象是否具有不必要的开销;我的意思是:整数占用的空间是否与int相同?同样的问题也适用于Double和doubles。
据我所知,对象数组包含一个32位整数数组,实际上它们存储在内存中的地址与数组无关。但是当我显式地创建一个原始数据类型的数组时,结果可能很糟糕。因为就我所知,原始数据类型的数组实际上是存储数据本身,而不是数据的指针。或者我是从C ++中做出了太多的假设?
因此,如果DataPackage中的数组实际上保存的是指针而不是原始数据类型,那么我可以继续进行。但是,如果它们保存的是原始数据类型本身,则访问数据将成为一个问题,因为double是64位的数据,但指向它的指针仍然是32位的。
/**
 *
 * 
 * @todo Comment all the code.
 * @author Davidthefat
 * @version 1.0
 */
public class DataPackage {

    private String dataType;
    private Object data;

    /**
     * 
     * @param type
     * @param numOfItems
     */
    public DataPackage(String type, int numOfItems) {
        dataType = type;
        if (type.equals("Wheels")) {
            data = new int[numOfItems * 2];
        }
        if (type.equals("Arms")) {
            data = new int[numOfItems * 1];
        }
        if (type.equals("Joysticks")) {
            data = new double[numOfItems * 2];
        }
        if (type.equals("Buttons")) {
            data = new boolean[numOfItems * 4];
        }
    }

    /**
     * 
     * @param t1
     */
    public void update(Object t1) {
        data = t1;
    }

    /**
     * 
     * @return
     */
    public Object getData() {
        return data;
    }

    /**
     * 
     * @return
     */
    public String toString() {
        return "This contains " + dataType;
    }
}

为了访问这些数据,我将对象数组转换为整数数组,然后调用intValue()函数: temp是一个int数组。 我必须确保getData返回一个DataPackage。
temp[0] = ((Integer[])input.getData("Wheels").getData())[0].intValue();

我现在无法运行这段代码,因为它是为我学校的FRC机器人设计的,而学校已经放假了。


11
如果你仍在使用Java 1.3,那么你面临的问题比原始类型包装器增加开销的问题更为严重。另外,欢迎来到SO! - Paul
5个回答

2

我很难理解您的问题,但我可以这样说:

  1. 原始类型数组如 intdouble 等只是值的数组,不是指向值的指针。
  2. Integerint 占用更多内存,因为 Integer 是一个对象,所以需要对象开销,而 int 只占用数据所需的空间。同样的情况也适用于 Double 等。

是的,我必须更好地表达我的问题。我首先将变量"data"声明为对象数组。然后,我将它们初始化为int数组。稍后,在另一个类中,我访问它们就像它们是整数一样。由于存在内存对齐问题,我应该将数据实际上作为整数数组而不是int数组。 - Davidthefat
我在这里的一个重要问题是,这个级别的内存消耗真的很重要吗?你是否有非常小的内存和大量的值,以至于每个值节省几个字节很重要? - Francis Upton IV
我只是担心我使用的变量大小不匹配。因此,如果我将数字存储为32位整数,然后作为44位整数访问它,那么我会遇到问题,因为它将读取比所需更多的数据,并导致实际数据不匹配。如果你明白我的意思。所以我只是通过使它成为包装器对象而不是基本类型来修复了这个问题。 - Davidthefat
听起来不错。Integerint 都保存相同数量的数据(32位[有符号])。只需将所有数字值设为 Long,然后您就不必担心了。 - Francis Upton IV
1
@Davidthefat - 我认为你混淆了指针和对象的概念。在 C/C++ 中,你可以在整数类型和指针之间进行交换,但是在 Java 中绝对不能做同样的事情。如果你声明了一个 Object 数组,你无论如何都不能将原始 int 存储在其中,反之亦然。你必须选择是否要使用 Integer 还是 int 进行操作。 - Perception
@Perception 有一点小挑剔:在 ANSI C/C++ 程序中,交换整数和指针也不是那么简单(据我所知,在 C99/C++11 中,唯一被指定为足够大以容纳指针的整数类型在两种实现中都是可选的);) - Voo

1

你对C++的假设太多了。如果你担心开销,这里有一篇关于它的文章

总结一下文章,一个整数比普通的int多了12字节的开销;这很可能是因为JVM会尝试对齐数据。然而,一个长整型与一个整数的大小相同,证明这是一个对齐问题。


注意:所引用的论文是2002年的。 - Andy Thomas
你确定不是12位吗?12字节等于96位。 - Davidthefat
2
@ Andy,原帖作者说他正在使用Java 1.3;我认为参考文献非常准确。 - PhilippeLM
2
如果JDK版本与对象开销有关,那么你是正确的。但实际上这完全取决于所使用的JVM。这也揭示了下一个致命缺陷:开销是实现定义的,可能随时更改或在不同的JVM之间发生变化。尽管如此,对于感兴趣的人来说:Hotspot每个对象有2个字节的开销,并在8字节边界上对齐。 - Voo

0

我只是猜测,但我想整数占用的空间应该比 int 和指针多几倍。我听说对象本身也有一些开销,每个方法都会增加这种开销。建议在您的系统上运行一些测试。


0

1
根据软件要求,您确实可能需要担心开销。在所引用的论文中,它在哪里说得不同呢? - Andy Thomas
C语言中指向内存元素数组的指针概念已经消失,随之而来的是在C语言中导致代码不可靠的任意指针算术运算。你再也不能走出数组的边界,可能会破坏内存并导致著名的“延迟崩溃”综合症,在这种情况下,内存访问违规今天可能会在几个小时或几天后表现出来。程序员可以相信Java中的数组检查将导致更强大和可靠的代码。 - kosa
我理解你对开销的担忧,并且同意你的看法。 - kosa
1
所有这些都是正确的--但它并没有解决int和Integer之间的大小差异,也没有说明这是否值得关注。 :) - Andy Thomas
@Andy 根据个人经验,Java需要的内存比同等规模的C++应用程序要多得多(通常被提及的数字是 ~2)。因此,如果某人的内存受限,以至于必须担心简单包装的开销,那么Java可能并不是最合适的选择。在我看来,C++程序的最后堡垒基本上是:内存严重受限的应用程序和低级别的东西。 - Voo

0
不,int和Integer占用的空间大小不同。int是4个字节,而Integer会更多(具体多少取决于您是否在32位或64位模式下运行,可以测量)。一个常见的大小似乎是16个字节的Integer。
我不太确定您想要实现什么,但如果您使用Integer、Double等,则数组将保存对对象的引用,但如果您使用int double等,则保存值本身。然而,由于Integer、Double等是不可变的,我不知道仅具有对对象的引用会带来什么好处。
还有,您使用的是什么系统,只支持Java 1.3?它的EOL是2004年10月25日启动,于2006年12月11日结束,因此已经相当陈旧了。

对于FIRST Robotics,它使用Squawk解释器。 - Davidthefat
@Davidthefat 对象的布局是JVM特定的。大多数现代JVM都很相似,但是旧的嵌入式JVM可能完全不同。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接