Язык Java зародился как часть проекта компании Sun Microsystems по разработке программного обеспечения для микропроцессоров, используемых в различных бытовых приборах. Реализация проекта была начата на языке С++, но вскоре у команды разработчиков возникли проблемы, обусловленные наличием большого количества процессоров, каждый из которых имеет свою архитектуру и систему команд. Соответственно, возникала необходимость разрабатывать компилятор языка С++ для каждого вида процессора (и каждой операционной системы, если речь шла о настольных компьютерах) и затем перекомпилировать все написанные программы. Стало очевидным, что необходим платформно-независимый язык программирования, позволяющий создавать программы, которые не приходилось бы компилировать отдельно для каждой архитектуры и можно было бы использовать на различных процессорах под различными операционными системами.
Толчком к разработке такого языка послужила довольно интересная история. В 1990 году ведущий разработчик ПО компании Sun Microsystems Патрик Ноутон (Patrick Naughton) понял, что ему надоело поддерживать сотни различных архитектур и операционных систем, и сообщил исполнительному директору Sun Microsystems и своему другу Скотту МакНили (Scott McNealy) о своем намерении перейти работать в компанию NeXT. МакНили, в свою очередь, попросил Ноутона составить список причин своего недовольства и выдвинуть такое решение проблем, как если бы он был Богом и мог исполнить все, что угодно. Ноутон, хотя и не рассчитывал на то, что кто-то обратит внимание на его письмо, все же изложил свои претензии, беспощадно раскритиковав недостатки модели разработки ПО, принятой в Sun Microsystems. К удивлению Ноутона, его письмо возымело успех: оно было разослано всем ведущим инженерам Sun Microsystems, которые не замедлили откликнуться и высказать горячую поддержку своему коллеге и одобрение его взглядов на ситуацию. Обращение вызвало одобрение и у высшего руководства компании, а именно, у Билла Джоя (Bill Joy), основателя Sun Microsystems, и Джеймса Гослинга (James Gosling), начальника Ноутона.
В 1991 г. в тот день, когда Ноутон должен был уйти из компании, было принято решение о создании команды ведущих разработчиков с тем, чтобы они «делали что угодно, но создали нечто необыкновенное». Команда из шести человек (Джеймс Гослинг, Патрик Ноутон, Крис Варт, Эд Франк, Майк Шеридан) приступила к разработке нового объектно-ориентированного, платформно-независимого языка программирования, который первоначально был назван Oak (дуб), в честь дерева, росшего под окном Гослинга. Перед публичным объявлением нового языка весной 1995 г. он был переименован в Java.
Из рисунка видно, что исходная Java-программа должна быть в файле с расширением java. Программа транслируется в байт-код компилятором javac.exe. Оттранслированная в байт-код программа имеет расширение class. Для запуска программы нужно вызвать интерпретатор байт-кода java.exe, указав в параметрах вызова, какую программу ему следует выполнять. Кроме того, ему нужно указать, какие библиотеки нужно использовать при выполнении программы. Библиотеки размещены в файлах с расширением jar.
Такая модель выполнения программ позволяет легко обеспечить их переносимость. Единственное условие: JVM должна быть реализована для каждой платформы. Как только для данной конкретной платформы появляется JVM – это означает, что для нее можно выполнить любую программу, написанную на Java без дополнительной обработки, перекомпиляции и т.п. JVM базируется на стандарте интерфейса переносимых операционных систем (POSIX).
Архитектурная независимость - лишь составная часть переносимости. В отличие от С или С++ в Java не существует понятия "зависимости от реализации", когда речь идет о размерности базовых типов. Форматы типов данных и операции над ними четко определены. Тем самым, программы остаются неизменными на любой платформе - не существует несовместимости типов данных на аппаратных и программных архитектурах.
Java является полностью объектно-ориентированным языком программирования. Это означает, что на Java нельзя писать программы не в объектно-ориентированном стиле. Здесь есть существенное отличие от С++, который допускает разработку программ в традиционном стиле, без использования объектно-ориентированного подхода. Это отличие объясняется тем, что С++ создавался как расширение языка С, который не являлся объектно-ориентированным, поэтому была необходимость обеспечить выполнение кода, написанного на С. Поскольку язык Java создавался «с чистого листа», без необходимости обеспечивать совместимость с каким-либо другим языком, разработчики получили возможность полностью реализовать в нем объектно-ориентированную модель. Основной структурной единицей Java-программы является класс, содержащий данные и код. Более того, в Java весь код программы должен находиться внутри одного или нескольких классов. Поддерживаются все компоненты объектно-ориентированной модели: инкапсуляция, наследование, полиморфизм.
Т.к. программы, написанные на Java, по замыслу разработчиков должны выполняться на самых разных платформах, повышенное внимание при разработке языка было уделено обеспечению устойчивости (надежности) кода, написанного на Java. Из-за необходимости обеспечения надежности кода, в Java отсутствуют некоторые конструкции, которые особенно часто становятся источниками ошибок (например, указатели, адресная арифметика). С другой стороны, в Java поддерживаются технологии, позволяющие избегать многих распространенных ошибок, возникающих во время выполнения программы (run-time errors). Большинство таких ошибок связаны с выделением/освобождением памяти или с возникновением исключительных ситуаций (например, деление на нуль или попытка открыть несуществующий файл). В С/С++ программисту приходится самому следить за всей используемой в программе памятью, не забывая освобождать ее по мере того, как потребность в ней отпадает. Зачастую программисты забывают освобождать выделенную память или, что еще хуже, освобождают ту память, которая все еще используется какой-либо частью программы. То же самое касается работы с файлами и другими системными ресурсами. Это приводит к возникновению «плавающих» (периодически проявляющихся) сбоев во время выполнения, причину которых очень трудно найти, особенно в большой программе. Java фактически снимает эти проблемы, обеспечивая автоматическую «сборку мусора», т.е. механизм освобождения неиспользуемой памяти, и объектно-ориентированную обработку исключительных ситуаций.
Большинству современных сетевых приложений обычно необходимо осуществлять несколько действий одновременно. В Java реализован механизм поддержки легковесных процессов-потоков (нитей). Многопоточность Java предоставляет средства создания приложений с множеством одновременно активных потоков. Для эффективной работы с потоками в Java реализован механизм семафоров и средств синхронизации потоков: библиотека языка предоставляет класс Thread, а система выполнения предоставляет средства диспетчеризации и средства, реализующие семафоры. Важно, что работа параллельных потоков с высокоуровневыми системными библиотеками Java не вызовет конфликтов: функции, предоставляемые библиотеками, доступны любым выполняющимся потокам.
Пока разрабатывался новый язык появился второй фактор, который впоследствии стал играть ключевую роль в языке Java. Началось бурное развитие Internet вообще и WWW в частности. Поскольку Internet – это распределенная система, состоящая из компьютеров различной архитектуры, работающих под управлением различных ОС, проблема переносимости программ между платформами встала очень остро. Пользователи Internet хотели бы, чтобы скачанная ими программа выполнялась у них на компьютере независимо от типа CPU и OC. Кроме того, возникла проблема обеспечения безопасности загружаемых из глобальной сети программ. Такая программа может содержать вирус или троян, который нарушит работу компьютера или получит несанкционированный доступ к частной информации пользователя.
Рассмотрим некоторые характерные особенности языка Java на примере небольшой программы.
1. В Java исходный файл называется единицей компиляции (compilation unit). Это текстовый файл, содержащий одно или несколько определений классов, внутри которых должен находиться весь код программы. Компилятор Java требует, чтобы исходный файл имел расширение .java, а его имя совпадало с именем одного из классов, описанных в этом исходном файле.
2. Строка class FirstProg определяет новый класс с именем FirstProg.
3. Строка public static void main(String args[ ]) – точка начала выполнения программы.
Все Java-программы начинают выполняться с вызова main(). Ключевое слово public – спецификатор доступа. Когда члену класса предшествует public, то к этому члену возможен доступ из кода, внешнего по отношению к классу, в котором данный метод описан. main() необходимо объявлять как public, если он должен вызываться кодом извне своего класса при старте программы. Ключевое слово static позволяет методу main() быть вызванным без наличия экземпляров данного класса. Оно необходимо, т.к. main() вызывается до того, как создается какой либо объект класса FirstProg. void() означает, что метод main() не возвращает значения.
4. String args[ ] параметры метода main() предназначенные для приема аргументов из командной строки (аналогчино argv[ ] в С++).
5. { } работают также как в С++ (блоки кода, тела классов и методов).
6. Метод main() указывает место начала выполнения Java-программы. Сложная программа может состоять из множества классов, но только в одном из них должен быть метод main(), с которого и начнется выполнение программы. Если метода main() нет ни в одном из классов (или есть несколько методом main() в разных классах), то JVM сообщит об ошибке. Функций main() может быть несколько с разным набором входных параметров и разными возвращаемыми значениями, но стартовать программа всегда будет с той функции, у которой возвращаемое значение void, а набор входных параметров String args[]. Если такой функции не будет обнаружено, то программа успешно откомпилируется, но при попытке запуска возникнет исключение (run-time error) NoSuchMetod.
7. System.out.println (“Hello, world”); - консольный вывод на экран. System – предопределенный класс, обеспечивающий доступ к системе, out – выходной поток, соединенный с консолью, println() – метод, выводящий на экран полученную им в качестве параметра строку и символ перевода строки (newline).
8. Аналогично С++, все инструкции в Java заканчиваются ; .
Для выполнения данной программы:
1. набрать текст и сохранить его в файле FirstProg.java
2. С помощью команды javac FirstProg.java откомпилировать данный файл. Будет создан файл байт-кода FirstProg.class.
3. Выполнить программу с помощью команды java FirstProg.