6

前几天我正在阅读Kernighan 和 Rob Pike的《编程实践》 。

在第二章的“搜索”部分,我读到了其中一些让我感到困惑的台词。

“没有什么能比数组更好地存储静态表格数据。编译时初始化使得构造这样的数组变得便宜且容易。(在 Java 中,初始化发生在运行时,但这是一个不重要的实现细节,除非数组很大。 )"

我的问题是,如果用户仅在运行时提供数组或变量的编译时初始化,并且变量的内存分配发生在运行时,那么在任何语言中如何进行数组或变量的编译时初始化。在不知道内存地址的情况下如何初始化数组?

4

3 回答 3

1

我想你误解了作者的意思。笔记:

这是一个静态数组,在 Java 中:

String[] suit = {
  "item 1", 
  "item 2", 
  "item 3", 
  "item 4"  
};

现在,Java 不允许您像 Delphi 和其他语言那样声明真正的动态数组,对于动态数组,我们必须选择另一个数据结构,ArrayList如下例所示:

List<String> list = new ArrayList<String>();

如果用户想使用运行时定义长度的静态数组,他可以做的最灵活的方法如下:

int maxsize = Integer.ParseInt(JOP.ShowInputDialog("give me a number")...);
int[] myArray = new int[maxsize]();

这是 Delphi 中的静态数组:

const MyStaticArray : array [0..3] of Integer = (0, 1, 2, 3);

这是动态数组

var MyDinamicArray : array of Integer; 
    MaxSize: Integer;
begin
  MaxSize := StrToInt(InputBox(..,'Give me a number', ..));
  SetLength(MyDinamicArray, MaxSize); //Defines the array size, in runtime;
end;

我的问题是,如果用户仅在运行时提供数组或变量的编译时初始化,并且变量的内存分配发生在运行时,那么在任何语言中如何进行数组或变量的编译时初始化。在不知道内存地址的情况下如何初始化数组?

也就是说,我们可以很容易地看到,这是一个“编译时”初始化(与实现细节无关)

String[] suit = {
  "item 1", 
  "item 2", 
  "item 3", 
  "item 4"  
};

一旦数组被初始化,它就不能被调整大小,所以操作系统可以在任何它想要的地方分配内存。而且由于数组在内存中是连续的,通过使用索引,Java 知道您想要获取的地址。

考虑到上面的数组,这是内存草图:

//程序存储器

address   00A1
value   | 00BA |
alias     suit 

//操作系统内存

address      00BA      00BB       00BC       00BD      
value    | "item 1" | "item 2" | "item 3" | "item 4" | 
alias       suit[0]    suit[1]    suit[2]    suit[3]

字符串在这里是为了方便理解,其实String也是一个指向某个东西的指针。

别名是Java隐藏指针算法的方式,即允许我们访问索引而不是内存地址。

以下是有关数组的一些文档:

读取静态数组并查看数组列表

于 2013-10-29T11:18:16.623 回答
1

它并没有说数据是在运行时提供的。它只是说“静态”数据。如果它在编译时是已知的,那么编译器可以将其直接编译到代码中。API 密钥、带有“幻数”的表格或错误消息文本都适合该模式。

于 2013-10-29T10:13:41.967 回答
0

JLS

10.2. 数组变量

数组类型的变量保存对对象的引用。声明数组类型的变量不会创建数组对象或为数组组件分配任何空间。它只创建变量本身,它可以包含对数组的引用。

但是,声明器的初始化部分(第 8.3 节、第 9.3 节、第 14.4.1 节)可能会创建一个数组,然后对它的引用成为变量的初始值。

于 2013-10-29T10:14:00.677 回答