Пакеты (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» |
Кофе-брейк #165. Пакеты на языке Java. Потокобезопасные методы для начинающих
Источник: Usemynotes Эта публикация поможет вам лучше изучить пакеты в Java, понять их предназначение и способы реализации.
Что такое пакеты в Java
Пакет (Package) в Java — это способ объединить группу классов, интерфейсов и подпакетов. С помощью пакетов создаются группы связанных классов, интерфейсов, перечислений и так далее. Подпакеты — это пакеты, находящиеся в другом пакете. Они не импортируются по умолчанию, но при необходимости их можно импортировать вручную. Спецификация доступа не предоставляется отдельным членам подпакета, они рассматриваются как разные пакеты.
Некоторые виды пакетов в Java:
- java.lang — по умолчанию поставляется в комплекте с Java.
- java.io — содержит классы, методы и другие элементы, связанные с вводом-выводом.
Зачем нужны пакеты?
- Во избежание конфликтов имен.
- Для обеспечения контролируемого доступа.
- Чтобы добиться инкапсуляции данных.
Как создать пакет в Java?
Давайте создадим пакет с именем computer . Обычно имя пакета пишется строчными буквами. Это делается только для того, чтобы избежать конфликтов имен с именами классов. Также мы создадим интерфейс с именем Pluggable , который будет находиться в пакете computer .
package computer; interface Pluggable
Теперь мы создадим класс с именем PenDrive , который будет реализовывать вышеуказанный интерфейс.
package computer; public class PenDrive implements Pluggable < int storage = 64; public void pluggedIn () < System.out.println("Pen Drive is connected"); >public void pluggedOut () < System.out.println("Pen Drive is removed"); >public int storage() < return storage; >public static void main(String args[]) < PenDrive p = new PenDrive (); p.pluggedIn(); System.out.println("Pen Drive Storage: " + p.storage()); p.pluggedOut(); >>
Как создать иерархию пакетов в Java?
При формировании иерархии пакеты в Java именуются в обратном порядке. Это делает их очень похожими на каталоги или папки. Также как и на персональном компьютере, где внутри одной папки может содержаться одна или несколько подпапок, то же самое применимо и к пакетам в Java. Давайте рассмотрим пакет с именем Asia.India.Kolkata . Все это существующие папки, но если учесть географию, то понятно, что Калькутта находится в Индии, а Индия находится в Азии. Основной цель иерархии — облегчить поиск классов.
Типы пакетов в Java
Встроенные пакеты (Built-in Packages)
- java.util — этот пакет содержит конечное количество служебных классов, которые используются для реализации структур данных, таких как связанный список, наборы и так далее. Он также поддерживает операции с датой и временем и многое другое.
- java.net — он содержит классы, используемые для сетевых операций.
Пользовательские пакеты (User-defined packages)
Пакеты, определяемые пользователем, называются пользовательскими пакетами. Пользователь может вручную создать пакет и иметь в нем столько классов, сколько захочет.
Как получить доступ к пакету из другого пакета?
- Использование звездочки в операторе импорта
import tools.*;
- Использование импорта package.ClassName;
import book.Pages;
- Использование полного имени
java.awt.List aSimpleList = new java.awt.List();
Размер пакета по умолчанию в Java
По умолчанию Java импортирует пакет java.lang . Он имеет много классов, которые обычно используются в простых программах Java, таких как String , Integer и других. Одним из наиболее важных классов является класс Object , который, в свою очередь, также находится в пакете java.lang . Размер этого пакета основан на его составляющих: 8 интерфейсов, 37 классов, 3 перечисления, 27 исключений, 23 типа ошибок и 5 типов аннотаций.
Потокобезопасные методы Java для начинающих
Источник: Medium Используя эту статью, вы сможете узнать о работе потокобезопасных методов в Java. Я обнаружил, что многие junior/middle Java-разработчики неправильно понимают, как должны работать потокобезопасные (thread-safety) методы в реальных проектах. А поскольку мы обычно работаем в многопоточной среде, то правильное их использование очень важно. Потокобезопасный метод — это метод, который можно вызывать из нескольких потоков одновременно, не влияя на состояние данных друг друга. Недостаточное понимание этой концепции приводит к появлению багов, которые сложно найти и исправить. Чтобы избегать таких ошибок, давайте посмотрим на примеры.
Пример №1:
public static int countLetters(String input) < int counter = 0; for (Character c : input.toCharArray()) < if (Character.isAlphabetic(c)) < counter++; >> return counter; >
- Метод countLetters является статическим, он возвращает значение int и принимает ввод строкового параметра.
- Внутри метода создается примитивный счетчик переменных, затем цикл перебирает символы входной строки и увеличивает счетчик переменных каждый раз, когда встречается буквенный символ.
Пример №2:
public static int countLetters2(String input) < ListlistCounter = new ArrayList<>(); for (Character c : input.toCharArray()) < if (Character.isAlphabetic(c)) < listCounter.add(c); >> return listCounter.size(); >
В этом коде использовалась та же логика, что и в первом примере, но здесь вместо примитивной переменной int использовался объект List . Из предыдущей части мы знаем, что объекты в Java хранятся в куче, а List — это объект. Также мы знаем, что стек хранит ссылки на объекты в куче. В примере №2 каждый поток создает новый объект ArrayList : а переменная listCounter хранит ссылку на свой объект в куче, поэтому никакой другой поток не может изменить этот объект.
List listCounter = new ArrayList<>();
Это означает, что этот метод является потокобезопасным.
Пример №3:
public class CounterUtil < // singleton ListlistCounter = new ArrayList<>(); public int countLetters3(String input) < for (Character c : input.toCharArray()) < if (Character.isAlphabetic(c)) < listCounter.add(c); >> return listCounter.size(); > >
В этом примере у нас есть одноэлементный (это важно) класс CounterUtil с глобальной переменной listCounter . Эта переменная создается одновременно с экземпляром синглтона. Когда несколько потоков вызывают метод countChars3 , все они используют одну и ту же глобальную переменную listCounter , которая сохраняет ссылку на один и тот же объект в куче, и потоки там будут влиять друг на друга. Поэтому мы можем сделать вывод, что этот метод не является потокобезопасным. И даже если мы поменяем List
Последний пример:
public static int countLetters4(List inputList) < ListlistCounter = new ArrayList<>(); for (Character c : inputList) < if (Character.isAlphabetic(c)) < listCounter.add(c); >> return listCounter.size(); >
Метод countLetters4 принимает список символов вместо параметра String . Здесь мы не можем гарантировать , что этот метод является потокобезопасным. Почему? Потому что мы не можем быть уверены, как разработчики будут использовать этот метод. Если другой поток извне изменит данные в inputList одновременно с нашим методом counterLetters4 , это может повлиять на окончательный результат.
Заключение
Мы рассмотрели только четыре примера, и они не охватывают все аспекты безопасности потоков в Java-проектах, но это хорошее начало для практики. В следующий раз, когда вы увидите какой-либо метод в своем коде, спросите себя: “Этот метод потокобезопасен?”. И очень скоро вы четко будете понимать ответ.
При подготовке материала использовались источники:
https://javarush.com/quests/lectures/questsyntax.level05.lecture02
https://javarush.com/groups/posts/3948-kofe-breyk-165-paketih-na-jazihke-java-potokobezopasnihe-metodih-dlja-nachinajujshikh