Kategorie szkoleń | Egzaminy | Kontakt

Odpowiedź (1)

  • 4

Spróbuję to wyjaśnić na przykładzie...

Załóżmy, że mamy klasę zawierającą metody generyczne:

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

public class Lists {

  public static <E> List<E> getEmptyList() {
    return new ArrayList<E>();
  }

}

Powstaje pytanie: jak użyć metodę getEmptyList i przekazać jej informację o pożądanym typie generycznym?

Z pomocą może przyjść 'type witness'... Użycie może wyglądać następująco:

List<Integer> li = Lists.<Integer>getEmptyList();

Type witness  to sposób na przekazanie informacji o użytym typie generycznym do metody.

No dobrze, ale przecież poniższy kod:

List<Integer> li = Lists.getEmptyList();

też się kompiluje i działa zgodnie z oczekiwaniem...

Jest to rezultatem tzw. wnioskowania typów, które pojawiło się w Javie 7 i zostało ulepszone w Javie 8. Faktyczny typ generyczny może być "odgadnięty" na podstawie typu referencji po stronie lewej.

Czy to oznacza, że konstrukcja 'type witness' jest już zbędna?

Nie do końca... Przyjrzyjmy się następującemu przykładowi:

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

public class Lists {

  public static <E> List<E> getEmptyList() {
    return new ArrayList<E>();
  }

  public static <E> List<E> addAtBeginning(E head, List<E> list) {
    list.add(0, head);
    return list;
  }

  public static void main(String[] args) {
    List<Integer> li = Lists.getEmptyList();         // wiersz 1
    Integer i = Lists.addAtBeginning(11, li).get(0); // wiersz 2
    System.out.println(i); // 11

    List<String> ls = Lists.getEmptyList();            // wiersz 3
    String s = Lists.addAtBeginning("abc", ls).get(0); // wiersz 4
    System.out.println(s); // abc
  }

}

Wszystko działa zgodnie z oczekiwaniem.

Co się jednak stanie, gdy postanowimy scalić w jedną instrukcję wiersze 1 i 2 oraz 3 i 4?

Zawartość metody main będzie wtedy wyglądać następująco:

Integer i = Lists.addAtBeginning(11, Lists.getEmptyList()).get(0); // błąd kompilacji
System.out.println(i); 

String s = Lists.addAtBeginning("abc", Lists.getEmptyList()).get(0); // błąd kompilacji
System.out.println(s);

Tym razem kod się nie kompiluje (komunikat w pierwszym przypadku: cannot convert from Object to Integer).

Informacja o typie generycznym używanym przez metodę jest niedostępna (wnioskowanie nie działa w bardziej zawiłych konstrukcjach).

Sposobem na "poprawienie kodu" może być użycie type witnesses:

Integer i = Lists.addAtBeginning(11, Lists.<Integer>getEmptyList()).get(0); 
System.out.println(i); // 11

String s = Lists.addAtBeginning("abc", Lists.<String>getEmptyList()).get(0);
System.out.println(s); // abc

 

  • Odpowiedział
  • @ | 06.12.2015
  • TRENER MODERATOR ALTKOM AKADEMII