Если я пытаюсь привести String
к a java.util.Date
, компилятор Java ловит ошибку. Так почему же компилятор не помечает следующее как ошибку?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Конечно, JVM генерирует a ClassCastException
во время выполнения, но компилятор не помечает его.
Поведение то же самое с javac 1.8.0_212 и 11.0.2.
java
casting
compiler-errors
javac
Майк Войноски
источник
источник
List
.Date d = (Date) new Object();
strList
был экземпляром класса, который реализует List.Ответы:
Актерское это технически возможно. Javac не может легко доказать, что это не так в вашем случае, и JLS фактически определяет это как допустимую Java-программу, поэтому пометка ошибки будет неправильной.
Это потому, что
List
это интерфейс. Таким образом, у вас может быть подкласс класса a,Date
который на самом деле реализуетList
замаскированный какList
здесь - и затем приведение к немуDate
будет совершенно нормально. Например:А потом:
Обнаружение такого сценария не всегда возможно, так как для этого потребуется информация времени выполнения, если экземпляр поступает, например, из метода. И даже если это потребует гораздо больше усилий для компилятора. Компилятор только предотвращает приведения, которые абсолютно невозможны из-за невозможности сопоставления дерева классов. Что не так здесь, как видно.
Обратите внимание, что JLS требует, чтобы ваш код был допустимой программой Java. В 5.1.6.1. Разрешено сужающее ссылочное преобразование :
Таким образом, даже если компилятор может выяснить, что ваш случай действительно доказуемо невозможен, он не может пометить ошибку, потому что JLS определяет ее как допустимую программу Java.
Было бы разрешено только показать предупреждение.
источник
myDate = (Date) myString
неудачу. Используя терминологию JLS, оператор пытается преобразовать изS
(theString
) вT
(theDate
). ЗдесьS
не тип интерфейса, поэтому приведенное выше условие JLS не применяется. В качестве примера попробуйте привести Календарь к дате, и вы получите ошибку компилятора, даже если ни один из классов не является окончательным.Date & List
не пригоден для жизни , недостаточно просто доказать, что он необитаем в настоящее время (это может произойти в будущем).Давайте рассмотрим обобщение вашего примера:
Это основные причины, почему
Date d = (Date) strList;
не ошибка компиляции.Интуитивная причина в том , что компилятор не (в целом) знать точный тип объекта , возвращаемого этим методом вызова. Возможно, что в дополнение к классу, который реализует
List
, это также подклассDate
.Техническая причина в том , что Спецификация языка Java «позволяет» Сужение ссылочное преобразование , которое соответствует этому типу актеров. Согласно JLS 5.1.6.1 :
В другом месте JLS также говорит, что исключение может быть выдано во время выполнения ...
Обратите внимание, что определение JLS 5.1.6.1 основано исключительно на объявленных типах задействованных переменных, а не на фактических типах времени выполнения. В общем случае компилятор не знает и не может знать фактические типы времени выполнения.
Итак, почему Java-компилятор не может решить, что приведение не будет работать?
В моем примере
someMethod
вызов может возвращать объекты различных типов. Даже если компилятор смог проанализировать тело метода и определить точный набор типов, которые могут быть возвращены, ничто не помешает кому-то изменить его, чтобы он возвращал разные типы ... после компиляции кода, который его вызывает. Это основная причина, почему JLS 5.1.6.1 говорит то, что говорит.В вашем примере умный компилятор может выяснить, что приведение никогда не может быть успешным. И разрешено выдавать предупреждение во время компиляции, чтобы указать на проблему.
Так почему же умному компилятору не разрешается говорить, что это ошибка?
Потому что JLS говорит, что это действительная программа. Период. Любой компилятор, который назвал это ошибкой , не будет Java-совместимым.
Кроме того, любой компилятор, который отклоняет программы Java, которые JLS и другие компиляторы считают допустимыми, является препятствием для переносимости исходного кода Java.
источник
5.5.1. Тип литья:
List<String>
естьS
иDate
естьT
в вашем случае.источник