La differenza tra C ++ e Java è in ciò che le lingue considerano la loro più piccola unità di collegamento.
Poiché C è stato progettato per coesistere con l'assembly, quell'unità è la subroutine chiamata da un indirizzo. (Questo è vero per altri linguaggi che vengono compilati in file di oggetti nativi, come FORTRAN.) In altre parole, un file oggetto contenente una funzione foo()
avrà un simbolo chiamato _foo
che verrà risolto in nient'altro che un indirizzo tale come 0xdeadbeef
durante il collegamento. Questo è tutto ciò che c'è. Se la funzione è di assumere argomenti, è compito del chiamante assicurarsi che tutto ciò che la funzione si aspetta sia in ordine prima di chiamare il suo indirizzo. Normalmente, questo viene fatto accumulando cose nello stack, e il compilatore si prende cura del lavoro del grugnito e assicurandosi che i prototipi combacino. Non c'è controllo di questo tra i file oggetto; se si risolve il collegamento di chiamata, la chiamata non sta per andare fuori come previsto e non si otterrà un avvertimento su di esso. Nonostante il pericolo, questo rende possibile che i file oggetto compilati da più linguaggi (incluso l'assemblaggio) siano collegati insieme in un programma funzionante senza troppe complicazioni.
C ++, nonostante tutto il suo fanciness aggiuntivo, funziona allo stesso modo. Il compilatore di scarpe namespace, classi e metodi / membri / ecc. in questa convenzione appiattendo i contenuti delle classi in singoli nomi che vengono storpiati in un modo che li rende unici. Ad esempio, un metodo come Foo::bar(int baz)
potrebbe essere modificato in _ZN4Foo4barEi
quando inserito in un file oggetto e un indirizzo come 0xBADCAFE
in fase di esecuzione. Questo dipende interamente dal compilatore, quindi se provi a collegare due oggetti con schemi di mangling diversi, sarai sfortunato. Per quanto brutto, significa che puoi usare un blocco extern "C"
per disabilitare il manegging, rendendo possibile rendere il codice C ++ facilmente accessibile ad altre lingue. C ++ ha ereditato la nozione di funzioni fluttuanti da C, soprattutto perché il formato nativo dell'oggetto lo consente.
Java è una bestia diversa che vive in un mondo isolato con il proprio formato di file oggetto, il file .class
. I file di classe contengono una grande quantità di informazioni sui loro contenuti che consentono l'ambiente fare cose con le classi in fase di esecuzione che il meccanismo di collegamento nativo non potrebbe nemmeno sognare. Questa informazione deve iniziare da qualche parte e quel punto di partenza è class
. Le informazioni disponibili consentono al codice compilato di descriversi senza la necessità di file separati contenenti una descrizione nel codice sorgente come avresti in C, C ++ o in altre lingue. Questo ti offre tutti i tipi di linguaggi di sicurezza che utilizzano la mancanza del link nativo, anche in fase di esecuzione, ed è ciò che ti permette di pescare una classe arbitraria da un file usando la reflection e usarla con un errore garantito se qualcosa non corrisponde .
Se non l'hai già capito, tutta questa sicurezza ha un compromesso: tutto ciò che colleghi a un programma Java deve essere Java. (Per "collegamento" intendo ogni volta che qualcosa in un file di classe fa riferimento a qualcosa in un altro.) Puoi collegare (in senso nativo) al codice nativo usando JNI , ma c'è un contratto implicito che dice che se rompi il lato nativo, possiedi entrambi i pezzi.
Java è stato grande e non particolarmente veloce sull'hardware disponibile quando è stato introdotto, proprio come Ada era stato nel decennio precedente. Solo Jim Gosling può dire con certezza quali fossero le sue motivazioni nel rendere la classe più piccola unità di collegamento di Java, ma dovrei indovinare che la complessità aggiuntiva che l'aggiunta di floaters avrebbe aggiunto al runtime avrebbe potuto essere un vero affare.