Перейти к основному содержимому

Руководство по созданию объектов в Java

· 7 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

Проще говоря, прежде чем мы сможем работать с объектом в JVM, его необходимо инициализировать.

В следующих разделах мы рассмотрим различные способы инициализации примитивных типов и объектов.

2. Декларация против инициализации

Начнем с того, что убедимся, что мы на одной странице.

Объявление — это процесс определения переменной вместе с ее типом и именем.

Здесь мы объявляем переменную id :

int id;

Инициализация, с другой стороны, заключается в присвоении значения; Например:

id = 1;

Для демонстрации мы создадим класс User со свойствами имени и идентификатора :

public class User {
private String name;
private int id;

// standard constructor, getters, setters,
}

Далее мы увидим, что инициализация работает по-разному в зависимости от типа поля, которое мы инициализируем.

3. Объекты против примитивов

Java предоставляет два типа представления данных: примитивные типы и ссылочные типы. В этом разделе мы обсудим различия между ними в отношении инициализации.

Java имеет восемь встроенных типов данных, называемых примитивными типами Java; переменные этого типа хранят свои значения напрямую.

Ссылочные типы содержат ссылки на объекты (экземпляры классов). В отличие от примитивных типов, которые хранят свои значения в памяти, где размещена переменная, ссылки не содержат значения объекта, на который они ссылаются.

Вместо этого ссылка указывает на объект, сохраняя адрес памяти, где находится объект.

Обратите внимание, что Java не позволяет нам узнать, что такое адрес физической памяти. Скорее, мы можем использовать ссылку только для ссылки на объект.

Давайте посмотрим на пример, который объявляет и инициализирует ссылочный тип из нашего класса User :

@Test
public void whenIntializedWithNew_thenInstanceIsNotNull() {
User user = new User();

assertThat(user).isNotNull();
}

Как мы видим здесь, ссылку на новый можно назначить с помощью ключевого слова new, которое отвечает за создание нового объекта User .

Давайте продолжим изучение создания объектов.

5. Создание объектов

В отличие от примитивов, создание объектов немного сложнее. Это потому, что мы не просто добавляем значение в поле; вместо этого мы запускаем инициализацию с помощью нового ключевого слова. Это, в свою очередь, вызывает конструктор и инициализирует объект в памяти.

Давайте обсудим конструкторы и новое ключевое слово более подробно.

Ключевое слово new отвечает за выделение памяти для нового объекта через конструктор.

Конструктор обычно используется для инициализации переменных экземпляра, представляющих основные свойства созданного объекта .

Если мы не укажем конструктор явно, компилятор создаст конструктор по умолчанию, который не имеет аргументов и просто выделяет память для объекта.

Класс может иметь много конструкторов, если их списки параметров различаются ( перегрузка ) . Каждый конструктор, который не вызывает другой конструктор в том же классе, имеет вызов своего родительского конструктора, независимо от того, был ли он написан явно или вставлен компилятором через super() .

Давайте добавим конструктор в наш класс User :

public User(String name, int id) {
this.name = name;
this.id = id;
}

Теперь мы можем использовать наш конструктор для создания объекта User с начальными значениями его свойств:

User user = new User("Alice", 1);

6. Область действия переменной

В следующих разделах мы рассмотрим различные типы областей видимости, в которых может существовать переменная в Java, и то, как это влияет на процесс инициализации.

6.1. Переменные экземпляра и класса

Переменные экземпляра и класса не требуют от нас их инициализации. Как только мы объявляем эти переменные, им присваивается значение по умолчанию следующим образом:

./c8694eba2735cac9a14aab2f18cf0f21.png

Теперь давайте попробуем определить некоторые переменные, связанные с экземпляром и классом, и проверить, имеют ли они значение по умолчанию или нет:

@Test
public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() {
User user = new User();

assertThat(user.getName()).isNull();
assertThat(user.getId() == 0);
}

6.2. Локальные переменные

Локальные переменные должны быть инициализированы перед использованием , так как они не имеют значения по умолчанию, и компилятор не позволит нам использовать неинициализированное значение.

Например, следующий код генерирует ошибку компилятора:

public void print(){
int i;
System.out.println(i);
}

7. Последнее ключевое слово

Последнее ключевое слово, примененное к полю, означает, что значение поля больше не может быть изменено после инициализации. Таким образом, мы можем определить константы в Java.

Давайте добавим константу в наш класс User :

private static final int YEAR = 2000;

Константы должны быть инициализированы либо при их объявлении, либо в конструкторе.

8. Инициализаторы в Java

В Java инициализатор — это блок кода, который не имеет связанного имени или типа данных и размещается вне любого метода, конструктора или другого блока кода.

Java предлагает два типа инициализаторов: статические и экземплярные. Давайте посмотрим, как мы можем использовать каждый из них.

8.1. Инициализаторы экземпляра

Мы можем использовать их для инициализации переменных экземпляра.

Чтобы продемонстрировать, давайте предоставим значение для идентификатора пользователя , используя инициализатор экземпляра в нашем классе User :

{
id = 0;
}

8.2. Статический блок инициализации

Статический инициализатор или статический блок — это блок кода, который используется для инициализации статических полей. Другими словами, это простой инициализатор, помеченный ключевым словом static:

private static String forum;
static {
forum = "Java";
}

9. Порядок инициализации

При написании кода, который инициализирует различные типы полей, конечно, мы должны следить за порядком инициализации.

В Java порядок операторов инициализации следующий:

  • статические переменные и статические инициализаторы по порядку
  • переменные экземпляра и инициализаторы экземпляра по порядку
  • конструкторы

10. Жизненный цикл объекта

Теперь, когда мы узнали, как объявлять и инициализировать объекты, давайте узнаем, что происходит с объектами, когда они не используются.

В отличие от других языков, где нам приходится беспокоиться об уничтожении объектов, Java заботится об устаревших объектах с помощью своего сборщика мусора.

Все объекты в Java хранятся в куче памяти нашей программы . По сути, куча представляет собой большой пул неиспользуемой памяти, выделенной для нашего Java-приложения.

С другой стороны, сборщик мусора — это программа на языке Java, которая обеспечивает автоматическое управление памятью , удаляя недоступные объекты.

Чтобы объект Java стал недоступным, он должен столкнуться с одной из следующих ситуаций:

  • Объект больше не имеет ссылок, указывающих на него
  • Все ссылки, указывающие на объект, выходят за рамки

В заключение, объект сначала создается из класса, обычно с использованием ключевого слова new. Затем объект живет своей жизнью и предоставляет нам доступ к своим методам и полям.

Наконец, когда он больше не нужен, сборщик мусора уничтожает его.

11. Другие методы создания объектов

В этом разделе мы кратко рассмотрим методы, отличные от ключевого слова new , для создания объектов и способы их применения, в частности, отражение, клонирование и сериализацию .

Отражение — это механизм, который мы можем использовать для проверки классов, полей и методов во время выполнения. Вот пример создания нашего объекта User с использованием отражения:

@Test
public void whenInitializedWithReflection_thenInstanceIsNotNull()
throws Exception {
User user = User.class.getConstructor(String.class, int.class)
.newInstance("Alice", 2);

assertThat(user).isNotNull();
}

В этом случае мы используем отражение, чтобы найти и вызвать конструктор класса User .

Следующий метод — клонирование — это способ создания точной копии объекта. Для этого наш класс User должен реализовать интерфейс Cloneable :

public class User implements Cloneable { //... }

Теперь мы можем использовать метод clone() для создания нового объекта clonedUser , который имеет те же значения свойств, что и объект пользователя :

@Test
public void whenCopiedWithClone_thenExactMatchIsCreated()
throws CloneNotSupportedException {
User user = new User("Alice", 3);
User clonedUser = (User) user.clone();

assertThat(clonedUser).isEqualTo(user);
}

Мы также можем использовать класс sun.misc.Unsafe для выделения памяти для объекта без вызова конструктора:

User u = (User) unsafeInstance.allocateInstance(User.class);

12. Заключение

В этом руководстве мы рассмотрели инициализацию полей в Java. Мы обнаружили различные типы данных в Java и способы их использования. Мы также подробно рассмотрели несколько способов создания объектов в Java.

Полную реализацию этого руководства можно найти на Github .