Подтвердить что ты не робот

Почему стирание типа Java не нарушает это?

public class Test {
    public static class Nested<T> {
        public T val;
        Nested(T val) { this.val = val; }
    }
    public static void main(String[] args) {
        Nested<Integer> a = new Nested<Integer>(5);
        Nested<Integer> b = new Nested<Integer>(2);
        Integer diff = a.val - b.val;
    }
}

Приведенный выше код работает нормально. Однако, если я добавлю метод в Nested:

T diff(Nested<T> other) { return this.val - other.val; }

Я получаю ошибку компиляции:

operator - cannot be applied to T,T

Это имеет смысл для меня. Тип T стирается во время выполнения, поэтому Java не может применить оператор, который определен только для определенных классов, таких как Integer. Но почему работает a.val - b.val?

Изменить:

Много хороших ответов. Всем спасибо. Суть его, если я правильно понимаю, заключается в том, что компилятор может добавлять приведения в Integer в a.val - b.val, потому что он знает a и b, были созданы как Nested<Integer > . Однако, поскольку this.val - other.val происходит внутри тела определения общей функции (где T все еще может быть чем угодно), компилятор не может добавить приведения, которые необходимы для создания "-". Это приводит к более интересному вопросу, а именно: если компилятор Java мог бы встраивать, можно ли использовать общую функцию, такую ​​как diff?

4b9b3361

Ответ 1

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

Вы поняли, что внутри метода T не известно Integer, поэтому оператор минус - не может быть применен. Однако, когда вы находитесь в main(), вне универсального метода, компилятор знает, что вы создали экземпляр Nested с Integer, поэтому он очень хорошо знает, как применить оператор. Несмотря на то, что реализация generic удалила тип для создания кода для Nested<T>, компилятор не думает о a и b в терминах Nested<T>: у него достаточно знаний, чтобы вставить соответствующий бросок, отмените результаты и примените оператор минус -.

Ответ 2

Вы получаете ошибку времени компиляции, а не время выполнения.

public static void main(String[] args) {
    Nested<Integer> a = new Nested<Integer>(5);
    Nested<Integer> b = new Nested<Integer>(2);
    Integer diff = a.val - b.val;
}

Здесь компилятор знает, что оба T равны Integer. Вы только что объявили <Integer>.

T diff(Nested<T> other) { return this.val - other.val; }

Здесь компилятор не уверен в T. Это может быть что угодно. И только оператор numeric - не допускается ни для чего.

Ответ 3

a.val - b.val работает, потому что он проверяется компилятором, а не во время выполнения. Компилятор "видит", что вы используете <Integer> и он компилируется и работает Ok, во время выполнения нет проблем даже с стиранием, потому что компилятор уже подтвердил это.

Ответ 4

Потому что вызов метода во время выполнения и a.val - b.val проверяется во время компиляции.

  • В первом случае компилятор знает, что тип Integer и - операция разрешена для целых чисел.
  • Во втором случае тип T заранее неизвестен компилятору, поэтому он не уверен, действительна ли операция - или нет. Следовательно, ошибка компилятора.

Рассмотрим, что мы используем метод как diff(Nested<Book> other), поэтому нет возможности вычитать книгу из другого.

Ответ 5

Поскольку код не живет в Nested, тип известен. Компилятор ясно видит, что a.val - b.val является Integer минус целое число, которое может быть автоматически загружено. Компилятор переписывает его на

Integer diff = Integer.valueOf(((Integer) a.val).intValue() - ((Integer) b.val).intValue())

Вызовы .intValue и .valueOf относятся к автоматическому боксу и автоматической распаковке.

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

Правда, технически, может быть что-то другое, как объект Calendar, поскольку тип неизвестен во время выполнения. Но если вы используете generics, компилятор верит, что вы не делаете ничего глупого, чтобы обойти его. Поэтому, если a.val или b.val были чем-то другим, кроме целых, исключение ClassCastException было бы запущено во время выполнения.