Как происходит стирание типа Java, когда для приведения используется параметр типа? - PullRequest
0 голосов
/ 19 сентября 2019

Я знаю, что обычно параметры несвязанного типа заменяются на Object во время компиляции.Но как работает этот фрагмент кода?

<T> void call(List<T> list, Object o) {
    fun((T) o);
}

Будет ли он скомпилирован в

void call(List list, Object o) {
    fun((Object) o);
}

Это выглядит как неправильный случай, потому что o должен быть приведен к тому же типу, что иэлементы в списке?

Ответы [ 3 ]

2 голосов
/ 19 сентября 2019

Из-за стирания типа, даже если ваш тип A, он будет рассматриваться как Object в вашем примере, как вы уже догадались.это означает, что если вы передали второй элемент, отличный от A, он будет фактически преобразован в Object.

Пример,

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

public class TypeErasure {

    static <A> void call(List<A> list, Object elem) {
        A o1 = (A) elem;
        System.out.println(o1);
    }

    static void callV2(List list, Object elem) {
        System.out.println(elem);
    }

    //bounded type
    static <A extends Number> void callV3(List<A> list, Object elem) {
        A o1 = (A) elem;
        System.out.println(o1);
    }

    public static void main(String[] args) {
        call(new ArrayList<Integer>(), "trying to cast string to Integer");
        callV2(new ArrayList<Integer>(), "trying to cast string to Integer");

        //will be casted to Number
        callV3(new ArrayList<Integer>(), 1);
        callV3(new ArrayList<Double>(), 1.5);
        callV3(new ArrayList<Long>(), 1L);

        // following will fail at runtime with ClassCastException
        /* Exception in thread "main" java.lang.ClassCastException: 
           class java.lang.String cannot be cast to class java.lang.Number 
          (java.lang.String and java.lang.Number are in 
           module java.base of loader 'bootstrap')
        */
        callV3(new ArrayList<Integer>(), "trying to cast string to Integer");
    }

}
1 голос
/ 19 сентября 2019

Нет, потому что информация о типе доступна в java только во время выполнения, следовательно, она не будет компилироваться с чем-то более конкретным, чем Object.Другой случай был бы, если бы был связан параметр типа T, например:

 <T extends Number> void call(List<T> list, Object o) {
     fun((T) o);
 }

Тогда компилятор не знает точный тип во время компиляции, но он знает, что это подтип Number, поэтому, если метод fun использует Number в качестве параметра, он будет компилироваться в отличие от первого примера.

Более подробную информацию можно получить здесь .

0 голосов
/ 19 сентября 2019

Будет ли он скомпилирован в

Нет, приведение не будет вставлено, если предел равен Object, потому что приведение к Object всегда выполняется успешно.

Если переменная типа ограничена, например, T extends Number, то будет вставлена ​​инструкция checkcast, чтобы o было Number, что эквивалентно (Number) o.

. Вы можете заметить, чтокомпилятор генерирует непроверенное предупреждение в этой строке.Непроверенное предупреждение означает, что компилятор не может вставить байт-код, чтобы гарантировать, что o является, в частности, экземпляром T.


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

void call(List<?> list, Object o) {
    fun(o);
}

Приведение не требуется, поскольку fun должен быть в состоянии принять любой Object в любом случае.

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