1

考虑一个简单的代码:

public class Graph {

    private final List<ArrayList<Integer>> adjList = new ArrayList<ArrayList<Integer>>();
    private final int vertexCount;
    private int edgeCount;

    public Graph(int vertexCount) {
        this.vertexCount = vertexCount; 
    }
}

我的问题是何时创建 adjList 对象,换句话说,何时将内存分配给 adjList?

是在构造函数调用之后(不太可能)吗?

之前(因为一个类可以是带有私有构造函数的静态类)?

如果在考虑代码之前精确地构造如下:

Graph g = new Graph(10); 
4

4 回答 4

3

jls-12.5 : 创建新类实例

每当创建一个新的类实例时,都会为其分配内存空间,并为该类类型中声明的所有实例变量和该类类型的每个超类中声明的所有实例变量(包括所有可能隐藏的实例变量)分配空间( §8.3)。

于 2013-08-14T05:50:17.453 回答
3

重要的是要理解这adjList不是一个对象。它是一个变量——一个字段。变量的空间adjList几乎是在创建实例时发生的第一Graph件事......在任何构造函数调用甚至开始之前。

接下来,VM 遍历继承层次结构,评估所需的任何构造函数参数,直到它到达Object类,然后它在那里执行构造函数的主体......然后堆栈弹出以执行子类的构造函数主体。因此,如果您有:

class Foo extends Object
class Bar extends Foo

然后 for 的构造函数体Object首先被执行,然后Foo是 ,然后是Bar.

只有当构造器主体执行时,实例初始化器才会被执行。这就是发生此调用的时间:

new ArrayList<ArrayList<Integer>>()

这会创建另一个对象,然后初始化程序将对新对象的引用adjList分配给变量。重要的是要理解 的值adjList不是一个对象——它是一个引用。所以现在有两个对象(一个Graph和一个ArrayList)以及对象内对Graph对象的引用ArrayList。(实际上,ArrayList也将引用一个数组。)

于 2013-08-14T05:52:13.040 回答
0
   private final List<ArrayList<Integer>> adjList = new ArrayList<ArrayList<Integer>>();
    private final int vertexCount;
    private int edgeCount;

    public Graph(int vertexCount) {
        this.vertexCount = vertexCount; 
    }

变成:

   private final List<ArrayList<Integer>> adjList;
    private final int vertexCount;
    private int edgeCount;

    public Graph(int vertexCount) {
        adjList = new ArrayList<ArrayList<Integer>>();
        edgeCount = 0;
        this.vertexCount = vertexCount; 

    }

默认内存是在new调用之后立即分配的,之后JVM调用构造函数。从那里,所有实例变量都在构造函数中实例化。编译器将显式定义移动到构造函数体内。

于 2013-08-14T05:50:00.583 回答
0

我的问题是何时创建 adjList 对象,换句话说,何时将内存分配给 adjList?

作为实例变量,它将在创建实例时创建。

是在构造函数调用之后(不太可能)吗?

它将作为构造函数调用的一部分创建,因为构造函数将确保根据实例变量在内存中创建对象。

之前(因为一个类可以是带有私有构造函数的静态类)?

不,在构造函数调用之前只创建静态变量。加载类时会创建静态变量。

于 2013-08-14T05:50:52.873 回答