Java asoslari 8-qism. Generics

30.06.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Java tili | 23 daqiqa o'qish

Generics - Java’da class, interface yoki methodni ma’lum bir type bilan xavfsiz ishlatish imkonini beradi.

Oddiy qilib aytganda:

Generics yordamida List ichida faqat String, faqat Integer, faqat User kabi aniq turdagi ma’lumot saqlashni majburlaymiz.

Generics bo‘limiga quyidagilar kiradi: Generic classes & methods, bounded type parameters, wildcards ? extends, ? super, type erasure.


1. Generics nega kerak?

Avval Java’da collectionlar generic’siz ishlatilgan.

List list = new ArrayList();

list.add("Ali");
list.add(25);
list.add(true);

Bu yomon. Chunki bitta ro‘yxat ichida har xil type bor:

String
Integer
Boolean

Keyin olishda muammo chiqadi:

String name = (String) list.get(1);

Bu yerda list.get(1) aslida 25, ya’ni Integer.

Natijada runtime xato bo‘ladi:

ClassCastException

2. Generics bilan xavfsiz yozish

List<String> names = new ArrayList<>();

names.add("Ali");
names.add("Vali");
names.add("Hasan");

Endi bu list ichiga faqat String qo‘shiladi.

names.add(25); // compile error

Bu yaxshi. Chunki xato dastur ishlaganda emas, compile vaqtida ushlanadi.


3. List<String>dagi <String> nima?

List<String> names = new ArrayList<>();

Bu yerda:

Qism

Ma’nosi

List

Interface

String

List ichida saqlanadigan type

ArrayList

Real implementation

<>

Generic type belgisi

Ya’ni:

Bu List faqat String saqlaydi.

Boshqa misollar:

List<Integer> numbers = new ArrayList<>();
List<User> users = new ArrayList<>();
Set<Long> ids = new HashSet<>();
Map<Long, User> usersById = new HashMap<>();

4. Generics bilan cast qilish shart emas

Generic’siz:

List list = new ArrayList();
list.add("Ali");

String name = (String) list.get(0);

Generic bilan:

List<String> names = new ArrayList<>();
names.add("Ali");

String name = names.get(0);

Bu yerda (String) yozish shart emas. Java o‘zi biladi: bu list ichida String bor.


5. Generics real backend’da qanday ishlatiladi?

Masalan, userlar ro‘yxati:

List<User> users = new ArrayList<>();

ID bo‘yicha user topish:

Map<Long, User> usersById = new HashMap<>();

Role nomlari:

Set<String> roles = new HashSet<>();

Orderlar:

List<Order> orders = new ArrayList<>();

Spring Boot’da ham Generics juda ko‘p ishlatiladi:

ResponseEntity<UserDto>
Optional<User>
Page<ProductDto>
List<OrderResponse>
Repository<User, Long>

6. Generic class

O‘zimiz generic class yozishimiz mumkin.

Masalan, bitta oddiy box class:

public class Box<T> {
    private T value;

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

    public T getValue() {
        return value;
    }
}

Bu yerda T - type parameter.

Endi Boxni har xil type bilan ishlatamiz.

Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");

String text = stringBox.getValue();
Box<Integer> integerBox = new Box<>();
integerBox.setValue(100);

Integer number = integerBox.getValue();

Box<T> degani:

Box ichidagi qiymatning type’i keyin belgilanadi.

7. T, E, K, V nimani anglatadi?

Generics’da harflar odatda shunday ishlatiladi:

Harf

Ma’nosi

T

Type

E

Element

K

Key

V

Value

R

Return type

Misollar:

public class Box<T> {
}
public interface List<E> {
}
public interface Map<K, V> {
}

Map<K, V> degani:

K - key type
V - value type

Masalan:

Map<Long, User> usersById = new HashMap<>();

Bu yerda:

K = Long
V = User

8. Generic method

Faqat class emas, method ham generic bo‘lishi mumkin.

public class Printer {
    public static <T> void print(T value) {
        System.out.println(value);
    }
}

Ishlatish:

Printer.print("Hello");
Printer.print(123);
Printer.print(true);

Bu method har xil type qabul qiladi.


8.1 Generic method real misol

public static <T> T first(List<T> list) {
    return list.get(0);
}

Ishlatish:

List<String> names = List.of("Ali", "Vali");
String firstName = first(names);
List<Integer> numbers = List.of(10, 20, 30);
Integer firstNumber = first(numbers);

Bu method qaysi type list kelsa, o‘sha type qiymat qaytaradi.


9. Bounded type parameter

Ba’zida generic type’ni cheklash kerak bo‘ladi.

Masalan, faqat Numberdan meros olgan type’lar bilan ishlaymiz:

public class NumberBox<T extends Number> {
    private T value;

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

    public double doubleValue() {
        return value.doubleValue();
    }
}

Endi quyidagilar ishlaydi:

NumberBox<Integer> intBox = new NumberBox<>(10);
NumberBox<Double> doubleBox = new NumberBox<>(15.5);

Lekin bu ishlamaydi:

NumberBox<String> stringBox = new NumberBox<>("Hello"); // compile error

Chunki String Numberdan meros olmagan.


10. extends generics’da nimani bildiradi?

<T extends Number>

Bu degani:

T Number yoki Numberdan meros olgan class bo‘lishi kerak.

Misollar:

Integer extends Number
Double extends Number
Long extends Number
Float extends Number

Shuning uchun ular qabul qilinadi.


11. Multiple bounds

Bitta type bir nechta shartga ega bo‘lishi mumkin.

public class Repository<T extends BaseEntity & Auditable> {
}

Bu degani:

T BaseEntitydan meros olgan bo‘lishi kerak
va Auditable interface’ini implement qilgan bo‘lishi kerak.

Muhim qoida:

<T extends ClassName & InterfaceName>

Class birinchi yoziladi, interface keyin yoziladi.


12. Wildcard ?

? - noma’lum type degani.

List<?> list

Bu degani:

Har qanday type’dagi List bo‘lishi mumkin.

Misol:

public static void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

Ishlatish:

printList(List.of("Ali", "Vali"));
printList(List.of(1, 2, 3));
printList(List.of(true, false));

Bu method har qanday listni print qiladi.


13. ? extends

List<? extends Number>

Bu degani:

Number yoki Numberdan meros olgan type’dagi List.

Masalan:

List<Integer>
List<Double>
List<Long>

hammasi mos keladi.

Misol:

public static double sum(List<? extends Number> numbers) {
    double result = 0;

    for (Number number : numbers) {
        result += number.doubleValue();
    }

    return result;
}

Ishlatish:

List<Integer> integers = List.of(1, 2, 3);
List<Double> doubles = List.of(1.5, 2.5, 3.5);

System.out.println(sum(integers));
System.out.println(sum(doubles));

Bu yerda ? extends Number sababli method Integer, Double, Long listlarini qabul qiladi.


13.1 ? extendsga element qo‘shish muammosi

List<? extends Number> numbers = new ArrayList<Integer>();

numbers.add(10); // compile error

Nega?

Chunki Java aniq bilmaydi: bu list aslida Integermi, Doublemi, Longmi?

Masalan:

List<? extends Number> numbers = new ArrayList<Double>();

Agar Java numbers.add(10)ga ruxsat bersa, Double list ichiga Integer tushib qolishi mumkin.

Shuning uchun:

? extends odatda o‘qish uchun ishlatiladi.


14. ? super

List<? super Integer>

Bu degani:

Integer yoki Integerning parent type’i bo‘lgan List.

Mos keladiganlar:

List<Integer>
List<Number>
List<Object>

Misol:

public static void addNumbers(List<? super Integer> numbers) {
    numbers.add(10);
    numbers.add(20);
    numbers.add(30);
}

Ishlatish:

List<Integer> integers = new ArrayList<>();
addNumbers(integers);

List<Number> numbers = new ArrayList<>();
addNumbers(numbers);

List<Object> objects = new ArrayList<>();
addNumbers(objects);

Bu ishlaydi.


14.1 ? superdan o‘qish

List<? super Integer> numbers = new ArrayList<Number>();

Object value = numbers.get(0);

Bu yerda Java faqat Object deb kafolat bera oladi. Chunki list Integer, Number yoki Object bo‘lishi mumkin.

Shuning uchun:

? super odatda yozish uchun ishlatiladi.


15. PECS qoidasi

Generics’dagi eng mashhur qoida:

PECS = Producer Extends, Consumer Super

Ya’ni:

Holat

Ishlatiladi

Collectiondan o‘qisangiz

? extends

Collectionga yozsangiz

? super

Oddiyroq:

extends = olish / read
super   = qo‘shish / write

Misol:

public static double sum(List<? extends Number> numbers) {
    double result = 0;

    for (Number number : numbers) {
        result += number.doubleValue();
    }

    return result;
}

Bu yerda listdan qiymat olinmoqda. Shuning uchun extends.

public static void addIntegers(List<? super Integer> numbers) {
    numbers.add(1);
    numbers.add(2);
}

Bu yerda listga qiymat qo‘shilmoqda. Shuning uchun super.


16. Generic interface

Interface ham generic bo‘lishi mumkin.

public interface Repository<T, ID> {
    T findById(ID id);

    void save(T entity);

    void deleteById(ID id);
}

User uchun:

public class UserRepository implements Repository<User, Long> {
    @Override
    public User findById(Long id) {
        return null;
    }

    @Override
    public void save(User entity) {
    }

    @Override
    public void deleteById(Long id) {
    }
}

Product uchun:

public class ProductRepository implements Repository<Product, Long> {
    @Override
    public Product findById(Long id) {
        return null;
    }

    @Override
    public void save(Product entity) {
    }

    @Override
    public void deleteById(Long id) {
    }
}

Bu Spring Data JPA’dagi repositoryga juda o‘xshaydi.

Masalan:

public interface UserRepository extends JpaRepository<User, Long> {
}

Bu yerda:

User - entity type
Long - ID type

17. Type erasure

Type erasure - Java’da generic type ma’lumotlari compile’dan keyin o‘chiriladi.

Masalan:

List<String> names = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();

Compile’dan keyin JVM uchun ular taxminan shunday ko‘rinadi:

List names = new ArrayList();
List numbers = new ArrayList();

Ya’ni JVM runtime’da List<String> va List<Integer>ni alohida type sifatida saqlamaydi.


17.1 Type erasure oqibatlari

Quyidagi kod ishlamaydi:

if (names instanceof List<String>) {
}

Chunki runtime’da List<String> degan aniq ma’lumot yo‘q.

To‘g‘ri variant:

if (names instanceof List<?>) {
}

17.2 Generic array yaratib bo‘lmaydi

Bu ishlamaydi:

List<String>[] lists = new List<String>[10]; // compile error

Yoki:

T[] array = new T[10]; // compile error

Sababi yana type erasure.


18. Raw type

Raw type - generic classni type bermasdan ishlatish.

Yomon:

List list = new ArrayList();

Yaxshi:

List<String> list = new ArrayList<>();

Yomon:

Map map = new HashMap();

Yaxshi:

Map<Long, User> map = new HashMap<>();

Junior uchun qoida:

Raw type ishlatmang. Har doim generic type ko‘rsating.


19. Diamond operator

Java 7'dan boshlab o‘ng tomonda type’ni qayta yozish shart emas.

Eski usul:

List<String> names = new ArrayList<String>();

Yangi usul:

List<String> names = new ArrayList<>();

Bu <> - diamond operator deyiladi.

Java chap tomondan type’ni o‘zi tushunadi.


20. Optional<T>

Optional ham generic class.

Optional<User> user = findUserById(1L);

Bu degani:

Natija User bo‘lishi ham mumkin, bo‘lmasligi ham mumkin.

Misol:

public Optional<User> findUserById(Long id) {
    if (id == 1L) {
        return Optional.of(new User("Ali"));
    }

    return Optional.empty();
}

Ishlatish:

Optional<User> optionalUser = findUserById(1L);

optionalUser.ifPresent(user -> {
    System.out.println(user.getName());
});

Bu null bilan ishlashni xavfsizroq qiladi.


21. Generic DTO response

Real backend’da umumiy response class yoziladi.

public class ApiResponse<T> {
    private boolean success;
    private String message;
    private T data;

    public ApiResponse(boolean success, String message, T data) {
        this.success = success;
        this.message = message;
        this.data = data;
    }

    public boolean isSuccess() {
        return success;
    }

    public String getMessage() {
        return message;
    }

    public T getData() {
        return data;
    }
}

User qaytarish:

ApiResponse<UserDto> response =
        new ApiResponse<>(true, "User topildi", userDto);

Product qaytarish:

ApiResponse<ProductDto> response =
        new ApiResponse<>(true, "Product topildi", productDto);

List qaytarish:

ApiResponse<List<ProductDto>> response =
        new ApiResponse<>(true, "Productlar topildi", products);

Bu juda foydali. Chunki bitta response class har xil data bilan ishlaydi.


22. Generic service misol

public interface CrudService<T, ID> {
    T findById(ID id);

    List<T> findAll();

    T save(T entity);

    void deleteById(ID id);
}

User service:

public class UserService implements CrudService<User, Long> {
    @Override
    public User findById(Long id) {
        return null;
    }

    @Override
    public List<User> findAll() {
        return List.of();
    }

    @Override
    public User save(User entity) {
        return entity;
    }

    @Override
    public void deleteById(Long id) {
    }
}

Bu yondashuv orqali umumiy CRUD qoidalarini bitta interface’da ushlab turamiz.


23. Generics’da inheritance muammosi

Ko‘pchilik juniorlar shu joyda adashadi.

Integer number = 10;
Number n = number;

Bu ishlaydi. Chunki Integer - Numberning child classi.

Lekin:

List<Integer> integers = new ArrayList<>();
List<Number> numbers = integers; // compile error

Nega?

Chunki agar bunga ruxsat berilsa, quyidagi muammo chiqadi:

List<Integer> integers = new ArrayList<>();
List<Number> numbers = integers;

numbers.add(10.5); // Double qo‘shildi

Integer value = integers.get(0); // muammo

List<Integer> ichiga Double tushib qoladi. Shuning uchun Java buni taqiqlaydi.

To‘g‘ri yondashuv:

List<? extends Number> numbers = integers;

Lekin bu holatda listga yangi element qo‘sha olmaysiz.


24. Method parameterlarda Generics

Yomon:

public void printUsers(List users) {
}

Yaxshi:

public void printUsers(List<User> users) {
}

Yanada umumiy:

public void printAll(List<?> items) {
    for (Object item : items) {
        System.out.println(item);
    }
}

Faqat numberlar uchun:

public void printNumbers(List<? extends Number> numbers) {
    for (Number number : numbers) {
        System.out.println(number);
    }
}

25. Generics bilan eng ko‘p uchraydigan xatolar

Xato 1: Raw type ishlatish

List list = new ArrayList();

To‘g‘ri:

List<String> list = new ArrayList<>();

Xato 2: Generic type’ni noto‘g‘ri tushunish

List<Object> objects = new ArrayList<String>(); // xato

To‘g‘riroq:

List<?> objects = new ArrayList<String>();

Xato 3: extendsga element qo‘shishga urinish

List<? extends Number> numbers = new ArrayList<Integer>();
numbers.add(10); // xato

extends - asosan o‘qish uchun.


Xato 4: superdan aniq type o‘qishga urinish

List<? super Integer> numbers = new ArrayList<Number>();

Integer value = numbers.get(0); // xato

To‘g‘ri:

Object value = numbers.get(0);

Xato 5: Generic array yaratish

T[] array = new T[10]; // xato

Ko‘pincha uning o‘rniga List<T> ishlatiladi.


26. Junior uchun eng muhim qismlar

Generics’da Junior darajada quyidagilarni yaxshi bilish kerak:

Mavzu

Bilish darajasi

List<String> nima

Majburiy

Map<Long, User> nima

Majburiy

Generic class

Kerak

Generic method

Kerak

T, E, K, V

Kerak

? wildcard

Kerak

? extends

Kerak

? super

Kerak

PECS

Juda foydali

Type erasure

Asosiy tushuncha yetadi


27. Amaliy mashq

Vazifa 1: Generic Box

Quyidagi classni yozing:

public class Box<T> {
    private T value;

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

    public T get() {
        return value;
    }
}

Ishlatib ko‘ring:

Box<String> stringBox = new Box<>();
stringBox.set("Hello");

Box<Integer> intBox = new Box<>();
intBox.set(100);

Vazifa 2: Generic method

public static <T> T getFirst(List<T> list) {
    return list.get(0);
}

Quyidagilar bilan test qiling:

List<String> names = List.of("Ali", "Vali");
List<Integer> numbers = List.of(10, 20);

Vazifa 3: Number sum

public static double sum(List<? extends Number> numbers) {
    double result = 0;

    for (Number number : numbers) {
        result += number.doubleValue();
    }

    return result;
}

Quyidagilar bilan ishlating:

sum(List.of(1, 2, 3));
sum(List.of(1.5, 2.5, 3.5));

Vazifa 4: Generic ApiResponse

public class ApiResponse<T> {
    private boolean success;
    private String message;
    private T data;
}

Quyidagi variantlar bilan ishlating:

ApiResponse<String>
ApiResponse<User>
ApiResponse<List<User>>

Xulosa

Generics Java’da type xavfsizligini oshiradi.

Asosiy eslab qolish kerak:

List<String> names
Map<Long, User> users
Optional<User> user
ApiResponse<ProductDto> response

Generics sizga:

  • noto‘g‘ri type qo‘shishni oldini oladi;

  • cast qilishni kamaytiradi;

  • runtime xatolarni compile vaqtida ushlaydi;

  • umumiy class va methodlar yozishga yordam beradi;

  • Spring Boot, JPA, REST response, service layerlarda juda ko‘p ishlatiladi.