Почему мы не можем перегружать методы, основанные на типичном типе списка [duplicate]

Вы можете увидеть все шаги для подключения базы данных MySQL из приложения Java здесь . Для другой базы данных вам просто нужно изменить драйвер только на первом шаге. Убедитесь, что вы предоставили правильный путь к базе данных и исправили имя пользователя и пароль.

Посетите http://apekshit.com/t/51/Steps-to-connect-Database-using-JAVA

125
задан Peter Mortensen 27 September 2015 в 08:04
поделиться

7 ответов

В основном это то, как генерические средства реализуются на Java через компиляцию. Скомпилированный общий код на самом деле просто использует java.lang.Object везде, где вы говорите о T (или каком-либо другом параметре типа), - и есть некоторые метаданные, чтобы сообщить компилятору, что он действительно является общим типом.

Когда вы компилируете какой-либо код против общего типа или метода, компилятор разрабатывает то, что вы действительно имеете в виду (то есть, что такое аргумент типа для T) и проверяет время компиляции , которое вы делаете правильные вещи, но испущенный код снова просто говорит в терминах java.lang.Object - компилятор при необходимости создает дополнительные приведения. Во время выполнения List<String> и List<Date> точно совпадают; Дополнительная информация о типе была удалена компилятором.

Сравните это, скажем, с C #, где информация сохраняется во время выполнения, позволяя коду содержать выражения, такие как typeof(T), что эквивалентно T.class - за исключением того, что последнее недействительно. (Есть дополнительные различия между .NET-генераторами и Java-дженериками, заметьте.) Стирание типа является источником многих «нечетных» предупреждений / сообщений об ошибках при работе с генериками Java.

Другие ресурсы:

177
ответ дан Aniket Sahrawat 25 August 2018 в 18:07
поделиться

Erasure, буквально означает, что информация о типе, которая присутствует в исходном коде, удаляется из скомпилированного байт-кода. Давайте поймем это с помощью некоторого кода.

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

public class GenericsErasure {
    public static void main(String args[]) {
        List<String> list = new ArrayList<String>();
        list.add("Hello");
        Iterator<String> iter = list.iterator();
        while(iter.hasNext()) {
            String s = iter.next();
            System.out.println(s);
        }
    }
}

Если вы скомпилируете этот код и затем декомпилируете его с помощью декомпилятора Java, вы получите что-то вроде этого. Обратите внимание, что декомпилированный код не содержит следов информации о типе, присутствующей в исходном исходном коде.

import java.io.PrintStream;
import java.util.*;

public class GenericsErasure
{

    public GenericsErasure()
    {
    }

    public static void main(String args[])
    {
        List list = new ArrayList();
        list.add("Hello");
        String s;
        for(Iterator iter = list.iterator(); iter.hasNext(); System.out.println(s))
            s = (String)iter.next();

    }
} 
22
ответ дан Blorgbeard 25 August 2018 в 18:07
поделиться

В дополнение к уже дополненному ответу Джона Скита ...

Было отмечено, что реализация дженериков посредством стирания приводит к некоторым раздражающим ограничениям (например, нет new T[42]). Также было упомянуто, что основной причиной для этого является обратная совместимость в байтекоде. Это также (в основном) верно. Генерируемый байт-код -target 1.5 несколько отличается от просто дезаваренного литья -target 1.4. Технически даже возможно (через огромные хитрости) получить доступ к экземплярам универсального типа во время выполнения , доказывая, что в байткоде действительно что-то есть.

Более интересный момент (который не было поднято) заключается в том, что реализация генерических средств, использующих стирание, предлагает довольно большую гибкость в том, что может сделать система высокого уровня. Хорошим примером этого может быть реализация JVM Scala и CLR. На JVM можно реализовать более высокие виды напрямую из-за того, что сам JVM не налагает ограничений на общие типы (поскольку эти «типы» фактически отсутствуют). Это контрастирует с CLR, который имеет знание времени исполнения параметров. Из-за этого сам CLR должен иметь некоторую концепцию использования дженериков, сводя на нет попытки расширить систему с непредвиденными правилами. В результате, более высокие виды Scala в среде CLR реализованы с использованием странной формы стирания, эмулируемой в самом компиляторе, что делает их не полностью совместимыми с обычными генерирующими .NET.

Erasure может быть неудобно, когда вы хотите совершать непослушные вещи во время выполнения, но это дает максимальную гибкость авторам компилятора. Я предполагаю, что это часть того, почему он не уходит в ближайшее время.

8
ответ дан Daniel Spiewak 25 August 2018 в 18:07
поделиться

В версии java 1.5 вводится общее программирование. Прежде всего, что общего в java? Общее программирование - это безопасный объект типа. Перед общим набором в коллекции мы можем хранить любой тип объекта. и после генерации мы должны хранить данные определенного типа объекта.

В чем преимущества Generic? Основными преимуществами родового является то, что литье по типу не требуется, а также тип-мудрец и Generic будут проверять время компиляции. и общий синтаксис Generic - это ClassOrInterface здесь type - это сигнал, который этот класс мог бы установить для класса при его создании

Пример . GenericClassDemo

genericclassDemo = новый GenericClassDemo (Employee.java)

-3
ответ дан JegsVala 25 August 2018 в 18:07
поделиться

Так же, как примечание, интересно посмотреть, что делает компилятор, когда он выполняет стирание, - это упрощает понимание всей концепции. Существует специальный флаг, который вы можете передать компилятору для вывода java-файлов, в которых были сгенерированы дженерики и вставлены листы. Пример:

javac -XD-printflat -d output_dir SomeFile.java

-printflat - это флаг, который передается компилятору, который генерирует файлы. (Часть -XD - это то, что сообщает javac передать ее исполняемому банку, который на самом деле выполняет компиляцию, а не только javac, но я отвлекаюсь ...) -d output_dir необходим, потому что компилятору нужно какое-то место для размещения новых .java-файлов.

Это, конечно, не просто стирает; все автоматические вещи, которые делает компилятор, делается здесь. Например, встроены конструкторы по умолчанию, новые петли for в стиле foreach расширены до регулярных циклов for и т. Д. Приятно видеть мелкие вещи, которые происходят автоматически.

36
ответ дан jigawot 25 August 2018 в 18:07
поделиться

Как я понимаю (будучи участником .NET ), JVM не имеет понятия дженериков, поэтому компилятор заменяет параметры типа Object и выполняет все литье для вы.

Это означает, что дженерики Java - это ничего, кроме синтаксического сахара, и не предлагают какого-либо повышения производительности для типов значений, которые требуют бокса / распаковки при передаче по ссылке.

25
ответ дан Peter Mortensen 25 August 2018 в 18:07
поделиться

Есть хорошие объяснения. Я добавляю только пример, показывающий, как стирание типа работает с декомпилятором.

Исходный класс,

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


public class S<T> {

    T obj; 

    S(T o) {
        obj = o;
    }

    T getob() {
        return obj;
    }

    public static void main(String args[]) {
        List<String> list = new ArrayList<>();
        list.add("Hello");

        // for-each
        for(String s : list) {
            String temp = s;
            System.out.println(temp);
        }

        // stream
        list.forEach(System.out::println);
    }
}

Декомпилированный код из его байт-кода,

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Consumer;

public class S {

   Object obj;


   S(Object var1) {
      this.obj = var1;
   }

   Object getob() {
      return this.obj;
   }

   public static void main(String[] var0) {

   ArrayList var1 = new ArrayList();
   var1.add("Hello");


   // for-each
   Iterator iterator = var1.iterator();

   while (iterator.hasNext()) {
         String string;
         String string2 = string = (String)iterator.next();
         System.out.println(string2);
   }


   // stream
   PrintStream printStream = System.out;
   Objects.requireNonNull(printStream);
   var1.forEach(printStream::println);


   }
}
0
ответ дан snr 25 August 2018 в 18:07
поделиться
Другие вопросы по тегам:

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