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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Введение в 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 человек на канале! 🤩

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


Спасибо всем подписавшимся и тем кто с нами!🤝
Java for Beginner pinned «Запись нашей сегодняшней встречи - https://www.youtube.com/watch?v=KTO2-XhWCnY Спасибо всем кто участвовал👍, продолжение на следующей неделе)))»
Внутренние классы

Внутренние классы (Inner Classes) — это классы, которые определены внутри других классов. Они используются для логической группировки классов, которые будут использоваться только в одном месте, и для улучшения читаемости и организации кода. Внутренние классы имеют доступ к членам внешнего класса, включая приватные члены.

Виды внутренних классов:

Не статические внутренние классы (Non-static inner classes):

Обычные внутренние классы (Regular Inner Classes)
Локальные внутренние классы (Local Inner Classes)
Анонимные внутренние классы (Anonymous Inner Classes)
Статические вложенные классы (Static Nested Classes)


Обычные внутренние классы (Regular Inner Classes)

Это классы, объявленные непосредственно внутри другого класса, но вне всех методов. Они имеют доступ ко всем полям и методам внешнего класса, включая приватные.
public class OuterClass {
private String outerField = "Outer Field";

public class InnerClass {
public void display() {
System.out.println("Outer field is: " + outerField);
}
}

public void testInner() {
InnerClass inner = new InnerClass();
inner.display();
}

public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.testInner();
}
}


В этом примере InnerClass является обычным внутренним классом и имеет доступ к приватному полю outerField внешнего класса OuterClass.



Локальные внутренние классы (Local Inner Classes)

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

public class OuterClass {
public void methodWithInnerClass() {
class LocalInnerClass {
void display() {
System.out.println("This is a local inner class");
}
}

LocalInnerClass localInner = new LocalInnerClass();
localInner.display();
}

public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.methodWithInnerClass();
}
}


В этом примере LocalInnerClass объявлен внутри метода methodWithInnerClass и доступен только внутри этого метода.

Анонимные внутренние классы (Anonymous Inner Classes)

Анонимные внутренние классы используются для создания экземпляров классов с одновременным переопределением их методов, обычно для реализации интерфейсов или абстрактных классов.
public class OuterClass {
public void createAnonymousClass() {
MyInterface anonymous = new MyInterface() {
@Override
public void myMethod() {
System.out.println("Anonymous inner class method");
}
};
anonymous.myMethod();
}

public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.createAnonymousClass();
}
}

interface MyInterface {
void myMethod();
}


В этом примере мы создаем анонимный внутренний класс, который реализует интерфейс MyInterface и переопределяет его метод myMethod.

#Java #Training
Варианты ответа:
Anonymous Quiz
0%
banana date
67%
date apple
33%
cherry banana
0%
apple cherry
Что выведет код?

import java.util.*;

public class CollectionsExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>(Arrays.asList("apple", "banana", "cherry", "date"));
List<String> list = new ArrayList<>(set);

Collections.sort(list, new CustomComparator());
Queue<String> queue = new LinkedList<>(list);

System.out.println(queue.poll() + " " + queue.peek());
}
}

class CustomComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}


#Tasks
Подписывайтесь на канал, мы знаем, что было в начале 😎

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM