6

enter link description hereHow does the java compiler manage to resolve inter-class references so quickly, if you have a bunch of classes that all refer to each other and use each other's methods?

I know how C++ compilers work in this regard: each .cpp file is compiled separately, and they use those awful .h files to declare class fields/methods, so that the same set of files is re-parsed each time and/or compilers have to support pre-compiled headers.

But Java doesn't do this and there's no separation in program source of class interfaces/implementations the way Turbo Pascal separated them out.

I can see that if you have a class Foo and it refers to classes Bar, Baz, Quux that are all in a separate barbazquux.jar file, then things would be straightforward: the .jar file has already been compiled, so when Foo.java gets compiled it can just go look at the .class files in barbazquux.jar.

But if you have cyclical class references, and class Foo references class Bar which references class Foo, how does it possibly compile Foo.java without having to first compile Bar.java and then decide it has to compile Foo.java and get stuck in a loop?

What does the Java compiler do to handle inter-class references?


edit: yair points out another question with answers that vaguely mentions multipass compilers. Okay, so there are multiple passes. What exactly happens on each pass and how does Java manage to compile so quickly? Does it have to re-parse each file on each pass, or does it store the abstract syntax tree to save time, or what?

Community
  • 1
  • 1
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • ...and what is this concept called, so I can learn more about it if I choose to look into some compiler books? – Jason S Feb 12 '12 at 04:16
  • looks like dup question that's answered. See [here](http://stackoverflow.com/questions/3032874/how-does-compiling-circular-dependencies-work). – yair Feb 12 '12 at 07:01
  • I guess, but that question doesn't really have answers that say very much. – Jason S Feb 12 '12 at 13:41
  • I haven't delved into javac enough to know the whole story, but apparently it creates a class representation (similar to a loaded class's representation) for each class referenced. Circular references are not really a problem since Java doesn't allow objects (vs references) to be embedded in other objects -- so each reference can start out as just pointer-to-Object and then be refined as more info is discovered. – Hot Licks Feb 12 '12 at 14:15
  • 1
    compiler for c++ are hard: http://stackoverflow.com/questions/575143/writing-my-own-c-compiler – Ray Tayek Feb 12 '12 at 14:23
  • 2
    Please avoid extending the scope of the question by adding new questions to it. The last edit, which adds the question about performance, means that this question now has very low value to future visitors, as they cannot be sure what is being answered, nor which answers are the best because there are multiple reasons for upvotes. – Lasse V. Karlsen Mar 16 '12 at 10:12
  • One major reason the javac compiler runs so quickly is that it isn't a full optimizing compiler and isn't translating all the way to machine code. A lot of the difficult work is left until runtime, when the JIT compiler (eventually) executes. – keshlam Feb 20 '14 at 05:53

2 Answers2

0

C++ has to parse the source code of an external class declaration, typically in a .hpp file. Java processes the object code of external class declarations, which is already compiled. What Java does is more like what languages with packages do, e.g. Ada, Modula-3, ... That's also why most C/C++ compilers have 'precompiled headers' too.

user207421
  • 305,947
  • 44
  • 307
  • 483
-1

The grammar of C++ is much more complicated, expression parts ambiguous. So Javac is more efficient in parsing. Also C++ has more fine grained compilation units. C++ includes, even if precompiled, have a recursive visibility: includes of includes of includes define names one can use. In Java if you use the parent class of an imported class, one need to explicitly import it.

Cyclic class references are problematic. In Java one may as precondition assume that a class exists, even if that class is yet uncompiled. But the java compiler is even more impressive, being able to compile them at the same time. Same because of the cyclic dependencies. The JVM byte code invoke instructions use method names, so one may speculatively compile the first class.

public class A {
    public static void a(int i) {
        System.out.println("a(" + i + ")");
        if (i < 10)
            B.b(i + 2);
    }
}

public class B {
    public static void b(int i) {
        System.out.println("b(" + i + ")");
        if (i < 10)
            A.a(i + 1);
    }
}

public static void main(String... args) {
    B.b(0);
}
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138