Java for Beginner
685 subscribers
585 photos
161 videos
12 files
900 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Глубокое изучение типа данных byte в Java

Тип byte в Java — это один из восьми примитивных типов, представляющий собой 8-битное целое число со знаком. Он занимает ровно 1 байт в памяти и используется в тех случаях, когда важна экономия пространства или требуется работа с низкоуровневыми бинарными данными. Несмотря на кажущуюся простоту, byte имеет ряд особенностей, которые важно понимать для корректной и безопасной работы.

Диапазон и внутреннее представление

Значения byte варьируются от -128 до 127. Это обусловлено использованием 8 бит и представления чисел в формате дополнительного кода (two's complement):

0: 00000000
127: 01111111
-1: 11111111
-128: 10000000

Самый старший бит (MSB) определяет знак: 0 — положительное число, 1 — отрицательное. Формат two's complement позволяет упростить реализацию арифметики на уровне процессора.

Как работает two's complement

Чтобы получить отрицательное значение, берут двоичное представление положительного числа, инвертируют биты и прибавляют единицу:

Пример:
5 → 00000101
~5 → 11111010
+1 → 11111011 → это -5

Этот подход ведет к асимметрии диапазона: -128 можно представить, а +128 — нет, так как 8 бит не хватает.


Размещение в памяти

Так как byte — это примитивный тип, он хранится в стеке, если это локальная переменная, либо в куче, если он является полем объекта. При входе в метод для переменной выделяется 1 байт в стеке. При выходе из метода фрейм стека удаляется целиком, вместе с переменными.

Если byte используется как поле класса, то память выделяется при создании объекта в куче. Освобождение происходит автоматически через сборщик мусора JVM.

Поведение в арифметике и преобразования

Одной из ключевых особенностей byte является то, что в арифметических операциях он автоматически приводится к int. Это значит, что результат выражений типа byte + byte — это int, и его необходимо явно привести обратно к byte, если нужно сохранить в переменной этого типа:
byte b1 = 100;
byte b2 = 30;
byte sum = b1 + b2; // ошибка компиляции
byte sum = (byte)(b1 + b2); // корректно


Переполнение (overflow)

Так как byte хранит только 8 бит, любые арифметические операции, выходящие за диапазон [-128; 127], приводят к оборачиванию значения:
byte b = 127;
b++; // теперь b = -128
Это не ошибка компиляции, но может привести к логическим багам, особенно если разработчик не учитывает граничные значения.


Беззнаковость и побитовые операции

В Java отсутствует беззнаковый byte. Для получения значений в диапазоне 0–255 применяется побитовая маска:
byte b = -1;
int unsigned = b & 0xFF; // результат: 255
Это часто используется при работе с бинарными протоколами, изображениями, файлами и сетевыми буферами.


Применение


Экономия памяти. В массивах или структурах, где значения всегда укладываются в [-128; 127], использование byte позволяет экономить в 4 раза больше памяти по сравнению с int.
Работа с файлами и сетевыми потоками. Классы вроде InputStream и ByteBuffer оперируют byte[] для обработки бинарных данных.
Явное ограничение диапазона. Использование byte вместо int служит также как форма документации: переменная ограничена по смыслу и диапазону.


Инициализация и значения по умолчанию

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


Потенциальные ошибки и рекомендации

Не забывайте про overflow при арифметике.
Используйте явное приведение типов при необходимости.
Помните, что byte[] — это массив чисел, не строка. Учитывайте кодировку, если работаете с текстом.
Для беззнаковой работы применяйте b & 0xFF.


Пример: работа с бинарным файлом
FileInputStream in = new FileInputStream("image.png");
byte[] buffer = new byte[1024];
int bytesRead = in.read(buffer);
in.close();


#Java #для_новичков #beginner #byte
👍3
Что выведет код?

public class Task140525 {
public static void main(String[] args) {
byte a = (byte) 0b10000000;
byte b = 1;
byte c = (byte) (a + b);
System.out.println(c);
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
14%
-128
10%
129
52%
-127
24%
Ошибка компиляции
👍1
Самые пугающие три точки кода.

💬 Varargs в Java 💬

Сегодня в рабочем проекте столкнулся с методом, в аргументах которого было выражение типа Object... data.

Сразу подумал, что скорее всего на канале, этот момент не рассматривался. Нашел в коротком варианте, опубликованном аж 6 июня 2024 года.

Решил немного расширить взгляд на такой вариант передачи данных в метод.
Поддержка переменного числа аргументов (varargs) была добавлена в Java, начиная с версии JDK 5 (Java 5). До этого программисту приходилось либо перегружать методы для разного количества параметров, либо передавать массив аргументов вручную.

Иными словами - если у Вас возникает случай, что в метод может поступать неопределенное количество параметров, в том числе и разного типа, но метод должен быть только ОДИН - Varargs Ваш выбор 🤙


Как это работает? Теория. 🤓

Когда метод принимает аргументы через Varargs, то компилятор при этом неявно преобразует такой параметр в массив типа Object[].

void foo(Object... data) { /*...*/ }


по сути компилируется как
void foo(Object[] data) { /*...*/ }


При вызове метода с varargs компилятор сам создаёт массив нужного размера и заполняет его переданными значениями (даже если аргументов нет, создаётся пустой массив).

❗️При этом varargs-параметр может быть только последним в списке и быть единственным varargs в методе ❗️


Как это работает? Практика. 🧑‍💻

Пример метода, принимающего переменное число строк:
public static void printStrings(String... words) {
for (String w : words) {
System.out.print(w + " ");
}
System.out.println();
}

// Вызовы:
printStrings("Alice", "Bob");
printStrings("one", "two", "three");

При этом внутри words будет String[] со всеми переданными значениями


Или самый любимый вариант когда метод printAll(Object... args) может принимать любой набор объектов:
public static void printAll(Object... args) {
for (Object o : args) {
System.out.print(o + " ");
}
System.out.println();
}

// Вызов:
printAll("Hello", 123, true, new User("Tom"));


Здесь в args будут храниться объекты типа String, Integer, Boolean, User и т.д. Встроенный метод String.format тоже использует varargs: его сигнатура String.format(Locale, String, Object... args) позволяет передавать любое количество различных объектов в шаблон.


С каким 💩 можно столкнуться если увлекаться Varargs. ⛔️

Выборки из stackoverflow.com:
Приведение типов и автопакетирование

Метод void m(Object... args) под капотом видит args как Object[]. Если вы ожидаете внутри определённый тип, будьте осторожны с приведением, иначе может возникнуть ClassCastException. Попытка привести Object[] к String[] при неправильном использовании varargs приведёт к ошибке времени выполнения.

Ещё один нюанс – работа с примитивными типами и их обёртками: varargs не применяет автопакетирование к массивам примитивов. То есть если вы ожидаете набор чисел, стоит использовать Integer... вместо int..., иначе передача int[] в параметр типа Object... будет воспринята как единичный объект int[], а не как набор чисел
.


Конфликт с перегрузкой методов

Перегрузка методов вместе с varargs может привести к неоднозначности. Так, если объявлены оба метода fun(int... a) и fun(boolean... b), то вызов fun() без аргументов компилятор посчитает неразрешимым, ведь он не может однозначно выбрать, какую версию вызывать.

Аналогично, комбинация fun(int... a) и fun(int n, int... a) приводит к конфликту при вызове fun(1), потому что компилятор не знает, вызвать ли первый метод с одним элементом или второй метод с фиксированным первым параметром. Такие неоднозначности приводят к ошибкам компиляции. Чтобы этого избежать, не перегружайте методы только за счёт varargs: лучше дать методам разные имена или явно менять количество параметров.


И личный совет: varargs удобны, но не злоупотребляйте ими. Старайтесь держать код ясным: ограничивайте использование varargs реальными случаями, где это упрощает интерфейс, и следите за типобезопасностью.


Понравился стиль подачи материала?

Отправь другу и ставь -
🔥

#Java #varargs #autor #для_новичков #junior
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤬11
📌 Факт дня:

А вы знали, что прародитель "джойстика" был создан для управления самолётом?

История возникновения джойстика началась еще на рассвете XX века: именно тогда, в 1907 году в Германии, был зарегистрирован патент на рукоять управления самолетом, которую, по сути, можно считать прародителем знакомого нам компьютерного джойстика.


proof

#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
📌 Цитата дня: Илон Маск

"Если человечество не станет межпланетным, у нас нет будущего."


Илон Маск сказал это в 2016 году на конференции IAC в Мексике, связывая технологии с выживанием человечества.

Почитать биографию

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Базовая десериализация и аннотации в Gson

Десериализация JSON в Java-объект


Метод fromJson(String, Class<T>)
Десериализация — процесс преобразования JSON-строки в Java-объект. Основной метод:

Gson gson = new Gson();
MyClass obj = gson.fromJson(jsonString, MyClass.class);


Пример
Допустим, есть JSON:
{
"model": "Tesla Model S",
"year": 2023,
"electric": true
}


Соответствующий Java-класс:
public class Car {
private String model;
private int year;
private boolean electric;

// Обязателен конструктор по умолчанию (или @SerializedConstructor в новых версиях)
public Car() {}

// Геттеры и сеттеры
public String getModel() { return model; }
public int getYear() { return year; }
public boolean isElectric() { return electric; }
}


Десериализация:
String json = "{\"model\":\"Tesla Model S\",\"year\":2023,\"electric\":true}";
Gson gson = new Gson();
Car car = gson.fromJson(json, Car.class);

System.out.println(car.getModel()); // Tesla Model S


Обработка ошибок

Gson выбрасывает JsonSyntaxException при невалидном JSON:
try {
Car car = gson.fromJson("{invalid json}", Car.class);
} catch (JsonSyntaxException e) {
System.err.println("Ошибка парсинга JSON: " + e.getMessage());
}


Аннотации @SerializedName и @Expose

@SerializedName — для нестандартных ключей JSON

Если имя поля в Java не совпадает с ключом в JSON:
public class User {
@SerializedName("user_name")
private String name; // Сопоставляется с JSON-ключом "user_name"

@SerializedName(value = "user_age", alternate = {"age", "years"})
private int age; // Допустимые альтернативные ключи в JSON
}


Пример JSON:
{"user_name": "Alice", "age": 25}


@Expose — избирательная сериализация/десериализация

Поля без @Expose игнорируются. Требуется особый Gson:
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();


Пример класса:
public class Product {
@Expose
private String name; // Сериализуется и десериализуется

@Expose(serialize = false)
private int id; // Только десериализация (из JSON в Java)

private String secret; // Игнорируется полностью
}


Отличие от Jackson

Аннотации:

В Gson: @SerializedName@JsonProperty в Jackson.
@Expose → Аналог @JsonInclude + @JsonIgnore.

Подход:
Gson использует рефлексию по умолчанию, Jackson — аннотации.

Производительность:
Jackson быстрее в некоторых сценариях, но Gson проще в настройке.

Полный пример

import com.google.gson.*;
import com.google.gson.annotations.*;

public class Main {
static class Device {
@SerializedName("device_name")
@Expose
private String name;

@Expose(deserialize = false)
private String manufacturer;

public Device(String name, String manufacturer) {
this.name = name;
this.manufacturer = manufacturer;
}
}

public static void main(String[] args) {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create();

// Сериализация (manufacturer исключен, т.к. deserialize = false)
Device device = new Device("Phone", "BrandX");
String json = gson.toJson(device);
System.out.println(json);

// Десериализация
String inputJson = "{\"device_name\":\"Tablet\",\"manufacturer\":\"BrandY\"}";
Device parsed = gson.fromJson(inputJson, Device.class);
System.out.println(parsed.name); // "Tablet"
}
}


Вывод:
{
"device_name": "Phone"
}


Ключевые моменты

@SerializedName решает проблему различий в именах JSON/Java.
@Expose дает контроль над процессами сериализации/десериализации.
Для работы
@Expose требуется GsonBuilder.

#Java #middle #Gson #SerializedName #Expose
👍4
Что выведет код?

public class Task150525 {
public static void main(String[] args) {
String str = " Hello, World! ";
str.trim().toLowerCase().substring(7);
System.out.println(str);
}
}


#Tasks
👍1
📌 Факт дня:

А вы знали, что первый компьютерный "чат" был создан в 1973 году?

Программа Talkomatic, разработанная в Университете Иллинойса, позволяла нескольким пользователям общаться в реальном времени на системе PLATO. Это был прототип современных мессенджеров.


proof

#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Цитата дня: Энди Рубин

"Мобильные устройства — это пульт управления вашей жизнью."


Энди Рубин, создатель Android, сказал это в 2008 году на запуске первого Android-устройства.

Почитать биографию

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Полный разбор примитивного типа int в Java

Тип int — это один из восьми примитивных типов данных в Java. Несмотря на его кажущуюся простоту, понимание того, как он устроен, работает в памяти и взаимодействует с JVM, критически важно для глубокого освоения языка.


Общая информация


Тип: примитивный (primitive)
Размер: 32 бита (4 байта)
Диапазон значений: от -2,147,483,648 до 2,147,483,647 (т.е. от -2³¹ до 2³¹ - 1)
Знаковый: да (signed)
Формат представления: two's complement (двойное дополнение)


Пример объявления переменной:
int number = 42;



Что значит signed (знаковый тип)?


В типе int один из битов используется для хранения знака числа:
0 — положительное число
1 — отрицательное число


Это позволяет хранить как положительные, так и отрицательные значения. Всего 2³² возможных комбинаций битов. Из них:
половина — для отрицательных чисел
половина — для положительных чисел (включая 0)



Представление чисел: формат two’s complement

Java использует формат двойного дополнения (two’s complement) для хранения отрицательных чисел. Это универсальный и эффективный способ хранения знаковых чисел в бинарной форме.

Как это работает:


Чтобы получить -x:
Возьми двоичное представление x.
Инвертируй все биты (обратное дополнение).
Прибавь 1.


Пример: -5

5 = 00000000 00000000 00000000 00000101
Инверсия = 11111111 11111111 11111111 11111010
+1 → 11111111 11111111 11111111 11111011
Так хранится -5 в памяти.



Где хранится int в памяти?

В стеке (stack)
Если переменная int — локальная переменная метода, она хранится в стековой рамке метода.

В куче (heap)
Если int является полем объекта (int age внутри класса), то он хранится в куче, как часть объекта.


Что такое стековая рамка (stack frame)?

Каждый вызов метода в Java создаёт отдельную область в стеке, называемую stack frame. Она содержит:
Локальные переменные
Временные значения
Адрес возврата
Операнды

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



Как происходит запись и удаление int?

Запись: JVM резервирует 4 байта и записывает число в двоичном формате.
Удаление: локальные переменные исчезают при завершении метода. Если int был частью объекта, он удаляется при сборке мусора (GC), когда объект становится недостижимым.



Особенности

1. Переполнение (overflow)

int не выбрасывает исключений при выходе за границы диапазона:

int a = Integer.MAX_VALUE; // 2_147_483_647
a++;
System.out.println(a); // -2_147_483_648 (переполнение)
Чтобы отлавливать такие случаи, используйте Math.addExact(), которая кидает ArithmeticException.


Если продолжить увеличивать значение переменной типа int после переполнения, то поведение будет цикличным. То есть от 2_147_483_647 до -2_147_483_648 не выходя за пределы этих значений.


2. Побитовые операции


Java поддерживает прямые операции над битами:
& — побитовое И
| — побитовое ИЛИ
^ — XOR
~ — побитовое НЕ
<< — сдвиг влево
>> — сдвиг вправо (с сохранением знака)
>>> — сдвиг вправо (без сохранения знака)


Пример:
int x = 5;    // 00000101
int y = 3; // 00000011

int result = x & y; // 00000001 (1)


3. Автоупаковка и Integer-кэш

При автоупаковке int → Integer:
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true


Но:
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b); // false


Почему?
Значения от -128 до 127 кэшируются.
JVM использует один и тот же объект для этих чисел (ради оптимизации).
Сравнение == проверяет ссылку, а не значение.
Для сравнения значений используйте .equals().



Преобразования типов

int неявно (автоматически) расширяется до long, float, double.

Сужающее преобразование требует явного приведения:
byte b = (byte) 130; // b == -126


#Java #для_новичков #beginner #int
👍2🤯1
Что выведет код?

public class Task160525 {
public static void main(String[] args) {
int a = 2_000_000_000;
int b = 2_000_000_000;
int c = a + b;
System.out.println(c);
}
}


#Tasks
👍1
👍3🤯1
Как вам изменения на канале?
Снижение количества постов, изменение тем, новые темы?
Anonymous Poll
88%
Отлично! Лучше чем было! 👍
12%
Да не заметно разницы... ☺️
0%
Все стало только хуже! Админ возвращай взад!😝
🔥3
Есть мысль собраться завтра в 16:00 по МСК и разобрать написание идеального контроллера 🧑‍💻

Вы придете?
Anonymous Poll
48%
Да, тема интересная, я буду! 🙂
29%
Я бы хотел, но занят ☹️
0%
Че там разбирать то? Нафига? 😠
23%
Что это за группа? Где я? 😱
👍6
Всем привет! ✌️

Приглашаю всех желающих сегодня собраться в Яндекс.Телемост в 16:00 по МСК!

В этот раз, дошла очередь рассказать о том, как написать контроллер в экосистеме Spring.

Рассмотрим:
- Зачем нам вообще нужны контроллеры
- Какие существуют основные принципы REST при написании контроллеров
- Основные аннотации Spring для написания контроллеров и их настройку
- Все это посмотрим на примере кода


Приходите, будет интересно 🧑‍💻

Как всегда жду всех! 🫡
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3