2012-02-12 8 views
6

enter link description here W jaki sposób kompilator Java może tak szybko rozwiązywać odwołania między klasami, jeśli masz kilka klas, które odnoszą się do siebie nawzajem i używają nawzajem swoich metod?kompilatory + odwołania międzyklasowe: w jaki sposób javac robi to szybko, co kompilatory C++ robią powoli?

Wiem, jak działają kompilatory C++ w tym zakresie: każdy plik .cpp jest kompilowany osobno i używa tych okropnych plików .h do deklarowania pól/metod klas, tak aby ten sam zestaw plików był ponownie analizowany za każdym razem i/lub kompilatory muszą obsługiwać wstępnie skompilowane nagłówki.

Ale Java tego nie robi i nie ma separacji w źródle programu dla interfejsów klas/implementacji w sposób, w jaki Turbo Pascal je rozdzielił.

Widzę, że jeśli masz klasę Foo i odnosi się ona do klas Bar, Baz, Quux, które znajdują się w oddzielnym pliku barbazquux.jar, wtedy rzeczy będą proste: plik .jar został już skompilowany, więc gdy Foo.java zostanie skompilowana, może po prostu przyjrzeć się plikom .class w pliku barbazquux.jar.

Ale jeśli masz cykliczne odwołania do klas, a klasa Foo odwołuje się do paska klasy, który odwołuje się do klasy Foo, w jaki sposób może kompilować Foo.java bez konieczności kompilacji najpierw Bar.javy, a następnie zdecydować, że musi skompilować Foo.java i utknąć w pętli?

Co robi kompilator Java, aby obsłużyć odwołania między klasami?


edit: Yair zaznacza another question z odpowiedzi, które ogólnikowo wspomina Multipass kompilatorów. Okej, więc jest wiele przepustek. Co dokładnie dzieje się przy każdym przejściu i jak Java tak szybko się kompiluje? Czy musi ponownie przeanalizować każdy plik przy każdym przejściu, czy też przechowuje abstrakcyjne drzewo składniowe, aby zaoszczędzić czas lub co?

+0

... i jak nazywa się to pojęcie, więc mogę dowiedzieć się więcej na ten temat, jeśli zdecyduję się zajrzeć do niektórych książek kompilatora? –

+0

wygląda na dupę, na którą odpowiedziano. Zobacz [tutaj] (http://stackoverflow.com/questions/3032874/how-does-compiling-circular-dependencies-work). – yair

+0

Zgaduję, ale to pytanie nie zawiera tak naprawdę odpowiedzi, które mówią bardzo. –

Odpowiedz

-1

Gramatyka języka C++ jest znacznie bardziej skomplikowana, a wyrażenia niejednoznaczne. Tak Javac jest bardziej wydajny w parsowaniu. Również C++ ma więcej drobnoziarnistych jednostek kompilacji. C++ zawiera, nawet jeśli jest skompilowany, dostęp do rekursywnej widoczności: obejmuje obejmuje zawiera definicje, których można użyć. W Javie, jeśli używasz klasy nadrzędnej importowanej klasy, należy ją jawnie zaimportować.

Odniesienia do klas cyklicznych są problematyczne. W Javie jako warunek wstępny można przyjąć, że klasa istnieje, nawet jeśli ta klasa jest jeszcze nieskompilowana. Ale kompilator java jest jeszcze bardziej imponujący, będąc w stanie skompilować je w tym samym czasie. To samo z powodu cyklicznych zależności. JVM byte code invoke instructions używa nazw metod, więc można spekulatywnie skompilować pierwszą klasę.

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); 
} 
+0

Pytanie nie dotyczy wydajności w analizie. Chodzi o rozwiązanie zależności między klasami. – EJP

0

C++ musi przeanalizować kod źródłowy zewnętrznej deklaracji klasy, zwykle w pliku .hpp. Java przetwarza kod obiektowy zewnętrznych deklaracji klasy, który jest już skompilowany. To, co robi Java, bardziej przypomina języki z pakietami, np. Ada, Modula-3, ... To także dlatego większość kompilatorów C/C++ ma również "prekompilowane nagłówki".

+0

@downvoter Twoje powody, proszę – EJP

+0

idk, ale przegłosowałem. Może to plik ".hpp"; nikt tak naprawdę ich nie używa, pliki C++ są również zwykle plikami ".h". –

Powiązane problemy