Как реализуются общие методы интерфейса [duplicate]

Ваш код getElementById() работает, поскольку идентификаторы должны быть уникальными, и поэтому функция всегда возвращает ровно один элемент (или null, если ни один не найден).

Однако getElementsByClassName() , querySelectorAll() и другие методы getElementsBy* возвращают массивный набор элементов. Итерации над ним, как и с реальным массивом:

var elems = document.getElementsByClassName('myElement');
for(var i = 0; i < elems.length; i++) {
    elems[i].style.size = '100px';
}

Если вы предпочитаете что-то более короткое, рассмотрите использование jQuery :

$('.myElement').css('size', '100px');

50
задан Charles 30 May 2012 в 21:58
поделиться

3 ответа

Это метод, который позволяет классу, расширяющему общий класс или реализующему общий интерфейс (с конкретным параметром типа), все еще использоваться как необработанный тип.

Представьте себе:

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

Это невозможно использовать в его исходной форме, передавая два Object s для сравнения, поскольку типы компилируются в метод сравнения (в отличие от того, что произойдет, если бы это был типичный параметр типа T, где тип будет удален). Вместо этого, за кулисами, компилятор добавляет «мостовой метод», который выглядит примерно так (был ли он источником Java):

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);
   }
}

Компилятор защищает доступ к мостовому методу, обеспечивая его явное вызовы непосредственно к нему приводят к ошибке времени компиляции. Теперь класс может использоваться и в его необработанном виде:

Object a = 5;
Object b = 6;

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

Зачем еще это нужно?

В дополнение к добавлению поддержки явного использования необработанных типов (что в основном для обратной совместимости), мосты также необходимы для поддержки стирания стилей. С стиранием типа такой метод:

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;
}

фактически скомпилирован в байт-код, совместимый с этим:

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;
}

Если мостовой метод не существует, и вы передали List<Integer> и MyComparator к этой функции, вызов в строке с тегами IMPORTANT потерпел бы неудачу, так как у MyComparator не было бы метода, называемого compare, который принимает два Object s ... только один, который принимает два Integer s.

Часто задаваемые вопросы ниже - хорошее чтение.

См. также:

63
ответ дан Community 22 August 2018 в 15:20
поделиться
  • 1
    Также для ковариантных типов возврата даже при отсутствии дженериков. – Tom Hawtin - tackline 16 February 2011 в 04:58
  • 2
    @paulmurray: что такое «равно (T o)»? – user102008 30 May 2012 в 22:50
  • 3
    @gstackoverflow Предположим, что у вас есть метод Object get(), а затем переопределите его в подклассе, скажем, String get(). JVM будет только перекрывать точно совпадающие подписи, включая тип возврата. Поэтому javac создает синтетический мостовой метод Object get() (a.k.a. get()Ljava/lang/Object;) с реализацией, которая вызывает String get() (a.k.a. get()Ljava/lang/String;). Это возможно только в исходном коде с 1,5, и вы не можете настроить таргетинг на более раннюю версию байт-кода, чем исходный код. – Tom Hawtin - tackline 15 June 2014 в 18:58
  • 4
    @AndrewTobilko: Да, это публично, как сообщается в javap -v MyComparator.class. Однако, как я уже упоминал, компилятор не позволяет вам вызвать метод моста непосредственно на параметризованном типе, поэтому я бы сказал, что это «общедоступно с оговоркой». Если вы посмотрите на вывод javap, вы увидите, что метод моста, несмотря на наличие ACC_PUBLIC, имеет два дополнительных флага: ACC_BRIDGE и ACC_SYNTHETIC. Это то, что компилятор будет использовать для запрета доступа. – Mark Peters 30 August 2016 в 14:37
  • 5
    @AndrewTobilko: Обратите внимание, что это также не означает, что все модовые методы являются общедоступными, только один в моем примере. Если вы расширили класс (и предоставили ему конкретный тип) с помощью защищенного общего метода и переопределили его защищенным методом, метод моста был бы защищен для соответствия. – Mark Peters 30 August 2016 в 14:44

Следует отметить, что компилятор описывает метод MyComparator:

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

пытается переопределить Comparator<T>

public int compare(T a, T b);

из объявленный тип Comparator<Integer>. В противном случае MyComparator 's compare будет обрабатываться компилятором как дополнительный (перегруженный), а не метод переопределения. И как таковой, для него не будет создан мостовой метод.

0
ответ дан Callistus 22 August 2018 в 15:20
поделиться

Если вы хотите понять, зачем вам нужен метод моста, вы лучше поймете, что произойдет без него. Предположим, что не существует мостового метода.

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);
  }
}

Обратите внимание, что после стирания метод set в A стал public void set(Object newVal), поскольку на параметре типа T нет ограничений. В классе B нет метода сигнатура которого совпадает с set в A. Таким образом, переопределение отсутствует. Следовательно, когда произошло что-то подобное:

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

Полиморфизм здесь не будет работать. Помните, что вам нужно переопределить метод родительского класса в дочернем классе, чтобы вы могли использовать родительский класс var для инициирования полиморфизма.

. Что такое метод моста, он молча переопределяет метод в родительском классе со всей информацией из метод с тем же именем, но с другой подписью. С помощью мостового метода работал полиморфизм. Хотя на первый взгляд вы переопределяете метод родительского класса методом различной подписи.

0
ответ дан ch48h2o 22 August 2018 в 15:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: