ジャバ・バイトコードの構文

最近ドットネットのCILとジャバのバイトコードの使用を見ています。バイトコードの場合にコンスタントプールと言うところに関して悩みがあります。
I understand that method calls, object instance fields, classes, and other data referenced via addresses on the heap are usually referred to in bytecode by offsets in the constant pool like "invokespecial #3" to call an init method defined at location 3 in the constant pool. However, I am not sure why the constant pool is needed. At compile time, the heap layout of the class in question with respect to other classes is not known, but any classes this class depends on will have already been compiled, so the compiler does have access to the dispatch table layout for another class. Perhaps this facilitates runtime memory layout (loading of other classes this one depends on), but I do not see why every method called for a given class is noted in the constant pool. In fact, even methods of the class to be defined are in the constant pool. Perhaps it makes the replacement of these entries with heap addresses easier at runtime, as multiple mentions of the same table entry are all set correctly by one update to the constant pool. まだ勉強中です。
更新
According to the VM specification, the constant pool serves the same purpose as the symbol table in other programming languages. However, the symbol table in other languages is primarily a compile-time resource. Perhaps it is useful at runtime for catching null pointer exceptions, although I would expect these to be thrown after the address in the symbol table is already evaluated in the expression. The constant pool is allocated from the VM's method area, which is analogous to the text segment in a native runtime. Other object file specifications use symbol tables for specifying external references, I believe (COFF, ELF), but I do not see why methods internal to the class of the file are included.