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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Другие методы класса Object

clone()

Метод clone() создает и возвращает копию объекта. Для использования этого метода класс должен реализовывать интерфейс Cloneable, иначе вызов метода clone() приведет к выбросу исключения CloneNotSupportedException.

Пример использования метода clone()
public class Person implements Cloneable {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}

public static void main(String[] args) {
try {
Person person1 = new Person("John", 25);
Person person2 = (Person) person1.clone();
System.out.println(person1);
System.out.println(person2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}


wait(), notify() и notifyAll()


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

wait(): Приостанавливает текущий поток до тех пор, пока другой поток не вызовет notify() или notifyAll() для этого объекта.
notify(): Пробуждает один поток, ожидающий на этом объекте.
notifyAll(): Пробуждает все потоки, ожидающие на этом объекте.


Эти методы должны вызываться внутри синхронизированного блока или метода.

Пример использования wait() и notify()
public class WaitNotifyExample {
private static final Object lock = new Object();

public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1: Waiting for lock...");
lock.wait();
System.out.println("Thread 1: Got the lock!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2: Got the lock!");
lock.notify();
System.out.println("Thread 2: Notified!");
}
});

t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}


finalize() (В настоящее время не рекомендуется к использованию)


Метод finalize() вызывается перед сборкой мусора для объекта. Он может быть использован для выполнения очистки ресурсов, но его использование не рекомендуется из-за непредсказуемости момента вызова и возможности замены на более современные механизмы управления ресурсами, такие как try-with-resources и интерфейс AutoCloseable.

Пример использования finalize()
public class FinalizeExample {
@Override
protected void finalize() throws Throwable {
try {
System.out.println("Finalize method called");
} finally {
super.finalize();
}
}

public static void main(String[] args) {
FinalizeExample obj = new FinalizeExample();
obj = null;
System.gc(); // Запрос сборщика мусора (не гарантия вызова finalize)
}
}


#Java #Training #Object
Введение в Queue

Queue — это интерфейс в Java, представляющий коллекцию, предназначенную для хранения элементов в порядке, поддерживающем принципы FIFO (First-In-First-Out). Элементы добавляются в конец очереди и извлекаются из начала. Queue является частью коллекций Java и находится в пакете java.util.

Реализации Queue

Существует несколько реализаций интерфейса Queue в Java:

LinkedList: Класс LinkedList реализует интерфейс Queue и предоставляет эффективные операции вставки и удаления с обоих концов списка.
Queue<String> queue = new LinkedList<>();


PriorityQueue: Класс PriorityQueue реализует интерфейс Queue и предоставляет приоритетную очередь, в которой элементы упорядочены на основе их естественного порядка или на основе предоставленного компаратора.
Queue<String> priorityQueue = new PriorityQueue<>();


ArrayDeque: Класс ArrayDeque реализует интерфейс Deque (двусторонняя очередь) и может использоваться как Queue.
Queue<String> arrayDeque = new ArrayDeque<>();


Основные операции:

Добавление элементов:

add(E e): Добавляет элемент в конец очереди. Выбрасывает исключение IllegalStateException, если очередь ограничена и заполнена.
queue.add("Element");


offer(E e): Добавляет элемент в конец очереди. Возвращает false, если очередь ограничена и заполнена.
queue.offer("Element");


Удаление элементов:

remove(): Удаляет и возвращает элемент из начала очереди. Выбрасывает исключение NoSuchElementException, если очередь пуста.
String element = queue.remove();


poll(): Удаляет и возвращает элемент из начала очереди. Возвращает null, если очередь пуста.
String element = queue.poll();


Просмотр элементов:

element(): Возвращает, но не удаляет, элемент из начала очереди. Выбрасывает исключение NoSuchElementException, если очередь пуста.
String element = queue.element();


peek(): Возвращает, но не удаляет, элемент из начала очереди. Возвращает null, если очередь пуста.
String element = queue.peek();



Пример использования Queue
import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();

// Добавление элементов
queue.add("Element 1");
queue.offer("Element 2");

// Просмотр элемента
System.out.println("Peek: " + queue.peek());

// Удаление элементов
System.out.println("Removed: " + queue.remove());
System.out.println("Polled: " + queue.poll());

// Попытка просмотра/удаления из пустой очереди
System.out.println("Peek from empty queue: " + queue.peek());
System.out.println("Poll from empty queue: " + queue.poll());
}
}


#Java #Training #Collections #Queue
Что выведет код?

import java.util.*;

public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
queue.add(3);
queue.offer(4);
queue.poll();
queue.remove();

System.out.println(queue);
}
}


#Tasks
Варинаты ответа:
Anonymous Quiz
9%
[1, 2, 3, 4]
73%
[3, 4]
18%
[2, 3, 4]
0%
[1, 3, 4]
Подписывайтесь на канал, мы работаем из дома😎

https://t.me/Java_for_beginner_dev

#Mems
Когда Вам удобно принять участие в онлайн встрече?
Anonymous Poll
0%
В субботу
43%
В воскресение
57%
Хоть когда, пофиг!
0%
Никогда! Отстаньте от меня!!!
Введение в Stack

Stack — это класс в Java, представляющий коллекцию, предназначенную для хранения элементов в порядке, поддерживающем принципы LIFO (Last-In-First-Out). Элементы добавляются и извлекаются с одного конца стека, называемого вершиной. Класс Stack находится в пакете java.util и наследуется от класса Vector.

Создание Stack


Для создания экземпляра Stack нужно импортировать класс java.util.Stack и использовать его конструктор:
Stack<String> stack = new Stack<>();


Основные операции

Добавление элементов:

push(E item): Добавляет элемент на вершину стека.
stack.push("Element");


Удаление элементов:

pop(): Удаляет и возвращает элемент с вершины стека. Выбрасывает исключение EmptyStackException, если стек пуст.
String element = stack.pop();


Просмотр элементов:

peek(): Возвращает, но не удаляет, элемент с вершины стека. Выбрасывает исключение EmptyStackException, если стек пуст.
String element = stack.peek();


Проверка состояния стека:

empty(): Проверяет, пуст ли стек. Возвращает true, если стек пуст, и false в противном случае.
boolean isEmpty = stack.empty();


search(Object o): Ищет элемент в стеке и возвращает его положение, начиная с вершины стека. Возвращает -1, если элемент не найден.
int position = stack.search("Element");



Пример использования Stack
import java.util.Stack;

public class StackExample {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();

// Добавление элементов
stack.push("Element 1");
stack.push("Element 2");
stack.push("Element 3");

// Просмотр элемента
System.out.println("Peek: " + stack.peek());

// Удаление элементов
System.out.println("Popped: " + stack.pop());
System.out.println("Popped: " + stack.pop());

// Проверка состояния стека
System.out.println("Is stack empty? " + stack.empty());

// Поиск элемента
stack.push("Element 4");
stack.push("Element 5");
System.out.println("Position of 'Element 4': " + stack.search("Element 4"));

// Удаление оставшихся элементов
System.out.println("Popped: " + stack.pop());
System.out.println("Popped: " + stack.pop());

// Попытка просмотра/удаления из пустого стека
System.out.println("Is stack empty? " + stack.empty());
}
}



Сравнение Queue и Stack
Очередь (Queue): Использует порядок FIFO (First-In-First-Out). Элементы добавляются в конец и удаляются из начала.
Стек (Stack): Использует порядок LIFO (Last-In-First-Out). Элементы добавляются и удаляются с вершины.


#Java #Training #Collections
Напоминаю, что у нас есть чат - https://t.me/Java_Beginner_chat 😂
Дженерики

Дженерики (Generics) — это механизм в языке программирования Java, который позволяет создавать классы, интерфейсы и методы с параметризованными типами. Они были введены в Java 5 для обеспечения безопасности типов и устранения необходимости явных приведений типов. Дженерики позволяют писать универсальный код, который может работать с разными типами данных, не теряя при этом безопасность типов.

Зачем нужны дженерики?

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


Основные концепции дженериков

Обобщенные классы: Классы, которые могут работать с любыми типами данных.
public class Box<T> {
private T value;

public void set(T value) {
this.value = value;
}

public T get() {
return value;
}
}


В этом примере T — это параметризованный тип. При создании экземпляра класса Box вы можете указать конкретный тип:
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
System.out.println(integerBox.get());

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
System.out.println(stringBox.get());


Обобщенные методы: Методы, которые могут работать с любыми типами данных.
public class Util {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}


Вызов обобщенного метода:
Integer[] intArray = {1, 2, 3, 4, 5};
String[] strArray = {"one", "two", "three"};

Util.printArray(intArray);
Util.printArray(strArray);


Обобщенные интерфейсы: Интерфейсы, которые могут работать с любыми типами данных.
public interface Pair<K, V> {
K getKey();
V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;

public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}

@Override
public K getKey() {
return key;
}

@Override
public V getValue() {
return value;
}
}


Использование обобщенного интерфейса:
Pair<String, Integer> pair = new OrderedPair<>("One", 1);
System.out.println("Key: " + pair.getKey() + ", Value: " + pair.getValue());


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

Повышение безопасности типов: Программисты могут избегать классовых приведений, которые могут привести к ошибкам времени выполнения. Дженерики позволяют обнаруживать ошибки на этапе компиляции.
Повторное использование кода: Дженерики позволяют разработчикам создавать классы, методы и интерфейсы, которые могут работать с любыми типами данных.
Улучшение читаемости кода: Дженерики позволяют программистам писать более понятный и краткий код, не нуждаясь в явных приведениях типов.


Рассмотрим простой пример с использованием дженериков. Создадим класс, который может хранить пару объектов любого типа:
public class Pair<T, U> {
private T first;
private U second;

public Pair(T first, U second) {
this.first = first;
this.second = second;
}

public T getFirst() {
return first;
}

public U getSecond() {
return second;
}

public void setFirst(T first) {
this.first = first;
}

public void setSecond(U second) {
this.second = second;
}

@Override
public String toString() {
return "Pair{" + "first=" + first + ", second=" + second + '}';
}
}


Теперь мы можем использовать этот класс с любыми типами данных:
Pair<Integer, String> pair = new Pair<>(1, "One");
System.out.println(pair); // Output: Pair{first=1, second=One}

pair.setFirst(2);
pair.setSecond("Two");
System.out.println(pair); // Output: Pair{first=2, second=Two}


#Java #Training #Generics
Что выведет код?

public class TypeCastingExample {
public static void main(String[] args) {
Parent parent = new Child();
Child child;

try {
child = (Child) parent;
System.out.println(child.getMessage());
} catch (ClassCastException e) {
System.out.println("ClassCastException");
}

try {
Parent anotherParent = new AnotherChild();
child = (Child) anotherParent;
System.out.println(child.getMessage());
} catch (ClassCastException e) {
System.out.println("ClassCastException");
}
}
}

class Parent {
String getMessage() {
return "Parent";
}
}

class Child extends Parent {
@Override
String getMessage() {
return "Child";
}
}

class AnotherChild extends Parent {
@Override
String getMessage() {
return "AnotherChild";
}
}


#Tasks
Подписывайтесь на канал, с нами разговаривают баги🪲🤪

https://t.me/Java_for_beginner_dev

#Mems
Продвинутые возможности дженериков

Ограничения типов

Ограниченные параметры типов (Bounded Type Parameters): Позволяют задать верхние и нижние границы для параметризованных типов.
public class Box<T extends Number> {
private T value;

public void set(T value) {
this.value = value;
}

public T get() {
return value;
}
}

В этом примере T должен быть подклассом Number.


Множественные ограничения (Multiple Bounds): Параметр типа может быть ограничен несколькими типами.
public <T extends Number & Comparable<T>> T findMax(T[] array) {
T max = array[0];
for (T element : array) {
if (element.compareTo(max) > 0) {
max = element;
}
}
return max;
}


Подстановочные знаки (Wildcards)

Неограниченные подстановочные знаки: Позволяют параметризованному типу принимать любой тип.
public void printList(List<?> list) {
for (Object element : list) {
System.out.println(element);
}
}


Ограниченные сверху подстановочные знаки (Upper Bounded Wildcards): Позволяют параметризованному типу принимать любой тип, который является подклассом указанного.
public void addNumbers(List<? extends Number> list) {
double sum = 0;
for (Number number : list) {
sum += number.doubleValue();
}
System.out.println("Sum: " + sum);
}


Ограниченные снизу подстановочные знаки (Lower Bounded Wildcards): Позволяют параметризованному типу принимать любой тип, который является суперклассом указанного.
public void addIntegers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}


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


Преимущества:

Повышение безопасности типов.
Уменьшение необходимости приведения типов.
Повышение читаемости и повторного использования кода.


Недостатки:

Усложнение кода для начинающих программистов.
Невозможность использовать примитивные типы в качестве параметров типов.
Ограничения, связанные с типизацией во время выполнения (Type Erasure).
Типизация во время выполнения (Type Erasure)
Дженерики в Java реализованы с использованием механизма стирания типов (Type Erasure). Это означает, что информация о параметризованных типах удаляется во время компиляции, и все операции с дженериками выполняются с использованием типов Object или соответствующих ограниченных типов. Это позволяет обеспечить совместимость с кодом, не использующим дженерики, но накладывает некоторые ограничения, такие как невозможность использования примитивных типов и невозможность создания массивов параметризованных типов.


Примеры сложных случаев использования дженериков

Рекурсивные обобщенные типы:
public class ComparableBox<T extends Comparable<T>> {
private T value;

public ComparableBox(T value) {
this.value = value;
}

public T getValue() {
return value;
}

public int compareTo(ComparableBox<T> other) {
return value.compareTo(other.getValue());
}
}


Обобщенные методы в обобщенных классах:
public class Util {
public static <T> boolean compare(Box<T> box1, Box<T> box2) {
return box1.get().equals(box2.get());
}
}


Использование:
Box<Integer> box1 = new Box<>();
box1.set(10);
Box<Integer> box2 = new Box<>();
box2.set(10);

boolean result = Util.compare(box1, box2); // true


#Java #Training #Generics
Всем доброго субботнего утра!!! 🔆

Пишите как проводите выходные!) 🍻

Напоминаю, что завтра в 16:00 по МСК, мы вновь организуем онлайн встречу и что-то (пока сами не знаем что) будем лайфкодить))))👨‍💻

Ждем всех!
Вы придете на онлайн встречу в 16:00 по МСК?
Anonymous Poll
33%
Да!
8%
Нет(
58%
Не знаю, если смогу
Встреча создана.

Ссылка в нашем чате - https://t.me/Java_Beginner_chat
Не знаю как, но нас уже неожиданно стало 100 человек на канале! 🤩

Для меня это крайне важный показатель того, что все делается не зря, есть потенциал для развития!
И только благодаря Вам, подписчикам, канал может становиться только лучше и лучше!!!


Спасибо всем подписавшимся и тем кто с нами!🤝