Java Generics-metoda brydżowa?

Coś, co nazywa się "metodą mostkową", związane z generykami Javy, skłoniło mnie do zatrzymania się i przemyślenia tego.

Btw, wiem tylko, że występuje w bytecode level and is not available do wykorzystania.

Ale chętnie poznam koncepcję "metody mostowej" używanej przez kompilator Javy.

Co dokładnie dzieje się za kulisami i dlaczego jest używany?

Każda pomoc z przykładem będzie bardzo mile widziana.

Author: Charles, 2011-02-15

3 answers

Jest to metoda, która pozwala klasie rozszerzającej klasę generyczną lub implementującej interfejs generyczny (z konkretnym parametrem typu) nadal być używana jako typ surowy.

Wyobraź sobie to:

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }
}

To nie może być użyte w jego surowej formie, przechodząc dwa Object s do porównania, ponieważ typy są kompilowane w metodzie compare(w przeciwieństwie do tego, co by się stało, gdyby był to ogólny parametr typu T, gdzie Typ zostanie usunięty). Więc zamiast tego, za kulisami, kompilator dodaje " most metoda", która wygląda mniej więcej tak (gdyby to było źródło Javy):

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }

   //THIS is a "bridge method"
   public int compare(Object a, Object b) {
      return compare((Integer)a, (Integer)b);
   }
}

Kompilator chroni dostęp do metody bridge, wymuszając, że jawne wywołania bezpośrednio do niej powodują błąd w czasie kompilacji. Teraz klasa może być również używana w postaci surowej:

Object a = 5;
Object b = 6;

Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);

Dlaczego jeszcze jest to potrzebne?

Oprócz dodawania wsparcia dla jawnego użycia typów surowych (co jest głównie dla wstecznej kompatybilności), metody bridge są również wymagane do obsługi kasowania typów. Z typem kasowanie, metoda taka jak ta:

public <T> T max(List<T> list, Comparator<T> comp) {
   T biggestSoFar = list.get(0);
   for ( T t : list ) {
       if (comp.compare(t, biggestSoFar) > 0) {
          biggestSoFar = t;
       }
   }
   return biggestSoFar;
}

Jest w rzeczywistości skompilowany do kodu bajtowego zgodnego z tym:

public Object max(List list, Comparator comp) {
   Object biggestSoFar = list.get(0);
   for ( Object  t : list ) {
       if (comp.compare(t, biggestSoFar) > 0) {  //IMPORTANT
          biggestSoFar = t;
       }
   }
   return biggestSoFar;
}

Jeśli metoda bridge nie istnieje i przekazałeś List<Integer> i MyComparator do tej funkcji, wywołanie linii oznaczonej IMPORTANT zakończy się niepowodzeniem, ponieważ MyComparator nie ma metody o nazwie compare, która zajmuje dwa Object s...tylko jeden, który zajmuje dwa Integer s.

Poniżej FAQ jest dobrą lekturą.

Zobacz Też:

 63
Author: Mark Peters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:31

Warto zauważyć, że kompilator wnioskuje , że MyComparator'S metoda:

public int compare(Integer a, Integer b) {/* code */}

Próbuje nadpisać Comparator<T>'s

public int compare(T a, T b);

Z deklarowanego typu Comparator<Integer>. W przeciwnym razie, MyComparator's compare będzie traktowana przez kompilator jako dodatkowa (przeciążająca), a nie nadpisująca metoda. I jako taki nie stworzyłby dla niego żadnej metody pomostowej.

 0
Author: Callistus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-02 22:45:08

Jeśli chcesz zrozumieć, dlaczego potrzebujesz metody bridge, lepiej zrozumieć, co się bez niej dzieje. Załóżmy, że nie ma metody bridge.

class A<T>{
  private T value;
  public void set(T newVal){
    value=newVal
  }
}

class B extends A<String>{
  public void set(String newVal){
    System.out.println(newVal);
    super.set(newVal);
  }
}

Zauważ, że po usunięciu, Metoda set W A stała się public void set(Object newVal), ponieważ nie jest związana z parametrem typu T. nie ma metody w klasie B, której podpis jest taki sam jak set W A. więc nie ma nadpisywania. Stąd, gdy coś takiego się stało:

A a=new B();
a.set("Hello World!");

Polimorfizm tu nie zadziała. Pamiętaj, że musisz obejść metoda klasy rodzica w klasie potomnej, dzięki której można użyć klasy rodzica var do wywołania polimorfizmu.

To, co robi metoda bridge, polega na cichym nadpisywaniu metody w klasie nadrzędnej wszystkimi informacjami z metody o tej samej nazwie, ale innej sygnaturze. Przy pomocy metody mostkowej zadziałał polimorfizm. Chociaż na powierzchni, nadpisujesz metodę klasy nadrzędnej metodą o innej sygnaturze.

 0
Author: ch48h2o,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-30 09:59:30