Typy wieloznaczne a generyczne java

0

Jaka jest roznica miedzy Pair<?> a Pair <T>?
Jaka jest roznica miedzy Pair<? extends Employee> a Pair<T extends Employee>?

1

Dzięki wildcardom można mieć np. heterogeniczne listy z kontrolą typów (chociaż nawet zbyt ograniczającą):

package org.example;

import java.util.ArrayList;
import java.util.List;

public class Wildcards {
    static class Aaa<T> {
        T get() {
            return null;
        }

        void set(T input) {
        }
    }

    public static void main(String[] args) {
        List<Aaa<?>> heterogeneous = new ArrayList<>();
        heterogeneous.add(new Aaa<Integer>());
        heterogeneous.add(new Aaa<String>());
        processHeterogeneousList(heterogeneous);
        var item0 = heterogeneous.get(0);
        var item1 = heterogeneous.get(1);
        // item0.set(item0.get()); // won't compile, but seems too restrictive
        // item0.set(item1.get()); // won't compile, OK because types are unrelated
        // item1.set(item0.get()); // won't compile, OK because types are unrelated
        // item1.set(item1.get()); // won't compile, but seems too restrictive
    }

    static void processHeterogeneousList(List<Aaa<?>> heterogeneous) {
        for (Aaa<?> elem : heterogeneous) {
            // elem.set(elem.get()); // won't compile, but seems too restrictive
            getAndSet(elem); // passing Aaa<?> as Aaa<T> lifts restrictions from above comment
        }
    }

    static <T> void getAndSet(Aaa<T> obj) {
        obj.set(obj.get());
    }
}

Zaawansowany ficzur. Żaden korpo-javowiec tego nie używa. Z drugiej strony wildcardy pojawiają się w bibliotece standardowej, np. w java.util.Collections#sort(java.util.List<T>)

public static <T extends Comparable<? super T>> void sort(List<T> list)

Spróbuję zrobić coś szalonego z tą metodą, ale nie wiem na ile są szanse, że mi się uda.

Aktualizacja: a może jednak nie będę robił nic szalonego :) Popatrzcie na te przykłady: https://stackoverflow.com/a/51682457 https://stackoverflow.com/a/35715359

2

@Ro3ert:
Zgłębiasz bo masz legacy projekt np. Java 1.3?
To polecam https://www.amazon.com/Java-Generics-Collections-Development-Process/dp/0596527756
Maurice Naftalin, Java Generics and Collections

Jak "Czesc, ucze sie programowac w springu," (styczeń 2021)
To polecam https://www.amazon.com/Effective-Java-Joshua-Bloch/dp/0134685997/
Joshua Bloch, Effective Java

Więcej jak zrozumienie PECS (Producer Extends, Consumer Super) nie będzie ci potrzebne

Klasa Animal, dziedziczą po niej klasy Cat i Dog

public class Animal {

    @Override
    public String toString() {

        return getClass().getSimpleName();
    }
}
public class Cat extends Animal {}
public class Dog extends Animal {}

Metoda kopiowania z jednej kolekcji do drugiej

    public <T> void copy(Collection<? extends T> src, Collection<? super T> dst) {

        dst.addAll(src);
    }

Przykład PECS

    public static void main(String[] args) {

        List<Cat> catList = new ArrayList<>();
        List<Animal> animalList = new ArrayList<>();

        catList.add(new Cat());
        
        animalList.add(new Animal());
        animalList.add(new Cat());
        animalList.add(new Dog());

        for (Animal animal : animalList) {
            System.out.println(animal);
        }
        for (Cat cat : catList) {
            System.out.println(cat);
        }
        System.out.println();
        copy(catList, animalList);
        System.out.println(animalList);
    }

    private static <T> void copy(Collection<? extends T> src, Collection<? super T> dst) {

        dst.addAll(src);
    }

Producer - lista kotów - ma być skopiowana do innej listy.
Jakie warunki?
Można dołączyć koty z listy src do kotów na liście kotów dst
albo
Można dołączyć kory z listy src do kotów na liście określonej ogólnie jako zwierzęta dst

copy(animalList, catList);

nie skompiluje się.
Bo nie można z listy zawierającej ogólnie zwierzęta np psy dodać wszystko jak leci do listy która jasno jest określona "tylko koty" (pies z kotem nie zgodzą się).

Producer extends Cat (koty lub podklasa koty perskie)
Consumer super Cat (też koty albo ogólnie zwierzęta bo zapewniono, że nie ma znaczenia, że są razem - np. osobne klatki)

Z typowych przykładów codziennego użytku jeszcze

<T extends Comparable<? super T>> 

/ https://docs.oracle.com/javase/8/docs/api/java/util/class-use/Comparator.html /

I wystarczy ;)

0

Tu masz wszystko opisane z przykładami, wróć z konkretnym problemem, niektórzy mają chyba za dużo wolnego czasu, że tworzą na forum własne tutoriale :) https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html

0

Suma liczb

        final List<? extends Number> numbers = List.of(1, 2L, 3.0, 4.0F, 0x5);
        final double total = total(numbers);
        final double weirdTotal = weirdTotal(numbers);

Po Bożemu

    private static <T extends Number> double total(Collection<T> numbers) {

        double total = 0.0;
        for (T number : numbers) {
            total += number.doubleValue();
        }

        return total;
    }

Albo iść w tutoriale sun/oracle

private static double weirdTotal(Collection<? extends Number> numbers) {

        return helper(numbers);
    }

    private static <E extends Number> double helper(Collection<E> numbers) {

        double total = 0.0;
        for (E number : numbers) {
            total += number.doubleValue();
        }

        return total;
    }

Ale po co?
Przyjdzie najbardziej pożądany przez pracodawców programista w 2021 roku - fullstack - i powstanie pytanie, na czym się zacznie wykładać, bo coś jest przekombinowane?
Przyszedł z frontendowymi korzeniami to na cudach Java "bo się SonarLint pluje"
Przyszedł z Javą we krwi to zrobi cuda i sztuczki a na barddziej frontendowej części będą cuda.

Keep It Simple Sweetheart

3

? to typ nieznany.
T to typ ograniczony.

Np. moze byc

Pair<T>
T jeden;
T dwa;

Deklarujac np.

Pair<JakisObiekt>

bedzie to:

JakisObiekt jeden;
JakisObiekt dwa;

Beda to te same typy.

Nie zadeklarujesz:

? jeden;
? dwa;

Ale zadeklarujesz juz:

T jeden;
E dwa; 

T mozesz zwrocic:

return T;

A ? nie zwrocisz.

1

@zgrzyt:
Typy wieloznaczne (wildcardy, ?) istnieją po to, by zwiększyć możliwości generyków. Same w sobie (tzn. nie będące parametrami typów generycznych) nie mają sensu, bo można je zastąpić konkretnym typem nadrzędnym, czyli java.lang.Object.

? metoda() {
  ? a = ...;
  ? b = ...;
  return połącz(a, b);
}

Zamiast powyższego możesz zrobić poniższe bez żadnej straty ogólności:

Object metoda() {
  Object a = ...;
  Object b = ...;
  return połącz(a, b);
}

Rozsądne jest odrzucanie pierwszej składni przez kompilator, bo jest nadmiarowa, a wildcardy są rzadko spotykane i rzadko rozumiane.

Natomiast List<Aaa<Object>> i List<Aaa<?>> to dwa zupełnie różne typy. Do pierwszej listy wstawimy tylko obiekty mogące być bezpiecznie zrzutowane na Aaa<Object> (w sensie kompilator statycznie ma stwierdzić, że to jest OK), a do drugiej możemy wstawić jednocześnie Aaa<Integer>, Aaa<String> itd

1

Ktoś ma wątpliwości co ma być z tym pytajnikiem

?

Niech zapisze sobie w rozwiniętej wersji

<? extends Object>

i wtedy powinno być jasne.

KISS, DRY, SOLID, YAGNI itd

1 użytkowników online, w tym zalogowanych: 0, gości: 1