Пакеты
Пакет является специальным библиотечным модулем, который содержит группу классов, объединённых в одном пространстве имён. Например, существует системная библиотека android.widget, в состав которой входит класс Button. Чтобы использовать класс в программе, можно привести его полное имя android.widget.Button. Но длинные имена классов не слишком удобно использовать в коде, поэтому можно использовать ключевое слово import.
import android.widget.Button;
Теперь к классу Button можно обращаться без указания полного имени.
Использование механизма импортирования обеспечивает возможность управления пространствами имён. Предположим, что вы создали класс Cat со своим набором методов, а кто-то другой тоже создал класс с подобным именем и со своим набором методов. Если вы захотите использовать свой и чужой класс в своей программе, то возникнет конфликт имён, так как Java не сможет понять, какой класс нужно использовать для вызова метода.
Файл с исходным кодом на Java является компилируемым модулем. Имя модуля имеет расширение java, а внутри него может находиться открытый (public) класс с именем файла без расширения. Модуль может содержать один открытый класс, остальные классы не должны быть открытыми и считаются вспомогательными по отношению к главному открытому классу.
Как уже говорилось, библиотека является набором файлов с классами. Директива package должна находиться в первой незакоментированной строке файла. По правилам Java имена пакетов записываются только строчными буквами. Все классы, находящиеся внутри данного файла, будут принадлежать указанному пакету. Если оператор package не указан, то имена классов помещаются в специальный пакет без имени. Но вы должны всячески избегать подобных ситуаций.
Указывать один и тот же пакет можно в разных файлах, он просто указывает кому принадлежит класс. Поэтому, если три разных класса в трёх разных файлах указывают на один и тот же package, то это нормально.
Можно создавать иерархию пакетов через точечный оператор:
package pack1[.pack2[.pack3]]; // например package cat.body.tail;
Создание уникальных имён пакетов
Существует общепринятая схема, где первая часть имени пакета должна состоять из перевёрнутого доменного имени разработчика класса. Так как доменные имена в интернете уникальны, соблюдение этого правила обеспечивает уникальность имён пакетов и предотврати конфликты. Если у вас нет собственного доменного имени, то придумайте свою уникальную комбинацию с малой вероятностью повторения.
Доступ к членам класса
Модификаторы обеспечивают различные уровни доступа к членам класса. Пакеты также вносят свою лепту. Можно представить себе такую таблицу.
private | Модификатор не указан | protected | public | |
---|---|---|---|---|
В том же классе | Да | Да | Да | Да |
Подкласс класса этого же пакета | Нет | Да | Да | Да |
Класс из общего пакета, не являющийся подклассом | Нет | Да | Да | Да |
Подкласс класса другого пакета | Нет | Нет | Да | Да |
Класс другого пакета, не являющий подклассом класса данного пакета | Нет | Нет | Нет | Да |
Любой компонент, объявленный как public, будет доступен из любого места. Компонент, объявленный как private, не виден для компонентов, расположенных вне его класса. Если модификатор явно не указан, он видим подклассам и другим классам в данном пакете. Это стандартное поведение по умолчанию. Если нужно, чтобы компонент был видим за пределами текущего пакета, но только классам, которые являются непосредственными подклассами данного класса, то используйте protected.
Это справедливо только для членов класса. У класса можно указать только два варианта: по умолчанию (не указан) и public.
Скорее всего в Android вам не придётся иметь дело с пакетами вплотную.
Импорт
В начале статьи я говорил вам, что импорт позволяет сократить написание полного имени класса. Он создан для удобства программистов и программа может обойтись из без него. Но если не выпендриваться и использовать импорт, то вы сократите уменьшите объём вводимого кода.
Оператор import должен идти сразу после оператора package (если он есть). Кстати, имя класса можно указать явно или с помощью символа «звёздочка» (*):
import java.io.*;
Но в Android такой способ категорически не рекомендуется использовать, так как ведёт к большому потреблению ресурсов. Да и сам я не разу не видел такой способ в примерах.
Таким образом, стандартный вариант:
public class MainActivity extends Activity <>
Можно заменить на вариант, удалив строчку кода из импорта:
public class MainActivity extends android.app.Activity <>
Создание пакета
В студии создать пакет можно двумя способами. Первый — традиционный, щёлкаем правой кнопкой мыши на папке java или на существующем пакете и выбираем в меню команду New | Package.
Второй способ более хитрый — когда вы создаёте в студии новый класс, то указывая его имя можете использовать точечную нотацию, например, database.CatDB. В этом случае пакет database будет создан автоматически и в нём будет находиться создаваемый класс.
Пакеты — Java: Введение в ООП
Реальные программы на Java состоят из сотен и тысяч классов! Часть этих классов добавляется программистами проекта, но многие приходят вместе с библиотеками, используемыми внутри. Например, только библиотека Apache Commons Lang включает в себя около сотни классов.
Если быть точными, то речь идет и про классы и интерфейсы, но чтобы постоянно не повторяться, в этом уроке будут упоминаться только классы, хотя все это относится и к интерфейсам тоже
При таких размерах легко возникают ситуации, когда разные программисты создают классы с одинаковыми именами. Если два таких класса окажутся внутри одного проекта, то он перестанет компилироваться. Иногда мы можем просто переименовать один из классов, но что если классы пришли из библиотек, которые мы используем? Здесь уже без вариантов.
Проблема конфликта имен актуальна для всех языков программирования и решение у всех примерно одинаковое. Для этого вводится система модулей, которая позволяет изолировать классы разных проектов, даже если у них одинаковые имена. В Java такая система называется пакетами.
Использование пакетов
Пакеты позволяют группировать похожие классы или даже отдельные проекты. Даже стандартная библиотека Java это не просто набор классов, это набор пакетов, внутри которых уже находятся классы. Например, встроенный пакет java.time содержит классы для работы с датой и временем:
// Импорт позволяет обращаться по прямому имени import java.time.LocalDate; import java.time.Month; import java.time.temporal.ChronoUnit; public class App public static void main(String[] args) LocalDate dateFrom = LocalDate.of(2017, Month.MAY, 24); LocalDate dateTo = LocalDate.of(2017, Month.JULY, 29); long noOfDaysBetween = ChronoUnit.DAYS.between(dateFrom, dateTo); System.out.println(noOfDaysBetween); > >
В коде выше импортируется три класса из пакета java.time. Причем один из них из вложенного пакета java.time.temporal. Импортирование позволяет обращаться к классу по его имени, иначе пришлось бы писать полное имя (fully qualified): java.time.LocalDate.of(. ) . Так тоже можно, но код получается захламленным, его сложнее читать.
Существует еще один способ импорта – с помощью * . Тогда код будет выглядеть немного по-другому:
import java.time.*; import java.time.temporal.*; public class App public static void main(String[] args) LocalDate dateFrom = LocalDate.of(2017, Month.MAY, 24); LocalDate dateTo = LocalDate.of(2017, Month.JULY, 29); long noOfDaysBetween = ChronoUnit.DAYS.between(dateFrom, dateTo); System.out.println(noOfDaysBetween); > >
* импортирует весь пакет целиком, то есть внутри класса мы можем обратиться ко всем классам импортируемого пакета напрямую. Может показаться, что такой способ удобнее всего, так как не нужно импортировать каждый класс по отдельности. Но тогда возникает две проблемы:
- Импортируемые классы из разных мест могут пересечься по именам
- Непонятно, кто и откуда был импортирован
Поэтому актуальны все способы и конкретный вариант импорта зависит от ситуации. Правда, обычно об этом думать не надо, так как импорты проставляются редактором автоматически.
Помимо java.time в Java еще есть множество других пакетов, например java.nio, java.util, java.net и другие. А, поскольку язык развивается, то какие-то пакеты и классы устаревают и не рекомендуются к использованию. Не удивляйтесь наличию примерно одинаковых классов, которые делают примерно одно и тоже. Если какой-то класс или пакет устарел, об этом обязательно укажут в документации.
Встроенные пакеты легко распознать по имени, они все начинаются со слова java. Но пакеты бывают и пользовательские. Фактически весь остальной код приложений и библиотек находится внутри своих пакетов. И мы снова приходим к проблеме конфликтов имен, но здесь уже не все так страшно. Пакетов значительно меньше чем классов и, как правило, они содержат какой-то префикс, который закреплен за конкретной компанией или продуктом. Например, пакеты организации Apache начинаются с org.apache, то есть это имя домена в обратном порядке. Повторить такое название технически можно, но никто не будет сам себе стрелять в ногу.
org.apache это пакет apache вложенный в пакет org. Как не трудно догадаться имя org может быть использовано разными компаниями, например org.w3c. Такая ситуация допустима, так как классы лежат дальше, уже внутри вложенных пакетов, которые точно уникальны.
// Класс генерирующий рандомные числа из пакета org.apache.commons.lang3 // Установку этого пакета в систему мы рассматриваем в другом курсе import org.apache.commons.lang3.RandomUtils; public class App public static void main(String[] args) var x = RandomUtils.nextInt(1, 1000); > >
Помимо разрешения конфликтов имен пакеты выполняют еще одну функцию — контроль доступа. По умолчанию все классы внутри пакета доступны только классам этого же пакета. Для доступа снаружи их нужно помечать публичными.
Определение пакетов
Структура пакетов связана со структурой директорий. Если пакет называется org.apache.commons.lang3, то путь к нему будет таким org/apache/commons/lang3. Имя пакета всегда соответствует директории, если пакет вложенный, то и директория тоже вложенная. В конце цепочки всегда файлы, в которых находятся классы. Их легко определить по названию, имена пакетов всегда идут с маленькой буквы, тогда как классов с заглавной. Пример создания пакета:
// io/hexlet/Course.java package io.hexlet; public class Course // Тут логика > // com/google/App.java package com.google; import io.hexlet.Course; public class App public static void main(String args[]) var course = new Course("Java"); > >
Классы находящиеся в одном пакете видят друг друга без импортов:
// io/hexlet/Lesson.java package io.hexlet; public class Lesson private Course course; // остальной код >
Здесь может возникнуть вопрос, а по какому принципу раскладывается код по пакетам и вложенным пакетам? Классы стараются группировать по смыслу, но в реальности все зависит от представлений о прекрасном у конкретного разработчика, который этим занимается. Со временем и у вас разовьется это чувство, когда появится насмотренность.
Статический импорт
Java позволяет импортировать и использовать статические методы и свойства без указания самого класса:
import static java.lang.System.*; class App public static void main(String args[]) // Можем опустить System out.println("GeeksforGeeks");
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Пакеты — Основы Java
Реальные программы на Java состоят из сотен и тысяч классов. При таких размерах легко возникают ситуации, когда создаются классы с одинаковыми именами. Если два таких класса окажутся внутри одного проекта, то он перестанет компилироваться.
Для решения проблемы конфликта имен вводится система пакетов. Пакеты позволяют группировать похожие классы.
Определение пакетов
Структура пакетов тесно связана со структурой директорий. Как правило, структура пакетов соответствует файловой структуре директорий проекта, в которых находится файлы с исходным кодом. Например, если классы размещены в пакете example.package1 , то и файлы в проекте должны быть расположены в директории example/package1. Некоторые IDE, например популярная IntelliJ IDEA, при создании пакета автоматически создают соответствующую файловую структуру в директории проекта
Здесь имя User — это так называемое простое имя класса. А полным именем класса считается имя, состоящее из всех пакетов, перечисленных через точку, и простого имени класса. Например, полные имена для классов User будут такими: example.package1.User и example.package2.User . Теперь проблема одинаковых имён классов в большом проекте решена, так как в разных пакетах могут находиться классы с одинаковым простым именем
Для примера в пакете example.package1 создадим класс User , который будет описывать методы для работы с пользователем:
// Файл src/main/java/example/package1/User.java // Именовать пакет начинаем от директории src/main/java/, // в которой расположен корневой пакет package example.package1; class User public static String getGreeting(String userName) return "Hello, " + userName + "!"; > >
Используем этот класс в том же пакете:
// Файл src/main/java/example/package1/App.java // Класс расположен в том же пакете, что и класс User package example.package1; class App public static void main(String[] args) // Внутри своего пакета класс можно использовать, // обратившись к нему по простому имени var greeting = User.getGreeting("John"); System.out.println(greeting); // => Hello, John! > >
Внутри своего пакета можно обращаться к классу по его простому имени. Компилятор поймет, что мы хотим использовать класс User , расположенный в том же пакете. Но в разработке постоянно приходится использовать классы из других пакетов. Помимо разрешения конфликтов имен, пакеты выполняют еще одну функцию — контроль доступа.
Контроль доступа
По умолчанию все классы внутри пакета доступны только классам этого же пакета. Чтобы получить доступ к классу снаружи, из другого пакета, этот класс нужно сделать публичным. Вернемся к нашему примеру с пользователем и сделаем класс User в пакете example.package1 публичным
package example.package1; // К определению класса добавляем модификатор public // Теперь класс User становится публичным // и к нему можно обратиться из другого пакета public class User public static String getGreeting(String userName) return "Hello, " + userName + "!"; > >
Используем класс User в другом пакете. Чтобы использовать класс в другом пакете, нужно обратиться к нему по его полному имени, чтобы однозначно указать компилятору, какой именно класс мы хотим использовать:
// Файл src/main/java/example/App.java // Уже другой пакет package example; class App public static void main(String[] args) // Обращаемся по полному имена класса var greeting = example.package1.User.getGreeting("John"); System.out.println(greeting); // => Hello, John! > >
Постоянно писать полное имя класса может быть не удобно. На деле чаще всего поступают иначе. Чтобы каждый раз не писать полное имя класса, мы можем импортировать этот класс, после чего в коде можно будет обращаться к нему по простому имени. Чтобы импортировать класс, нужно использовать ключевое слово import , после которого указать полное имя класса, который мы хотим импортировать
package example; // Импортируем класс User из пакета example.package1 import example.package1.User; class App public static void main(String[] args) // Теперь класс можно использовать, обратившись к нему по простому имени var greeting = User.getGreeting("John"); System.out.println(greeting); // => Hello, John! > >
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Пакеты (packages)
— Файлы в компьютере группируются по папкам. Классы в Java (а каждый класс лежит в отдельном файле) группируются по пакетам, которые являются папками на диске. Ничего принципиально нового. Но есть два замечания
— Первое. «Полным уникальным именем класса» является «имя пакета» + «имя класса». Примеры:
Полное уникальное имя | Имя пакета | Имя класса |
---|---|---|
java.io.FileInputStream | java.io | FileInputStream |
java.lang.String | java.lang | String |
java.util.ArrayList | java.util | ArrayList |
org.apache.tomcat.Servlet | org.apache.tomcat | Servlet |
Cat | отсутствует | Cat |
— Полное имя класса всегда уникально!
— Каждый раз писать длинное имя, например java.util.ArrayList, очень неудобно. Поэтому в Java добавили возможность «импортировать классы». В своем коде ты можешь пользоваться коротким именем других классов, но ты должен в начале своего класса явно указать, какой именно класс будет использоваться.
— А как это сделать?
— Делается это конструкцией вида « import java.util.ArrayList; »
— В начале класса, сразу после объявления package, ты можешь указать какой именно класс скрывается за ArrayList, который ты используешь у себя в коде.
— Зачем такая сложность? Что могут быть классы с одинаковыми именами?
— Да, в разных пакетах могут лежать классы с одинаковыми именами. Но мы не можем импортировать в наш класс два класса с одинаковыми именами , поэтому к одному из них придётся обращаться по полному имени.
— Вот еще одна аналогия. У тебя в коллективе есть Серега и никаких проблем с общением – все знают кто это. Но если бы их было трое, то чтобы их различать пришлось бы использовать полные уникальные имена.
— Второе. Лучше всегда класть классы в пакеты, а не в корень папки src . Когда классов мало, это ещё не представляет проблему, но когда классов много – очень легко запутаться. Поэтому всегда создавай классы только в пакетах.
В Java принято давать классам и пакетам осмысленные имена. Многие компании выпускают свои библиотеки (набор классов) и, чтобы не было путаницы, называют пакеты этих классов по имени компании/сайта:
Имя пакета | Имя компании/проекта |
---|---|
org.apache.common org.apache.tomcat org.apache.util |
Проект «Апач» |
com.oracle.jdbc | Компания «Oracle» |
java.io javax.servlet |
Компания Sun, проект Java |
com.ibm.websphere | Компания «IBM», проект WebSphere |
com.jboss | Проект «Jboss» |