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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Подписывайтесь на канал, мы поможем построить правильные планы 😏

https://t.me/Java_for_beginner_dev

#Mems
Автоупаковка (Autoboxing) и распаковка (Unboxing)

Автоупаковка (Autoboxing) и распаковка (Unboxing) — это процесс автоматического преобразования между примитивными типами данных и их соответствующими классами-обёртками в Java. Эти функции были введены в J2SE 5.0 и значительно упрощают код, устраняя необходимость явного преобразования.

Автоупаковка (Autoboxing)

Автоупаковка — это автоматическое преобразование примитивного типа в соответствующий ему объект класса-обёртки.

Примеры автоупаковки:
public class AutoboxingExample {
public static void main(String[] args) {
int intValue = 5;
Integer integerObject = intValue; // Автоупаковка
System.out.println("Integer object: " + integerObject);

char charValue = 'a';
Character characterObject = charValue; // Автоупаковка
System.out.println("Character object: " + characterObject);
}
}


В этом примере примитивный int автоматически преобразуется в объект Integer, а примитивный char — в объект Character.



Распаковка (Unboxing)


Распаковка — это автоматическое преобразование объекта класса-обёртки обратно в соответствующий примитивный тип.

Примеры распаковки:
public class UnboxingExample {
public static void main(String[] args) {
Integer integerObject = Integer.valueOf(10);
int intValue = integerObject; // Распаковка
System.out.println("Primitive int: " + intValue);

Character characterObject = Character.valueOf('a');
char charValue = characterObject; // Распаковка
System.out.println("Primitive char: " + charValue);
}
}


В этом примере объект Integer автоматически преобразуется в примитивный int, а объект Character — в примитивный char.

Преимущества автопреобразования

Упрощение кода: Снижение количества явных преобразований, улучшение читаемости и поддерживаемости кода.
Совместимость с коллекциями: Возможность использования примитивных типов данных в коллекциях, таких как ArrayList, без необходимости явного преобразования.

Особенности и подводные камни


Производительность: Автоупаковка и распаковка могут привести к снижению производительности из-за дополнительных операций создания объектов.
NullPointerException: При распаковке, если объект класса-обёртки равен null, возникает NullPointerException.


Пример потенциальной ошибки с распаковкой:
public class UnboxingPitfall {
public static void main(String[] args) {
Integer integerObject = null;
try {
int intValue = integerObject; // Может вызвать NullPointerException
} catch (NullPointerException e) {
System.out.println("Caught NullPointerException!");
}
}
}


В этом примере попытка распаковки null объекта Integer приводит к NullPointerException.

#Java #Training
Класс Object и его значение в Java

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

Основные методы класса Object

Класс Object содержит несколько методов, которые могут быть использованы и переопределены в ваших классах:

public boolean equals(Object obj)
public int hashCode()
public String toString()
protected Object clone() throws CloneNotSupportedException
public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException
public final void notify()
public final void notifyAll()
protected void finalize() throws Throwable


equals()

Метод equals() используется для сравнения двух объектов на равенство. По умолчанию метод equals() в классе Object сравнивает ссылки на объекты, т.е. проверяет, указывают ли обе ссылки на один и тот же объект в памяти. Обычно этот метод переопределяется, чтобы определить равенство объектов по их содержимому.

Пример переопределения equals()
public class Person {
private String name;
private int age;

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

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
}


hashCode()

Метод hashCode() возвращает целочисленное значение, представляющее внутренний адрес объекта. В Java рекомендуется переопределять hashCode() всякий раз, когда переопределяется equals(), чтобы поддерживать согласованность между этими двумя методами. Объекты, которые равны по методу equals(), должны иметь одинаковый хеш-код.

Пример переопределения hashCode()
public class Person {
private String name;
private int age;

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

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}
}


toString()

Метод toString() возвращает строковое представление объекта. Этот метод часто переопределяется, чтобы предоставить более информативное строковое представление объектов.

Пример переопределения toString()
public class Person {
private String name;
private int age;

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

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


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

public class ObjectMethodsExample {
public static void main(String[] args) {
MyClass obj1 = new MyClass(1);
MyClass obj2 = new MyClass(1);
MyClass obj3 = obj1;

System.out.println(obj1.equals(obj2));
System.out.println(obj1 == obj2);
System.out.println(obj1.hashCode() == obj2.hashCode());
System.out.println(obj1 == obj3);
}
}

class MyClass {
int value;

MyClass(int value) {
this.value = value;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MyClass myClass = (MyClass) obj;
return value == myClass.value;
}

@Override
public int hashCode() {
return value;
}
}

#Tasks
Подписывайтесь на канал, мы умеем фиксить баги! 😂🤌

https://t.me/Java_for_beginner_dev

#Mems
Другие методы класса 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