自从我上次用Java编写代码以来已经有一段时间了,但我需要一点提示。 我们有一个简单的功能 - 请注意这是C:
void update(double *source, double *target, int n) {
for(int i = 0; i < n; ++i)
target[i] = source[i] * i; // well, actually a bit more complicated, just some kind of calculation
}
所以,现在我需要在Java中有效地重新编码这个函数。我的问题是:
请注意,源和目标是大型数组,最多可存储100万个元素
答案 0 :(得分:6)
在Java中,它几乎是一样的:
static void update(double[] source, double[] target, int n)
{
for (int i = 0; i < n; i++)
target[i] = source[i] * i;
}
您不复制任何内存。将数组传递给此函数时,它会按值将引用传递给数组。
通常,Java按值传递函数参数。但是对于数组和用户定义的类,您正在处理的对象始终是引用类型。因此,对类和数组的函数调用总是按值传递类/数组引用。
因此,如果您有一个类似于以下的类:
class Foo
{
int[] A; // For arguments say let's say this contains 1 million items always
}
你有一个可以调用的功能:
static void Bar(Foo f)
{
....
}
它仅将引用传递给Foo
,它根本不会复制数据。
答案 1 :(得分:2)
通过引用传递数组(传递引用的值)。所以不会有任何新的数组副本。
代码非常相似:
void update(double source[], double target[], int n)
{
for (int i = 0; i < n; i++)
target[i] = source[i] * i;
}
'数组的数据结构'是什么意思?数组本身就是一种数据结构。无论如何,您必须访问每个元素,以了解您尝试执行的操作类型。所以数组本身就是一个很好的数据结构。你可能想看看ArrayList。
答案 2 :(得分:1)
Java使用数组(和其他对象)的引用。引用的值而不是数组本身在方法调用中传递,其成本类似于C指针。如果您不需要动态展开它们,简单数组就是最快的数据结构。
否则,考虑 ArrayList<Double>。但是这些在速度和大小方面都要贵得多,因为每个double都在Double对象中“装箱”。
第三种方法是使用具有高性能原始集合的库中相关的可调整大小的列表类,如Trove's TDoubleArrayList。
您没有提出的问题是,Java是否会将处理器的任何相关SIMD功能用于这样的简单循环。我很高兴你没有,因为我不知道。但我相信,如果 足够聪明,可以使用它们,那么它只适用于简单数组。
答案 3 :(得分:1)
Java使用call-by-object语义,因此没有复制。
答案 4 :(得分:1)
Java规范说Java中的所有内容都是按值传递的。在Java中没有“pass-by-reference”这样的东西。 但是,不要被这种愚弄,内部工作非常复杂,你实际上可以按照你想要的方式操作数组。
从Oracle的Java教程中逐字逐句:
也会传入参考数据类型参数,例如对象 方法的价值。这意味着当方法返回时, 传入引用仍引用与以前相同的对象。 但是,可以在中更改对象字段的值 方法,如果他们有适当的访问级别。
Java按值复制并传递引用,而不是对象。因此,方法操作将改变对象,因为引用指向原始对象。但由于引用是副本,因此交换将失败。
要使用的代码类似且简单明了:
void update(double source[], double target[], int n)
{
for (int i = 0; i < n; i++)
target[i] = source[i] * i;
}
为了更好地理解我提到的内容,请看一下这个问题:Is Java "pass-by-reference" or "pass-by-value"?
关于数据结构的问题,请使用数组。看看你的代码片段,显然你需要随机访问,所以只需坚持使用好的数组..
答案 5 :(得分:1)
正如其他一些人已经指出的那样,-ref / by-value是一个C / C ++的东西,不适用于Java。
现在,除非你正在做一些真正的本机编码,将这些数组C / C ++传递给Java:
鉴于C代码数组作为指针(void update(double *source, double *target, int n)
)传递,我假设它的大小是动态的,如果是这样,你在Java中的签名应该是void update(List<Double> source, List<Double> target, int n)
。让来电者决定是ArrayList
还是Vector
还是LinkedList
还是......
但是如果你进入一些JNI(将这些数组C / C ++传递给Java / Java),那么我们可能需要考虑其他方面。