Что сериализуется и что нет
Сериализуемое состояние
Механизм нативной сериализации записывает состояние экземпляра объекта — значения всех полей экземпляра, за исключением тех, что явно исключены. Это включает:
Поля всех уровней доступности:
Поля примитивных типов: их значения записываются в бинарном виде.
Поля ссылочных типов: объекты, на которые ссылаются поля, сериализуются рекурсивно. Если поле ссылается на другой объект, механизм обходит ссылку и сериализует целевой объект, затем возвращается к текущему.
При сериализации
Что не сериализуется
Статические поля не сериализуются. Они принадлежат классу, а не экземпляру, и их значения хранятся в Metaspace (в структурах класса), а не в куче вместе с объектом. При десериализации статические поля получают текущие значения, определённые в загруженном классе, а не значения из потока.
Это логично: если бы статические поля сериализовались, восстановление объекта на другой JVM с другим состоянием класса привело бы к конфликтам.
Transient-поля явно исключаются из сериализации. Ключевое слово
Важно:
Поля-суперклассы
Если класс реализует
При десериализации
Механизм обхода графа объектов
Отслеживание ссылок и циклы
Ключевая особенность: каждый объект в графе записывается ровно один раз. Для этого
Объект записывается полностью (дескриптор класса + поля).
Объекту присваивается handle — следующее свободное целое число.
Handle сохраняется в таблице.
При повторной встрече того же объекта (через другую ссылку или в цикле):
В поток записывается маркер backreference (TC_REFERENCE) + handle ранее записанного объекта.
Полная сериализация не выполняется.
Этот механизм предотвращает бесконечную рекурсию при циклических ссылках и гарантирует, что после десериализации топология графа сохранится:
Handle (в контексте сериализации Java) — это целочисленный идентификатор, присваиваемый каждому уникальному объекту в потоке сериализации. Handles начинаются с базового значения (обычно
#Java #для_новичков #beginner #IO #NIO #Serialize
Сериализуемое состояние
Механизм нативной сериализации записывает состояние экземпляра объекта — значения всех полей экземпляра, за исключением тех, что явно исключены. Это включает:
Поля всех уровней доступности:
public, protected, package-private и private. Сериализация обходит модификаторы доступа через механизм reflection или нативный доступ JNI, поэтому приватные поля сохраняются и восстанавливаются без геттеров и сеттеров.Поля примитивных типов: их значения записываются в бинарном виде.
Поля ссылочных типов: объекты, на которые ссылаются поля, сериализуются рекурсивно. Если поле ссылается на другой объект, механизм обходит ссылку и сериализует целевой объект, затем возвращается к текущему.
public class Library implements Serializable {
private String name;
private List<Book> books; // Book тоже должен быть Serializable
private Librarian head; // Librarian тоже должен быть Serializable
}При сериализации
Library механизм рекурсивно обойдёт список books: каждый элемент Book будет сериализован со своими полями, включая ссылки на Author, Publisher и т.д. Затем будет сериализован head (Librarian) со всеми его полями. Результат — глубокая копия всего графа объектов в виде потока байтов.Глубокая копия (deep copy) — это копия объекта, при которой копируются не только сам объект, но и все объекты, на которые он ссылается, рекурсивно. В отличие от поверхностной копии (shallow copy), где копируются только ссылки на те же внутренние объекты.
Что не сериализуется
Статические поля не сериализуются. Они принадлежат классу, а не экземпляру, и их значения хранятся в Metaspace (в структурах класса), а не в куче вместе с объектом. При десериализации статические поля получают текущие значения, определённые в загруженном классе, а не значения из потока.
Это логично: если бы статические поля сериализовались, восстановление объекта на другой JVM с другим состоянием класса привело бы к конфликтам.
public class Config implements Serializable {
private static String globalPrefix = "app"; // не сериализуется
private String instanceName; // сериализуется
}Transient-поля явно исключаются из сериализации. Ключевое слово
transient указывает механизму, что поле не должно быть записано в поток. При десериализации такое поле получает значение по умолчанию: null для ссылочных типов, 0 для чисел, false для boolean.public class UserSession implements Serializable {
private String username;
private transient String password; // не сериализуется
private transient Connection dbConn; // не сериализуется
private transient byte[] cachedToken; // не сериализуется
}transient используется для чувствительных данных (пароли, ключи), ресурсов, привязанных к runtime (соединения с БД, потоки, сокеты), и вычисляемых/кэшированных значений, которые можно восстановить после загрузки.Важно:
transient не влияет на видимость поля — оно остаётся приватным или публичным, просто исключается из сериализационного протокола.Поля-суперклассы
Если класс реализует
Serializable, а его суперкласс — нет, то поля суперкласса не сериализуются. При десериализации суперкласс инициализируется через свой no-arg конструктор (конструктор без аргументов). Если такого конструктора нет — InvalidClassException.public class Base { // не Serializable
private int baseField;
public Base() {} // обязателен no-arg конструктор
}
public class Derived extends Base implements Serializable {
private int derivedField; // только это поле сериализуется
}При десериализации
Derived поле baseField не восстанавливается из потока. Вместо этого вызывается Base(), и baseField получает значение по умолчанию (0), независимо от того, каким оно было при сериализации. Это частый источник багов: разработчик забывает, что суперкласс не serializable, и удивляется, почему поля предка обнуляются.No-arg конструктор (no-argument constructor, default constructor) — это конструктор без параметров. В Java, если класс не объявляет явных конструкторов, компилятор генерирует no-arg конструктор автоматически. Если объявлен хотя бы один конструктор с параметрами, no-arg конструктор нужно объявлять явно.
Механизм обхода графа объектов
ObjectOutputStream не просто записывает байты полей. Он обходит весь граф объектов, начиная с корневого, используя алгоритм, похожий на обход в ширину (BFS) или обход в глубину (DFS) с отслеживанием посещённых узлов.Отслеживание ссылок и циклы
Ключевая особенность: каждый объект в графе записывается ровно один раз. Для этого
ObjectOutputStream поддерживает внутреннюю таблицу handles — отображение от сериализованного объекта к целочисленному идентификатору (int). При первой встрече объекта:Объект записывается полностью (дескриптор класса + поля).
Объекту присваивается handle — следующее свободное целое число.
Handle сохраняется в таблице.
При повторной встрече того же объекта (через другую ссылку или в цикле):
В поток записывается маркер backreference (TC_REFERENCE) + handle ранее записанного объекта.
Полная сериализация не выполняется.
public class Node implements Serializable {
private String name;
private Node next; // может образовать цикл
}
// Создаём цикл: A -> B -> C -> A
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
a.next = b;
b.next = c;
c.next = a; // цикл!
// Сериализация не зацикливается благодаря таблице handles
oos.writeObject(a); // записывает A, B, C, затем backreference на AЭтот механизм предотвращает бесконечную рекурсию при циклических ссылках и гарантирует, что после десериализации топология графа сохранится:
c.next будет ссылаться на тот же объект a, что и корневой указатель. Без handles граф с циклами привёл бы к StackOverflowError при сериализации.Handle (в контексте сериализации Java) — это целочисленный идентификатор, присваиваемый каждому уникальному объекту в потоке сериализации. Handles начинаются с базового значения (обычно
baseWireHandle = 0x7E0000) и инкрементируются. Они используются для кодирования backreferences.#Java #для_новичков #beginner #IO #NIO #Serialize
👍4
serialVersionUID: идентификатор версии класса
Что такое serialVersionUID
При десериализации она сравнивает
Этот механизм защищает от десериализации объектов, сериализованных несовместимой версией класса. Например, если класс
Генерация по умолчанию
Если класс не объявляет
Имя класса.
Модификаторы класса (
Имена интерфейсов, которые реализует класс.
Имена полей, их модификаторы, типы.
Имена методов, их модификаторы, сигнатуры (возвращаемый тип, параметры).
Имена конструкторов, их сигнатуры.
Имена и сигнатуры методов
Имена статических полей (кроме
Этот хеш вычисляется через алгоритм, похожий на Secure Hash Algorithm (SHA), но упрощённый. Результат — 64-битное целое число
Проблема автоматической генерации
Автоматическая генерация
Если объект
Это происходит даже если изменение семантически совместимо: добавление метода не влияет на состояние объекта, но меняет вычисленный хеш.
Решение: явное объявление
Рекомендуется всегда объявлять
При явном объявлении JVM не вычисляет UID динамически, а использует указанное значение. Теперь добавление методов, изменение порядка полей, рефакторинг внутренней структуры не влияет на совместимость сериализации — до тех пор, пока изменения совместимы с форматом потока.
Как выбрать начальное значение? Традиционно используется
Когда менять serialVersionUID
Несовместимые изменения включают:
Удаление полей.
Изменение типа поля (например,
Изменение модификаторов класса с
Перемещение класса в другой пакет (имя класса входит в поток).
Изменение порядка полей суперкласса (влияет на порядок в потоке).
Изменение класса с
Совместимые изменения
При явном
Добавление полей: новые поля в потоке отсутствуют, поэтому при десериализации они получают значения по умолчанию (
Добавление классов в иерархию: если добавить новый суперкласс, который сам реализует
Удаление классов из иерархии: если удалить сериализуемый суперкласс, поля этого суперкласса в потоке игнорируются.
Добавление/удаление методов
Изменение модификатора доступа поля: не влияет, так как сериализация обходит модификаторы.
Пометка поля как transient: поле перестаёт читаться из потока, получает значение по умолчанию.
При десериализации объекта версии 1 в класс версии 2 поле
Обратная совместимость: новый объект в старый класс
Если объект сериализован версией 2 (с полем
#Java #для_новичков #beginner #IO #NIO #Serialize
Что такое serialVersionUID
serialVersionUID — это статическое поле типа long, которое выступает уникальным идентификатором версии класса для механизма сериализации. При сериализации JVM записывает serialVersionUID класса в поток.При десериализации она сравнивает
serialVersionUID из потока с serialVersionUID загруженного класса. Если значения не совпадают — InvalidClassException.public class Document implements Serializable {
private static final long serialVersionUID = 1L;
private String title;
}Этот механизм защищает от десериализации объектов, сериализованных несовместимой версией класса. Например, если класс
Document v1 имел поля title и author, а в v2 поле author было удалено и добавлено content, десериализация v1-объекта в v2-класс без контроля версий привела бы к повреждению данных или ClassCastException.Генерация по умолчанию
Если класс не объявляет
serialVersionUID явно, JVM вычисляет его автоматически на основе структуры класса. Алгоритм генерации (документирован в спецификации Java Object Serialization) учитывает:Имя класса.
Модификаторы класса (
public, final, abstract, interface).Имена интерфейсов, которые реализует класс.
Имена полей, их модификаторы, типы.
Имена методов, их модификаторы, сигнатуры (возвращаемый тип, параметры).
Имена конструкторов, их сигнатуры.
Имена и сигнатуры методов
writeObject, readObject, writeReplace, readResolve.Имена статических полей (кроме
serialVersionUID itself).Этот хеш вычисляется через алгоритм, похожий на Secure Hash Algorithm (SHA), но упрощённый. Результат — 64-битное целое число
long.SHA (Secure Hash Algorithm) — семейство криптографических хеш-функций, которые преобразуют входные данные произвольной длины в строку фиксированной длины (дайджест). В контексте serialVersionUID используется не криптографический SHA, а похожий алгоритм хеширования структурных элементов класса.
Проблема автоматической генерации
Автоматическая генерация
serialVersionUID кажущеися удобной, но на практике является источником хрупкости. Любое изменение класса — даже добавление приватного метода, изменение порядка полей, добавление комментария (нет, комментарии не влияют, но форматирование может влиять на порядок элементов в некоторых компиляторах) — может изменить вычисленный serialVersionUID.// Версия 1
public class User implements Serializable {
private String name;
private int age;
}
// Версия 2 — добавлен метод, serialVersionUID изменился!
public class User implements Serializable {
private String name;
private int age;
public void greet() { // новый метод изменяет вычисленный UID
System.out.println("Hello");
}
}
Если объект
User был сериализован версией 1, а десериализуется версией 2, JVM вычислит новый serialVersionUID для загруженного класса, сравнит с UID из потока, обнаружит несоответствие и выбросит:java.io.InvalidClassException: User; local class incompatible:
stream classdesc serialVersionUID = -123456789,
local class serialVersionUID = 987654321
Это происходит даже если изменение семантически совместимо: добавление метода не влияет на состояние объекта, но меняет вычисленный хеш.
Решение: явное объявление
Рекомендуется всегда объявлять
serialVersionUID явно:public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
}При явном объявлении JVM не вычисляет UID динамически, а использует указанное значение. Теперь добавление методов, изменение порядка полей, рефакторинг внутренней структуры не влияет на совместимость сериализации — до тех пор, пока изменения совместимы с форматом потока.
Как выбрать начальное значение? Традиционно используется
1L. Если позже потребуется несовместимое изменение, значение увеличивают: 2L, 3L и т.д. Некоторые команды используют timestamp или хеш от начальной структуры класса, но на практике последовательные номера проще в управлении.Когда менять serialVersionUID
serialVersionUID следует изменять (инкрементировать) при несовместимых изменениях структуры класса. Несовместимые изменения включают:
Удаление полей.
Изменение типа поля (например,
int → String).Изменение модификаторов класса с
Serializable на несериализуемый.Перемещение класса в другой пакет (имя класса входит в поток).
Изменение порядка полей суперкласса (влияет на порядок в потоке).
Изменение класса с
enum на обычный или наоборот.Совместимые изменения
При явном
serialVersionUID можно вносить изменения, не ломающие десериализацию старых объектов:Добавление полей: новые поля в потоке отсутствуют, поэтому при десериализации они получают значения по умолчанию (
null, 0, false). JVM использует ObjectInputStream.defaultReadObject(), который читает из потока только те поля, которые есть в текущем классе, игнорируя лишние данные в потоке.Добавление классов в иерархию: если добавить новый суперкласс, который сам реализует
Serializable, старые объекты десериализуются корректно — новые поля суперкласса получат значения по умолчанию.Удаление классов из иерархии: если удалить сериализуемый суперкласс, поля этого суперкласса в потоке игнорируются.
Добавление/удаление методов
writeObject/readObject: не влияет на serialVersionUID при явном объявлении.Изменение модификатора доступа поля: не влияет, так как сериализация обходит модификаторы.
Пометка поля как transient: поле перестаёт читаться из потока, получает значение по умолчанию.
// Версия 1
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
}
// Версия 2 — совместимое изменение: добавлено поле
public class User implements Serializable {
private static final long serialVersionUID = 1L; // тот же UID!
private String name;
private String email; // новое поле, старые объекты получат null
}
При десериализации объекта версии 1 в класс версии 2 поле
email получит null. Это безопасно, но требует, чтобы код класса корректно обрабатывал null (например, через инициализацию в readObject() или ленивую инициализацию в геттере).Обратная совместимость: новый объект в старый класс
Если объект сериализован версией 2 (с полем
email), а десериализуется классом версии 1 (без email), JVM прочитает из потока поле email, но не найдёт соответствующего поля в классе. В этом случае данные поля сохраняются во внутренней структуре ObjectInputStream как no-data или skipped fields, но не восстанавливаются. Это не вызывает исключения, но данные теряются.#Java #для_новичков #beginner #IO #NIO #Serialize
👍4
Расширенный контроль: writeObject, readObject, readResolve
writeObject и readObject
Класс может переопределить поведение сериализации, объявив приватные методы:
JVM вызывает эти методы через рефлексию, если они объявлены. Метод
Этот паттерн позволяет сериализовать
readResolve
Метод
Без
writeReplace
Аналогично,
Этот паттерн рекомендуется Джошуа Блохом (Joshua Bloch) в "Effective Java" как предпочтительный способ сериализации сложных объектов
#Java #для_новичков #beginner #IO #NIO #Serialize
writeObject и readObject
Класс может переопределить поведение сериализации, объявив приватные методы:
private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
JVM вызывает эти методы через рефлексию, если они объявлены. Метод
writeObject вызывается после записи дескриптора класса, но перед записью полей. Внутри него можно выполнить out.defaultWriteObject() (записать стандартные поля) и затем дописать произвольные данные.public class SecureDocument implements Serializable {
private static final long serialVersionUID = 1L;
private String title;
private transient String secretContent; // не сериализуем напрямую
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // записываем title и другие нетранзиентные поля
// Шифруем секретный контент перед записью
String encrypted = encrypt(secretContent);
out.writeUTF(encrypted);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // читаем title
// Дешифруем секретный контент
String encrypted = in.readUTF();
this.secretContent = decrypt(encrypted);
}
private String encrypt(String data) { /* ... */ return data; }
private String decrypt(String data) { /* ... */ return data; }
}Этот паттерн позволяет сериализовать
transient-поля в зашифрованном виде, выполнять валидацию инвариантов, восстанавливать производные структуры.readResolve
Метод
readResolve вызывается после полной десериализации объекта и позволяет заменить десериализованный экземпляр на другой объект. Это критично для реализации singleton и enum-like паттернов.Singleton — это порождающий паттерн проектирования, гарантирующий, что класс имеет только один экземпляр, и предоставляющий глобальную точку доступа к нему. При десериализации singleton механизм создаёт новый объект, нарушая гарантию единственности. readResolve возвращает существующий экземпляр.
public class Singleton implements Serializable {
private static final long serialVersionUID = 1L;
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
// При десериализации возвращаем существующий INSTANCE, а не новый объект
private Object readResolve() {
return INSTANCE;
}
}Без
readResolve десериализация Singleton создала бы новый объект в куче, и getInstance() вернул бы старый INSTANCE, в то время как десериализованный объект — отдельная сущность. readResolve гарантирует, что любая десериализация вернёт канонический экземпляр.writeReplace
Аналогично,
writeReplace вызывается перед сериализацией и позволяет заменить объект на другой перед записью в поток. Используется для прокси-сериализации (serialization proxy pattern), когда внутреннее представление объекта не должно попадать в поток.Прокси-сериализация (serialization proxy pattern) — это паттерн, при котором вместо самого объекта сериализуется лёгкий прокси-объект (proxy), содержащий только необходимые данные, а при десериализации прокси через readResolve восстанавливает оригинальный объект через его конструктор или фабрику. Это защищает инварианты, предотвращает создание "сырых" объектов и позволяет менять внутреннюю структуру класса, не ломая совместимость.
public class ComplexObject implements Serializable {
private static final long serialVersionUID = 1L;
private final int x;
private final int y;
// инвариант: x >= 0 && y >= 0
public ComplexObject(int x, int y) {
if (x < 0 || y < 0) throw new IllegalArgumentException();
this.x = x;
this.y = y;
}
// Вместо себя сериализуем прокси
private Object writeReplace() {
return new SerializationProxy(x, y);
}
// Запрещаем десериализацию ComplexObject напрямую
private void readObject(ObjectInputStream in) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
private static class SerializationProxy implements Serializable {
private static final long serialVersionUID = 1L;
private final int x;
private final int y;
SerializationProxy(int x, int y) {
this.x = x;
this.y = y;
}
// При десериализации прокси восстанавливаем ComplexObject через конструктор
private Object readResolve() {
return new ComplexObject(x, y); // инвариант проверяется!
}
}
}Этот паттерн рекомендуется Джошуа Блохом (Joshua Bloch) в "Effective Java" как предпочтительный способ сериализации сложных объектов
#Java #для_новичков #beginner #IO #NIO #Serialize
👍4
Что выведет код?
#Tasks
import java.io.*;
public class Task310726 {
static class DataV1 implements Serializable {
private static final long serialVersionUID = 1L;
String name = "John";
}
static class DataV2 implements Serializable {
private static final long serialVersionUID = 1L;
String fullName;
}
public static void main(String[] args) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(new DataV1());
}
byte[] bytes = baos.toByteArray();
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
DataV2 obj = (DataV2) ois.readObject();
System.out.println(obj.fullName);
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName());
}
}
}
#Tasks
👍2
👍2
Что такое 🤓
Ответ:
Collectors.toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) собирает стрим в Map.
Если возникают дублирующиеся ключи, нужно передать mergeFunction для разрешения конфликта.
Пример: list.stream ().collect(Collectors.toMap(Item::getId, Function.identity(), (oldVal, newVal) -> newVal)) — при конфликте берется новое значение.
Также можно указать Supplier для конкретной реализации Map. Без mergeFunction конфликт вызовет IllegalStateException.
#собеседование
Collectors.toMap() и как разрешать конфликты ключей? Ответ:
Collectors.toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)
Если возникают дублирующиеся ключи, нужно передать mergeFunction для разрешения конфликта.
Пример:
Также можно указать Supplier для конкретной реализации Map. Без mergeFunction конфликт вызовет IllegalStateException.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 01 августа
ℹ️ Кто родился в этот день
Дуглас Дин Оше́ров (англ. Douglas Dean Osheroff; род. 1 августа 1945, Абердин, Вашингтон, США) — американский физик, лауреат Нобелевской премии по физике в 1996 г. (совместно с Дэвидом Ли и Робертом Ричардсоном) «за открытие сверхтекучести гелия-3». Открытие было сделано в 1971 году, когда Ошеров был аспирантом в Корнеллском университете.
Жорж Шарпа́к (фр. Georges Charpak, в семье и среди знакомых — Гриша Шарпак; 1 августа 1924 — 29 сентября 2010) — французский физик, лауреат Нобелевской премии по физике в 1992 году «за открытие и создание детекторов частиц, в частности многопроволочной пропорциональной камеры».
🌐 Знаковые события
1774 — английским учёным Джозефом Пристли открыт химический элемент кислород.
#Biography #Birth_Date #Events #01августа
Дуглас Дин Оше́ров (англ. Douglas Dean Osheroff; род. 1 августа 1945, Абердин, Вашингтон, США) — американский физик, лауреат Нобелевской премии по физике в 1996 г. (совместно с Дэвидом Ли и Робертом Ричардсоном) «за открытие сверхтекучести гелия-3». Открытие было сделано в 1971 году, когда Ошеров был аспирантом в Корнеллском университете.
Жорж Шарпа́к (фр. Georges Charpak, в семье и среди знакомых — Гриша Шарпак; 1 августа 1924 — 29 сентября 2010) — французский физик, лауреат Нобелевской премии по физике в 1992 году «за открытие и создание детекторов частиц, в частности многопроволочной пропорциональной камеры».
1774 — английским учёным Джозефом Пристли открыт химический элемент кислород.
#Biography #Birth_Date #Events #01августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Всем привет! 😉
Опубликовал еще пару статей на devforge.ru
Пагинация, которую начинаешь ненавидеть 😵
Как я память искал
Поправил мобильное отображение статей. Должно быть комфортно читать)))
Проверяйте))
Если не сложно напишите хоть одно слово о том как вам?☺️
Опубликовал еще пару статей на devforge.ru
Пагинация, которую начинаешь ненавидеть 😵
Как я память искал
Поправил мобильное отображение статей. Должно быть комфортно читать)))
Проверяйте))
Если не сложно напишите хоть одно слово о том как вам?
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
Я, который решил добавить в прод либу о которой много пишут в интернете🤣
🤣5🔥1
Java for Beginner
Всем привет! 😉 Опубликовал еще пару статей на devforge.ru Пагинация, которую начинаешь ненавидеть 😵 Как я память искал Поправил мобильное отображение статей. Должно быть комфортно читать))) Проверяйте)) Если не сложно напишите хоть одно слово о том…
Вот как надо было🤣 и че я с мобилкой замарачивался🤪
🤣2👍1🔥1🤓1
История технологии сегодня — 02 августа
ℹ️ Кто родился в этот день
Элайша Грей (другой вариант имени в русских источниках: Элиша, англ. Elisha Gray; 2 августа 1835, Барнсвилл, Огайо — 21 января 1901, Ньютонвилл, Мидлсекс) — американский инженер-электрик, соучредитель компании Western Electric Manufacturing Company. Элайша Грей также считается отцом современного музыкального синтезатора, и получил более 70 патентов на свои изобретения. Он был одним из основателей Graybar, приобретя контрольный пакет акций компании вскоре после её создания.
Сэ́мюэл Ду́нкан Блэк (англ. Samuel Duncan Black, более известный как С. Дункан Блэк (англ. S. Duncan Black); 1883—1951) — американский предприниматель и изобретатель, вместе с Алонзо Дж. Деккером основавший компанию по производству инструментов Black & Decker. Известность они приобрели благодаря совместной разработке пистолетной рукоятки и спускового переключателя для переносных электрических дрелей, а также универсального двигателя для переносных электроинструментов.
🌐 Знаковые события
1932 — Карл Андерсон сделал снимок со следом античастицы позитрон.
2020 — космический корабль Dragon 2 компании SpaceX впервые совершил посадку после космического полёта с астронавтами в миссии SpaceX DM-2.
#Biography #Birth_Date #Events #02августа
Элайша Грей (другой вариант имени в русских источниках: Элиша, англ. Elisha Gray; 2 августа 1835, Барнсвилл, Огайо — 21 января 1901, Ньютонвилл, Мидлсекс) — американский инженер-электрик, соучредитель компании Western Electric Manufacturing Company. Элайша Грей также считается отцом современного музыкального синтезатора, и получил более 70 патентов на свои изобретения. Он был одним из основателей Graybar, приобретя контрольный пакет акций компании вскоре после её создания.
Сэ́мюэл Ду́нкан Блэк (англ. Samuel Duncan Black, более известный как С. Дункан Блэк (англ. S. Duncan Black); 1883—1951) — американский предприниматель и изобретатель, вместе с Алонзо Дж. Деккером основавший компанию по производству инструментов Black & Decker. Известность они приобрели благодаря совместной разработке пистолетной рукоятки и спускового переключателя для переносных электрических дрелей, а также универсального двигателя для переносных электроинструментов.
1932 — Карл Андерсон сделал снимок со следом античастицы позитрон.
2020 — космический корабль Dragon 2 компании SpaceX впервые совершил посадку после космического полёта с астронавтами в миссии SpaceX DM-2.
#Biography #Birth_Date #Events #02августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ребят, напоминаю, набираю желающих обучиться Java!
Карьерным консультантом не работаю, но до уровня крепкого мидла с Spring доведу.
Что изучаем: Spring Boot, Spring Security, Spring Data, OAuth2, FeignClient, Specification, Pageable, WebClient, PostgreSQL, Redis, Hibernate, REST API, Caffeine, JUnit, Mockito, WireMock, Zonky, Kafka, Apache Common и так далее. Но тут не все))
Кроме того могу провести мок-интервью или проверить ваш пет-проект. По итогу дам развернутый фидбек.
Пишите, спрашивайте, за спрос денег не берут)
@Oleborn
Карьерным консультантом не работаю, но до уровня крепкого мидла с Spring доведу.
Что изучаем: Spring Boot, Spring Security, Spring Data, OAuth2, FeignClient, Specification, Pageable, WebClient, PostgreSQL, Redis, Hibernate, REST API, Caffeine, JUnit, Mockito, WireMock, Zonky, Kafka, Apache Common и так далее. Но тут не все))
Кроме того могу провести мок-интервью или проверить ваш пет-проект. По итогу дам развернутый фидбек.
Пишите, спрашивайте, за спрос денег не берут)
@Oleborn
👍6
Ребят кому не сложно, накиньте пару лайков под статьей - https://habr.com/ru/articles/1065138/
Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Хабр
"__TypeId__": как один Kafka-заголовок незаметно связывает микросервисы именами Java-классов
Всем привет! Пока ищу работу, продолжаю знакомить Вас с внутренностями и неочевидными моментами работы распределенной микросервисной архитектуры в мире Java Spring. Сегодня на очереди Apache Kafka,...
🔥3 1
Java for Beginner
Ребят кому не сложно, накиньте пару лайков под статьей - https://habr.com/ru/articles/1065138/ Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Честно говоря я не пойму почему статья не зашла... Реально больная тема. Реально не все знают пути решения... Хм......
История технологии сегодня — 03 августа
ℹ️ Кто родился в этот день
Коити Танака, иногда Коичи Танака (яп. 田中 耕一 Танака Ко:ити, род. 3 августа 1959, Тояма, Япония) — японский инженер и химик, лауреат Нобелевской премии по химии 2002 года за разработку нового масс-спектрометрического метода исследования биологических макромолекул. Он единственный Нобелевский лауреат без научной степени.
🌐 Знаковые события
1929 — в Ростове-на-Дону стала работать первая в СССР автоматическая телефонная станция (АТС) на 6000 номеров, построенная при содействии шведской фирмы «Эрикссон».
2004 — запущена автоматическая межпланетная станция (АМС) MESSENGER для исследования Меркурия.
#Biography #Birth_Date #Events #03августа
Коити Танака, иногда Коичи Танака (яп. 田中 耕一 Танака Ко:ити, род. 3 августа 1959, Тояма, Япония) — японский инженер и химик, лауреат Нобелевской премии по химии 2002 года за разработку нового масс-спектрометрического метода исследования биологических макромолекул. Он единственный Нобелевский лауреат без научной степени.
1929 — в Ростове-на-Дону стала работать первая в СССР автоматическая телефонная станция (АТС) на 6000 номеров, построенная при содействии шведской фирмы «Эрикссон».
2004 — запущена автоматическая межпланетная станция (АМС) MESSENGER для исследования Меркурия.
#Biography #Birth_Date #Events #03августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #067]
Тема:
Проблема: Многие разработчики ошибочно полагают, что
На самом деле этот метод оборачивает переданный список в прокси-объект, который перехватывает все методы, изменяющие коллекцию (
Однако сам исходный список остается доступным через оригинальную ссылку, и любые его модификации немедленно отражаются в неизменяемом view. Это нарушает инкапсуляцию и может привести к неожиданному поведению: клиент, получивший неизменяемый список, ожидает, что его содержимое будет постоянным, но оно может измениться из-за внешних изменений. Особенно опасно в многопоточных сценариях, когда исходный список модифицируется конкурентно.
Этот паттерн часто называют "неизменяемая обертка" (unmodifiable wrapper), а не "иммутабельная коллекция" (immutable collection), в отличие от
Решение: Если вы хотите защитить данные от изменений, возвращая неизменяемый список, убедитесь, что исходный список больше не доступен для модификации в вашем коде.
Либо передавайте только view клиентам и храните исходный список только внутри класса, с возможностью его изменения только через внутренние методы. Для полной изоляции создавайте копию исходного списка перед оборачиванием:
Однако такая копия защищает только от изменений через оригинальную ссылку, но сама копия все еще изменяема, если сохранить ссылку на нее. Лучшее решение — использовать
Объяснение:
Это часто используется в API для предоставления доступа "только для чтения" к внутреннему состоянию. Однако для гарантии неизменности данных нужно либо сделать исходный список недоступным для модификации (например, через
#Java #советы
Тема:
Collections.unmodifiableList возвращает view на исходный список.Проблема: Многие разработчики ошибочно полагают, что
Collections.unmodifiableList(list) создает независимую неизменяемую копию исходного списка. На самом деле этот метод оборачивает переданный список в прокси-объект, который перехватывает все методы, изменяющие коллекцию (
add, remove, set и др.), и выбрасывает UnsupportedOperationException. Однако сам исходный список остается доступным через оригинальную ссылку, и любые его модификации немедленно отражаются в неизменяемом view. Это нарушает инкапсуляцию и может привести к неожиданному поведению: клиент, получивший неизменяемый список, ожидает, что его содержимое будет постоянным, но оно может измениться из-за внешних изменений. Особенно опасно в многопоточных сценариях, когда исходный список модифицируется конкурентно.
Этот паттерн часто называют "неизменяемая обертка" (unmodifiable wrapper), а не "иммутабельная коллекция" (immutable collection), в отличие от
List.of() или Collections.emptyList(), которые действительно неизменяемы.Решение: Если вы хотите защитить данные от изменений, возвращая неизменяемый список, убедитесь, что исходный список больше не доступен для модификации в вашем коде.
Либо передавайте только view клиентам и храните исходный список только внутри класса, с возможностью его изменения только через внутренние методы. Для полной изоляции создавайте копию исходного списка перед оборачиванием:
Collections.unmodifiableList(new ArrayList<>(list)). Однако такая копия защищает только от изменений через оригинальную ссылку, но сама копия все еще изменяема, если сохранить ссылку на нее. Лучшее решение — использовать
List.copyOf() (Java 10+) или List.of() (Java 9+), которые создают действительно неизменяемые списки, не зависящие от оригинала. Если вы используете unmodifiableList, явно документируйте, что view отражает изменения исходного списка, и что клиент не должен рассчитывать на неизменность содержимого без внешних гарантий.public class UnmodifiableView {
public static void main(String[] args) {
List<String> original = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> unmodifiable = Collections.unmodifiableList(original);
System.out.println("Original: " + original); // [A, B, C]
System.out.println("Unmodifiable: " + unmodifiable); // [A, B, C]
// Изменяем исходный список
original.add("D");
System.out.println("После изменения оригинала:");
System.out.println("Original: " + original); // [A, B, C, D]
System.out.println("Unmodifiable: " + unmodifiable); // [A, B, C, D] — изменился!
// Попытка изменить view вызовет исключение
try {
unmodifiable.add("E"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.err.println("Нельзя изменить view");
}
//Решение 1: копия + обертка (все равно оригинал может быть изменен, если доступен)
List<String> copyAndWrap = Collections.unmodifiableList(new ArrayList<>(original));
original.add("F");
System.out.println("Copy+wrap не изменился: " + copyAndWrap); // [A, B, C, D] — не изменился
//Решение 2: List.copyOf (Java 10+) — действительно неизменяемый
List<String> immutable = List.copyOf(original);
original.add("G");
System.out.println("List.copyOf: " + immutable); // [A, B, C, D, F] — не изменился
//Решение 3: List.of (Java 9+) — для фиксированного набора значений
List<String> fixed = List.of("X", "Y", "Z");
// fixed не зависит от внешних списков
}
}Объяснение:
Collections.unmodifiableList использует паттерн декоратор. Возвращаемый объект — внутренний класс UnmodifiableList, который делегирует все методы чтения (get, size, iterator) исходному списку, а все методы записи переопределяет, бросая исключение. Поскольку он хранит ссылку на исходный список, любые изменения в исходном списке видны через view. Это часто используется в API для предоставления доступа "только для чтения" к внутреннему состоянию. Однако для гарантии неизменности данных нужно либо сделать исходный список недоступным для модификации (например, через
private и отсутствие сеттеров), либо использовать действительно неизменяемые коллекции. List.copyOf() и List.of() возвращают экземпляры, которые не содержат ссылок на внешние изменяемые структуры, и их содержимое гарантированно не изменяется. #Java #советы
👍5
Что выведет код?
#Tasks
import java.util.*;
public class Task030826 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
List<Integer> unmod = Collections.unmodifiableList(list);
list.add(4);
try {
unmod.add(5);
} catch (UnsupportedOperationException e) {
System.out.print("ex ");
}
System.out.println(unmod.size());
}
}
#Tasks
👍4
👍4
Что такое 🤓
Ответ:
Collectors.teeing() (Java 12) — это составной коллектор, который принимает два коллектора и функцию объединения их результатов.
Позволяет выполнить две независимые операции над одним стримом за один проход.
Пример: Collectors.teeing(Collectors.summingInt(Item::getPrice), Collectors.counting(), (sum, count) -> sum / count) — вычисляет среднюю цену за один проход.
Полезно, когда нужно несколько агрегаций, но стрим нельзя переиспользовать.
#собеседование
Collectors.teeing()? Collectors.teeing() (Java 12) — это составной коллектор, который принимает два коллектора и функцию объединения их результатов.
Позволяет выполнить две независимые операции над одним стримом за один проход.
Пример: Collectors.teeing(Collectors.summingInt(Item::getPrice), Collectors.counting(), (sum, count) -> sum / count) — вычисляет среднюю цену за один проход.
Полезно, когда нужно несколько агрегаций, но стрим нельзя переиспользовать.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 04 августа
ℹ️ Кто родился в этот день
Джорджо Паризи (итал. Giorgio Parisi; род. 4 августа 1948 года) — итальянский физик-теоретик. Труды в основном посвящены квантовой теории поля, статистической механике и сложным системам. Соавтор уравнения ДГЛАП, уравнений Кардара — Паризи — Жанга. Нобелевская премия по физике (2021) за «открытие того, как беспорядок и флуктуации взаимодействуют в физических системах в масштабах от атомов до планет».
🌐 Знаковые события
1954 — свой первый полёт совершил британский сверхзвуковой самолёт P-1.
2007 — запущен космический аппарат НАСА «Феникс», предназначенный для исследования Марса.
#Biography #Birth_Date #Events #04августа
Джорджо Паризи (итал. Giorgio Parisi; род. 4 августа 1948 года) — итальянский физик-теоретик. Труды в основном посвящены квантовой теории поля, статистической механике и сложным системам. Соавтор уравнения ДГЛАП, уравнений Кардара — Паризи — Жанга. Нобелевская премия по физике (2021) за «открытие того, как беспорядок и флуктуации взаимодействуют в физических системах в масштабах от атомов до планет».
1954 — свой первый полёт совершил британский сверхзвуковой самолёт P-1.
2007 — запущен космический аппарат НАСА «Феникс», предназначенный для исследования Марса.
#Biography #Birth_Date #Events #04августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2