Trzy rodzaje przenośności w Javie

Java wzbudziła wiele emocji w społeczności programistów, ponieważ obiecuje przenośne aplikacje i aplety. W rzeczywistości Java zapewnia trzy różne typy przenośności: przenośność kodu źródłowego, przenośność architektury procesora i przenośność OS / GUI. Fakt, że istnieją trzy różne typy przenośności, jest krytyczny, ponieważ tylko jeden z nich stanowi zagrożenie dla firmy Microsoft. Można oczekiwać, że Microsoft podważy ten jeden typ przenośności, jednocześnie przyjmując dwa pozostałe - jednocześnie twierdząc, że obsługuje Javę. Zrozumienie trzech typów przenośności i sposobu ich współdziałania ma kluczowe znaczenie dla zrozumienia zagrożenia dla firmy Microsoft oraz możliwych odpowiedzi firmy Microsoft.

Zanim jednak przejdziemy do szczegółów każdego z tych trzech rodzajów przenośności, przyjrzyjmy się kilku podstawowym pojęciom.

Definiowanie niektórych terminów

W tym artykule używane są następujące terminy:

Endianizm
Endianizm odnosi się do kolejności przechowywania bajtów w wielobajtowej ilości w danym procesorze. Na przykład krótki bez znaku 256 (dziesiętny) wymaga dwóch bajtów pamięci: 0x01 i 0x00. Te dwa bajty mogą być przechowywane w dowolnej kolejności: 0x01, 0x00lub 0x00, 0x01. Endianizm określa kolejność, w jakiej dwa bajty są przechowywane. Ze względów praktycznych endianizm ma zwykle znaczenie tylko wtedy, gdy procesory o innym endianizmie muszą udostępniać dane.
Jawa
Java to kilka różnych technologii spakowanych razem - język programowania Java, wirtualna maszyna Java (JVM) i biblioteki klas powiązane z językiem. W tym artykule omówiono wszystkie te aspekty.
Wirtualna maszyna Java (JVM)

JVM to wyimaginowany procesor, dla którego większość kompilatorów języka Java emituje kod. Obsługa tego wyimaginowanego procesora umożliwia uruchamianie programów Java bez ich ponownej kompilacji na różnych procesorach. Żaden element języka programowania Java nie wymaga, aby kod źródłowy Java został wkompilowany w kod maszyny JVM zamiast w natywny kod obiektowy.

W rzeczywistości Asymetrix i Microsoft ogłosiły kompilatory Java, które emitują natywne aplikacje Microsoft Windows. (Aby uzyskać dodatkowe informacje, zobacz sekcję Zasoby w tym artykule).

Kod J.
Kod J jest wyjściem emitowanym przez większość kompilatorów Java do plików klas. Kod J można traktować jako kod obiektowy maszyny wirtualnej Java.
Ruchliwość
Przenośność odnosi się do możliwości uruchamiania programu na różnych komputerach. Uruchamianie danego programu na różnych maszynach może wymagać różnej ilości pracy (na przykład brak jakiejkolwiek pracy, ponowna kompilacja lub wprowadzanie niewielkich zmian w kodzie źródłowym). Kiedy ludzie określają aplikacje i aplety Java jako przenośne, zwykle mają na myśli aplikacje i aplety działające na różnych typach maszyn bez żadnych zmian (takich jak rekompilacja lub poprawki w kodzie źródłowym).

Teraz, gdy omówiliśmy kilka podstawowych terminów, wyjaśnimy każdy z trzech typów przenośności języka Java.

Java jako język: przenośność kodu źródłowego

Jako język programowania Java zapewnia najprostszą i najbardziej znaną formę przenośności - przenośność kodu źródłowego. Dany program Java powiniendają identyczne wyniki niezależnie od używanego procesora, systemu operacyjnego czy kompilatora Java. Ten pomysł nie jest nowy; języki takie jak C i C ++ zapewniają ten poziom przenośności przez wiele lat. Jednak C i C ++ zapewniają również wiele możliwości tworzenia nieprzenośnego kodu. O ile programy napisane w C i C ++ od samego początku nie są zaprojektowane tak, aby były przenośne, możliwość przenoszenia się na inne maszyny jest bardziej teoretyczna niż praktyczna. C i C ++ pozostawiają niezdefiniowane szczegóły, takie jak rozmiar i endianizm atomowych typów danych, zachowanie matematyki zmiennoprzecinkowej, wartość niezainicjowanych zmiennych oraz zachowanie podczas uzyskiwania dostępu do zwolnionej pamięci.

Krótko mówiąc, chociaż składnia C i C ++ jest dobrze zdefiniowana, semantyka tak nie jest. Ta luźność semantyczna pozwala pojedynczemu blokowi kodu źródłowego C lub C ++ na kompilowanie do programów, które dają różne wyniki, gdy są uruchamiane na różnych procesorach, systemach operacyjnych, kompilatorach, a nawet na jednej kombinacji kompilator / procesor / system operacyjny, w zależności od różnych ustawień kompilatora. (Zobacz sekcję Składnia a semantyka, aby zapoznać się z omówieniem różnic między semantyką a składnią).

Java jest inna. Java zapewnia znacznie bardziej rygorystyczną semantykę i pozostawia mniej w gestii osoby wdrażającej. W przeciwieństwie do C i C ++, Java ma zdefiniowane rozmiary i endianizm dla typów atomowych, a także zdefiniowane zachowanie zmiennoprzecinkowe.

Ponadto Java definiuje więcej zachowań niż C i C ++. W Javie pamięć nie jest zwalniana, dopóki nie będzie można uzyskać do niej dostępu, a język nie ma żadnych niezainicjowanych zmiennych. Wszystkie te funkcje pomagają zawęzić różnice w zachowaniu programu Java od platformy do platformy i od implementacji do implementacji. Nawet bez maszyny JVM można oczekiwać, że programy napisane w języku Java będą przenosić (po ponownej kompilacji) na różne procesory i systemy operacyjne znacznie lepiej niż równoważne programy w języku C lub C ++.

Niestety, funkcje, które sprawiają, że Java jest tak przenośna, mają wadę. Java zakłada 32-bitową maszynę z 8-bitowymi bajtami i zmiennoprzecinkową matematyką IEEE754. Maszyny, które nie pasują do tego modelu, w tym 8-bitowe mikrokontrolery i superkomputery Cray, nie mogą wydajnie obsługiwać języka Java. Z tego powodu powinniśmy oczekiwać, że C i C ++ będą używane na większej liczbie platform niż język Java. Powinniśmy również oczekiwać, że programy w Javie będą łatwiejsze do przenoszenia niż C lub C ++ między tymi platformami, które obsługują obie platformy.

Java jako maszyna wirtualna: przenośność procesora

Większość kompilatorów tworzy kod obiektowy, który działa na jednej rodzinie procesorów (na przykład rodzina Intel x86). Nawet kompilatory, które tworzą kod obiektowy dla kilku różnych rodzin procesorów (na przykład x86, MIPS i SPARC), generują jednocześnie kod obiektowy tylko dla jednego typu procesora; jeśli potrzebujesz kodu obiektowego dla trzech różnych rodzin procesorów, musisz trzykrotnie skompilować kod źródłowy.

Obecne kompilatory Java są różne. Zamiast generować dane wyjściowe dla każdej rodziny procesorów, na których program Java ma działać, obecne kompilatory języka Java tworzą kod obiektowy (zwany kodem J) dla procesora, który jeszcze nie istnieje.

(Sun został ogłoszony procesor, który będzie wykonywał bezpośrednio J-kodu, ale wskazuje pierwsze próbki chipów Java nie pojawią się dopiero w drugiej połowie tego roku; pełna produkcja takich chipów rozpocznie się w przyszłym roku podstawową technologię Sun Microelectronics' picoJavaI. będzie stanowić serce własnej linii procesorów microJava firmy Sun, która będzie skierowana do komputerów sieciowych. Licencjobiorcy tacy jak LG Semicon, Toshiba Corp. i Rockwell Collins Inc. planują również produkować chipy Java oparte na rdzeniu picoJavaI).

Dla każdego rzeczywistego procesora, na którym mają działać programy w języku Java, interpreter języka Java lub maszyna wirtualna „wykonuje” kod J. Ten nieistniejący procesor umożliwia uruchomienie tego samego kodu obiektowego na dowolnym procesorze, dla którego istnieje interpreter języka Java.

Tworzenie danych wyjściowych dla wyimaginowanego procesora nie jest niczym nowym w Javie: kompilatory Pascal UCSD (University of California w San Diego) stworzyły kod P lata temu; Limbo, nowy język programowania rozwijany w Lucent Technologies, tworzy kod obiektowy dla wyimaginowanego procesora; a Perl tworzy pośrednią reprezentację programu i wykonuje tę pośrednią reprezentację zamiast tworzenia natywnego kodu wykonywalnego. Wirtualna maszyna wirtualna obsługująca Internet wyróżnia się spośród innych implementacji wirtualnych procesorów tym, że jest celowo zaprojektowana w celu umożliwienia generowania dającego się udowodnić i wolnego od wirusów kodu. Przed pojawieniem się Internetu maszyny wirtualne nie musiały potwierdzać, że programy są bezpieczne i wolne od wirusów. Ta funkcja bezpieczeństwa, w połączeniu ze znacznie lepszym zrozumieniem, jak szybko uruchamiać programy dla wyimaginowanych procesorów, doprowadziła do szybkiego,powszechna akceptacja JVM. Obecnie większość głównych systemów operacyjnych, w tym OS / 2, MacOS, Windows 95 / NT i Novell Netware, ma lub ma mieć wbudowaną obsługę programów w języku J.

JVM, będący zasadniczo wyimaginowanym procesorem, jest niezależny od języka kodu źródłowego. Język Java może tworzyć kod J. Ale tak samo może się stać Ada95. W rzeczywistości interpretery hostowane w kodzie J zostały napisane dla kilku języków, w tym BASIC, Forth, Lisp i Scheme, i jest prawie pewne, że implementacje innych języków będą emitować kod J w przyszłości. Po przekonwertowaniu kodu źródłowego na kod w języku J interpreter języka Java nie może stwierdzić, jaki język programowania utworzył kod J, który wykonuje. Wynik: przenośność między różnymi procesorami.

Zaletą kompilowania programów (w dowolnym języku) do kodu J jest to, że ten sam kod działa na różnych rodzinach procesorów. Wadą jest to, że kod w języku J nie działa tak szybko, jak kod natywny. W przypadku większości aplikacji nie będzie to miało znaczenia, ale w przypadku najwyższych programów z wyższej półki - tych, które potrzebują co najmniej jednego procentu procesora - koszt wydajności kodu J nie będzie akceptowalny.

Java jako wirtualny system operacyjny i graficzny interfejs użytkownika: przenośność systemu operacyjnego

Większość programów Microsoft Windows napisanych w C lub C ++ nie daje się łatwo przenosić do środowisk Macintosh lub Unix, nawet po ponownej kompilacji. Nawet jeśli programiści zwracają szczególną uwagę na semantyczne słabości w C lub C ++, port jest trudny. Ta trudność występuje nawet wtedy, gdy port do systemu operacyjnego innego niż Windows odbywa się bez zmiany procesorów. Skąd ta trudność?

Po wyeliminowaniu problemów semantycznych w C i C ++ oraz problemów z portowaniem procesora programiści nadal muszą radzić sobie z innym systemem operacyjnym i różnymi wywołaniami interfejsu GUI API.

Programy Windows wykonują bardzo różne wywołania systemu operacyjnego niż programy Macintosh i Unix. Te wywołania mają kluczowe znaczenie dla pisania nietrywialnych programów, więc dopóki nie zostanie rozwiązany ten problem z przenośnością, przenoszenie pozostanie trudne.

Java rozwiązuje ten problem poprzez dostarczenie zestawu funkcji bibliotecznych (zawarte w Java dostarczonych bibliotek takich jak awt, utili lang), że rozmowa na wyimaginowanej OS i urojonej GUI. Podobnie jak JVM przedstawia wirtualny procesor, tak biblioteki Java przedstawiają wirtualny system operacyjny / graficzny interfejs użytkownika. Każda implementacja Java udostępnia biblioteki implementujące ten wirtualny system operacyjny / graficzny interfejs użytkownika. Programy w języku Java, które używają tych bibliotek do zapewniania potrzebnego portu operacyjnego i funkcji GUI dość łatwo.

Używanie biblioteki przenośności zamiast natywnych wywołań systemu operacyjnego / GUI nie jest nowym pomysłem. Produkty takie jak Galaxy firmy Visix Software i Zinc firmy Protools Software zapewniają tę możliwość w językach C i C ++. Innym podejściem, którego nie stosuje Java, jest wybranie pojedynczego systemu operacyjnego / GUI jako głównego i udostępnienie bibliotek opakowujących obsługujących ten główny system operacyjny / GUI na wszystkich maszynach, na które chcesz przenieść. Problem z podejściem master OS / GUI polega na tym, że portowane aplikacje często wyglądają obco na innych komputerach. Na przykład użytkownicy komputerów Macintosh narzekali na najnowszą wersję programu Microsoft Word dla komputerów Macintosh, ponieważ wyglądała ona i zachowywała się jak program Windows, a nie jak program Macintosh. Niestety podejście przyjęte przez Javę również ma problemy.

Java zapewnia funkcjonalność najmniej wspólnego mianownika w swoich bibliotekach OS / GUI. Funkcje dostępne tylko w jednym systemie operacyjnym / GUI, takie jak okna dialogowe z zakładkami, zostały pominięte. Zaletą tego podejścia jest to, że mapowanie typowych funkcji na natywny system operacyjny / graficzny interfejs użytkownika jest dość łatwe i, z ostrożnością, może zapewnić aplikacje, które działają zgodnie z oczekiwaniami w większości systemów operacyjnych / graficznych interfejsów użytkownika. Wadą jest to, że dla aplikacji w trybie natywnym będą dostępne funkcje niedostępne dla aplikacji Java. Czasami programiści będą mogli obejść ten problem, rozszerzając AWT; innym razem nie. W przypadkach, gdy pożądana funkcjonalność jest nieosiągalna przy użyciu obejść, programiści najprawdopodobniej zdecydują się napisać nieprzenośny kod.

Kogo obchodzi przenośność?

Trzy główne grupy odbiorców dbają o przenośność: programiści, użytkownicy końcowi i działy MIS.

Deweloperzy: Szanse i zagrożenia są duże

Programiści mają żywotny interes w tworzeniu oprogramowania przenośnego. Z drugiej strony, przenośne oprogramowanie pozwala im obsługiwać więcej platform, co prowadzi do większej bazy potencjalnych klientów. Jednak ta sama przenośność, która umożliwia programistom kierowanie reklam na nowe rynki, umożliwia również konkurentom kierowanie reklam na ich rynek.

Krótko mówiąc, przenośność Javy wypycha rynek oprogramowania aplikacyjnego z oddzielnych rynków opartych na różnych systemach operacyjnych i graficznych interfejsach użytkownika w kierunku jednego dużego rynku. Na przykład na obecnym rynku oprogramowania Microsoft jest potęgą, z którą należy się liczyć na rynkach oprogramowania użytkowego dla systemów Windows i Macintosh, ale prawie nie jest obecna na rynkach OS / 2 i Unix. To partycjonowanie pozwala firmom na rynkach OS / 2 i Unix ignorować Microsoft jako konkurenta. Java ułatwia tym firmom konkurowanie na rynku Windows, ale także umożliwia Microsoftowi łatwiejsze wejście na rynki OS / 2 i Unix.

Użytkownicy: pośredni beneficjenci przenoszenia

Użytkownicy nie dbają o przenośność jako taką. Jeśli przenośność sprawia, że ​​ich życie jest łatwiejsze i przyjemniejsze, wszyscy są za tym; jeśli nie, to nie są. Przenośność ma pewne pozytywne skutki dla użytkowników, ale są one nieco pośrednie. Pozytywne efekty: