Чем обусловлена структура Java?


Как вы уже слышали, Java проектировалась с рассчётом на совместимость со всем, чем только можно. Такое ограничение вынудило разработчиков Java сделать её такой, чтобы максимально упрос��ить развёртывание приложений, при этом обеспечив логическую стройность языка.

Как происходит загрузка классов?


Для того, чтобы найти класс по имени когда вы его вызываете, в Java существует стандартный загрузчик классов. Он оперирует понятием classpath. Список classpath — это набор путей, где следует искать файлы классов. Каждый classpath может указывать как на директорию, так и на так называемый jar-файл (зазипованная директория со скомпилированными .class'ами и разрешением .jar, типа «йА java-archive!»). По умолчанию в classpath входят файлы стандартных библиотек и директория, из которой вы вызвали саму Java. Именно таким образом был найден класс HelloWorld — java нашла файл HelloWorld.class и запустила в нём метод main. Собственно, так и работают большинство программ, даже самых сложных. Всё начинается с одного main'а…

Пакеты классов


Пакет (package) представляют собой набор классов, объединённых по смыслу. Пакеты обычно вкладываются друг в друга, образуя собо иерархию, дающую понять, что зачем. На файловой системе такая иерархия выглядит в виде вложенных друг в друга директорий с исходниками. Так, исходники пакета a лежат в папке a, исходники пакета a.b — в папке a/b и так далее. Типичный путь к пакету выглядит примерно так:
org.apache.commons.collectons. Видите, сразу ясно зачем он нужен. Чтобы использовать какой-то класс в коде другого класса, вы должны импортировать его, написав до объявления класса строку
import путь.к.классу.ИмяКласса;
Кроме того, если вы используете классы одного пакета часто, вы можете импортировать весь пакет:
import путь.к.классу.*;
Это относится ко всем пакетам, кроме java.lang — он импортирован по умолчанию, именно из него были в прошлом примере взяты классы System и String. На самом деле они лежат в некоем jar'е, в каталоге java/lang.

Что ж, теперь вы знаете как работает загрузчик классов. В реальных проектов количество classpath измеряется десятками, а то и сотнями.

Организация кода


Если вы пишете свои первые маленькие примерчики и вам лень создавать иерархию классов — пусть, это ваше право. Но помните, в серьёзном проекте вы всегда должны будете разложить свои классы по пакетам. Обычно корневые пакеты создаются такими, чтобы ясно давать понять кто автор кода, и к чему он относится.
Например:
ru.vasiapupkin.photomaker выбирается корневым пакетом
ru.vasiapupkin.photomaker.core сюда мы пишем классы отвечающие за логику
ru.vasiapupkin.photomaker.visual сюда, допустим, все наши окошки приложения

и так далее.
Чтобы создать класс
ru.vasiapupkin.photomaker.Starter
вы должны:
создать файл Starter.java в папке ru/vasiapupkin/photomaker/
прописать в нём первой строчкой (точнее говоря, до импортов)
package ru.vasiapupkin.photomaker;

Коллижн


«А что будет, если у нас будет два класса с одним именем?», — спросите вы. «Смотрите», — отвечу я.
Допустим вы решили что вы умнее джавы и создали свой класс строки — String. Но вот проблема, у нас же уже есть такой!
Значит, вам придётся положить свой класс в пакет, скажем ru.vp.stuff и обращаться к нему так: ru.vp.stuff.String.
Именно поэтому не рекомендуется класть классы прямо в корень classpath — таким образом вы роете себе дорогу к несовместимости, ведь Java требует, чтобы каждый класс определялся однозначно. Именно поэтому нельзя написать так:
import ru.vp.SuperClass;
import ru.mashka.SuperClass;

За это вас накажет компилятор, потому что он не будет знать, какой из них использовать.
Мораль: правильно выбирайте и имя класс и имя пакета.

Погоняем?


Давайте улучшим первое приложение. Эх, классика интернета… Создадим апплет.

Эх, может быть апплетами...


import java.applet.Applet;
import java.awt.Graphics;

public class HelloWorld extends Applet{

    public void paint(Graphics g){
        g.drawString("Hello World",15,15);
    }

}

* This source code was highlighted with Source Code Highlighter.


Так, что у нас тут? Импортировано 2 класса, один из них — стандартный пустой апплет, который мы будем расширять. Второй — Graphics. Graphics — это понятие из библиотеки AWT. Кстати, небольшой экскурс. AWT (Abstract Window Toolkit) входил ещё в первую Java и был предназначен для многих задач, связанных в основном с отображением.
Так вот, объект типа Graphics позволяет нам рисовать на себе всякую муру типа строк, линий, кружочков и прочего. В данном примере мы написали строчку с отступом.
Метод paint здесь написан не от балды — он перекрывает аналогичный метод класса Applet, и когда java будет перерисовывать этот конкретный апплет, она вызовет этот метод.

Посмотреть на наш ап��лет достаточно просто — пишем небольшой HTML:
<body>
<applet code="HelloWorld.class" codebase="file:///home/devgru/" width="150" height="30"></applet>
</body>

* This source code was highlighted with Source Code Highlighter.


… а может приложением...


Давайте попробуем сделать HelloWorld в standalone-приложении.

import java.awt.*;
import javax.swing.*;
public class HelloWorld extends JFrame{

    public static void main(String[] args){
        new HelloWorld();
    }

    {
        add(new JLabel("Hello world"));
        setSize(200,200);
        setVisible(true);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }
}       


* This source code was highlighted with Source Code Highlighter.

Здесь мы полностью импортируем основные классы пакетов Swing и AWT. Swing — более поздняя чем AWT библиотека, сейчас именно она обеспечивает отображение основной части графического интерфейса для Java-приложений.
Итак, в main мы просто создаём экземпляр класса HelloWorld.
Сейчас наш класс наследуется от класса JFrame. Это класс из Swing, он представляет собой окно, которое отображается пока не будет закрыто.
Блок {...} — это «общий конструктор». Он добавляется к любому конструктору нашего класса. Так как у нас нет ни одного — он добавляется к пустому конструктору без параметров, который создаётся на лету, если у класса нет ни одного.
Мы добавляем на окно новый объект типа JLabel (т.е. надпись), затем устанавливаем окну размеры и отображаем его. Последняя строчка нужна, чтобы выполнение приложения закончилось, когда будет закрыто окно. Таким образом, вы можете быть уверены что после закрытия окна у вас в памяти не останется висеть ваше приложение.
Запускать его нужно точно так же как и прошлое: пишем, компилируем, запускаем.

А может и сервлетами? Наверное, потом.


В этих двух статьях я постарался дать вам начальное представление о возможностях Java в общем. За рамками сегодняшней статьи (наверное, будут в завтрашней) остались сервлеты и прочие радости серверной части типа JSP-страниц, а также МИДлеты — приложения для мобилок. Я бы мог рассмотреть и то и то, но хотел бы знать, чего больше хотят читатели. Кроме того, возможно, нужно рассказать о самых основах языка. Примерно на том же уровне подробности, что и начало этой статьи. Напишите в комментариях, какую статью вы хотели бы видеть в следующий раз:
— классы и интерфейсы: ООП в джаве;
— буквы-цифры-строчки: работа с базовыми типами;
— создание оконных приложений с помощью Swing;
— от мала до велика: сервлеты, мидлеты и 2 слова о портлетах.

Когда отпишетесь — станет ясно, куда копать дальше. Всем спасибо за внимание.

Ссылка для тех, кому лень ждать завтра: основы языка (eng.).