Непроверенное поведение приведения с назначением переменной и без - PullRequest
3 голосов
/ 31 мая 2019

Почему первая строка в main не генерирует ClassCastException, а вторая?

import java.util.function.Function;

class Scratch {

    static <T> T getSomething(Function<Integer, T> fun) {
        return (T) fun;
    }

    public static void main(String[] args) {
        Scratch.<String>getSomething(x -> "hello");
        String something = Scratch.<String>getSomething(x -> "hello");
    }
}

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Разница в том, что вы не используете результат метода в первом случае, но вы используете во втором.

Приведение - это выражение , но это не такStatementExpression.Это означает, что вы не можете написать это:

(String) somethingReturningAString();

, но вы можете написать:

String aString = (String) somethingReturningAString();

Во время компиляции компилятор вставляет checkcast инструкции, где это необходимо, игде он может:

  • Невозможно вставить приведение для первого случая, поэтому проверка не выполняется.
  • Может (и должен) вставить приведение во второй случайслучай, чтобы гарантировать, что он присваивает что-то, что на самом деле String переменной String.Таким образом, он проверяет приведение, и это не удается.

Стоит отметить, что есть некоторые, возможно, неожиданные случаи, когда приведение не строго необходимо, новставлен.Например:

Scratch.<String>getSomething(x -> "hello").toString();

потерпит неудачу с ClassCastException, поскольку он будет преобразован в:

((String) Scratch.getSomething(x -> "hello")).toString();

, даже если Object имеет метод toString(), и поэтомуэто может вызвать это без приведения.

1 голос
/ 31 мая 2019

Обобщения - это только проверка времени компиляции (читайте о стирании типа ). Итак, во время выполнения ваш getSomething() метод выглядит примерно так:

static Object getSomething(Function fun) {
    return fun;
}

Теперь вы ясно видите, что первая строка никогда не выдаст исключение

Scratch.getSomething(x -> "hello");

, поскольку Function является Object и, следовательно, может быть возвращено без проблем.

Вторая строка, однако, будет бросать одну, потому что она будет выглядеть примерно так:

String something = (String) Scratch.getSomething(x -> "hello");

A Function по-прежнему Object, поэтому его можно вернуть из метода, но это не String и, таким образом, вы получите ClassCastException.

Код прекрасно компилируется, потому что вы указываете компилятору, что знаете, что делаете. Вы получите предупреждение Unchecked cast в этой строке:

 return (T) fun;

Это предупреждение должно указывать вам, программисту, на то, что он (компилятор) не может быть уверен, что приведение выполнится успешно.

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