Когда я учился на C ++ о пороках оператора приведения в стиле C, я сначала был рад обнаружить, что в Java 5 java.lang.Class
есть cast
метод.
Я подумал, что наконец-то у нас появился ОО-подход к кастингу.
Оказывается, Class.cast
это не то же самое, что static_cast
в C ++. Это больше похоже reinterpret_cast
. Он не будет генерировать ошибку компиляции там, где она ожидается, а вместо этого будет отложена до времени выполнения. Вот простой тестовый пример, чтобы продемонстрировать различное поведение.
package test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class TestCast
{
static final class Foo
{
}
static class Bar
{
}
static final class BarSubclass
extends Bar
{
}
@Test
public void test ( )
{
final Foo foo = new Foo( );
final Bar bar = new Bar( );
final BarSubclass bar_subclass = new BarSubclass( );
{
final Bar bar_ref = bar;
}
{
// Compilation error
final Bar bar_ref = foo;
}
{
// Compilation error
final Bar bar_ref = (Bar) foo;
}
try
{
// !!! Compiles fine, runtime exception
Bar.class.cast( foo );
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
{
final Bar bar_ref = bar_subclass;
}
try
{
// Compiles fine, runtime exception, equivalent of C++ dynamic_cast
final BarSubclass bar_subclass_ref = (BarSubclass) bar;
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
}
}
Итак, это мои вопросы.
- Должно
Class.cast()
быть сослан в дженерик землю? Там у него довольно много законных применений. - Должны ли компиляторы генерировать ошибки компиляции при
Class.cast()
использовании, а недопустимые условия могут быть определены во время компиляции? - Должна ли Java предоставлять оператор приведения в качестве языковой конструкции, подобной C ++?
java
generics
casting
compiler-warnings
Александр Погребняк
источник
источник
Class.cast()
если во время компиляции можно определить недопустимые условия. В этом случае все, кроме вас, используют стандартный оператор приведения. (3) В Java есть оператор приведения в качестве языковой конструкции. Он не похож на C ++. Это потому, что многие языковые конструкции Java не похожи на C ++. Несмотря на внешнее сходство, Java и C ++ совершенно разные.Ответы:
Я только когда-либо использовал,
Class.cast(Object)
чтобы избежать предупреждений в "стране дженериков". Я часто вижу такие методы:Часто лучше заменить его:
Это единственный случай использования, с которым
Class.cast(Object)
я когда-либо сталкивался.Что касается предупреждений компилятора: я подозреваю, что
Class.cast(Object)
это не особенность компилятора. Его можно было бы оптимизировать при статическом использовании (то есть,Foo.class.cast(o)
а неcls.cast(o)
), но я никогда не видел, чтобы кто-нибудь его использовал, что делает попытки встроить эту оптимизацию в компилятор несколько бесполезной.источник
Во-первых, вам категорически не рекомендуется использовать практически любые заклинания, поэтому вам следует максимально ограничить их! Вы теряете преимущества строго типизированных функций Java во время компиляции.
В любом случае его
Class.cast()
следует использовать в основном при полученииClass
токена через отражение. Писать более идиоматичноскорее, чем
EDIT: ошибки во время компиляции
В целом Java выполняет проверку приведения только во время выполнения. Однако компилятор может выдать ошибку, если сможет доказать, что такое приведение не может быть успешным (например, приведение класса к другому классу, не являющемуся супертипом, и приведение окончательного типа класса к классу / интерфейсу, не входящему в его иерархию типов). Здесь, поскольку
Foo
иBar
являются классами, не входящими в иерархию друг друга, приведение не может быть успешным.источник
Class.cast
кажется, что оно отвечает всем требованиям, оно создает больше проблем, чем решает.Всегда проблематично и часто вводить в заблуждение пытаться переводить конструкции и концепции между языками. Кастинг - не исключение. В частности, потому что Java - это динамический язык, а C ++ несколько отличается.
Все приведение типов в Java, независимо от того, как вы это делаете, выполняется во время выполнения. Информация о типе хранится во время выполнения. C ++ - это немного больше смесь. Вы можете преобразовать структуру в C ++ к другой, и это просто переинтерпретация байтов, которые представляют эти структуры. Java так не работает.
Также дженерики в Java и C ++ сильно отличаются. Не беспокойтесь слишком о том, как вы делаете вещи C ++ в Java. Вам нужно научиться делать что-то на языке Java.
источник
(Bar) foo
, во время компиляции возникает ошибка, ноBar.class.cast(foo)
этого не происходит. На мой взгляд, если он используется таким образом, он должен.Bar.class.cast(foo)
явно сообщает компилятору, что вы хотите выполнить приведение во время выполнения. Если вы хотите проверить правильность преобразования во время компиляции, единственный выбор - выполнить приведение(Bar) foo
стиля.Class.cast()
редко когда-либо используется в коде Java. Если он используется, то обычно с типами, которые известны только во время выполнения (т. Е. Через их соответствующиеClass
объекты и какой-либо параметр типа). Это действительно полезно только в коде, который использует дженерики (это также причина, по которой он не был представлен ранее).Это не похоже на
reinterpret_cast
, потому что это не позволит вам нарушить систему типов во время выполнения, как и обычное приведение (т.е. вы можете нарушить параметры универсального типа, но не можете сломать «настоящие» типы).Пороки оператора приведения в стиле C обычно не относятся к Java. Код Java, который выглядит как приведение в стиле C, больше всего похож на код
dynamic_cast<>()
со ссылочным типом в Java (помните: Java имеет информацию о типе времени выполнения).Обычно сравнивать операторы приведения C ++ с приведением Java довольно сложно, поскольку в Java вы можете приводить только ссылку, и никакое преобразование никогда не происходит с объектами (с использованием этого синтаксиса можно преобразовать только примитивные значения).
источник
dynamic_cast<>()
со ссылочным типом.Обычно оператор приведения предпочтительнее метода приведения Class #, поскольку он более краток и может быть проанализирован компилятором, чтобы выявить явные проблемы с кодом.
Class # cast берет на себя ответственность за проверку типов во время выполнения, а не во время компиляции.
Несомненно, существуют варианты использования приведения Class #, особенно когда дело доходит до отражающих операций.
Поскольку лямбда пришла в java, мне лично нравится использовать приведение Class # с API коллекций / потоков, например, если я работаю с абстрактными типами.
источник
C ++ и Java - разные языки.
Оператор приведения типа Java в C намного более ограничен, чем версия C / C ++. Фактически приведение Java похоже на C ++ dynamic_cast, если имеющийся у вас объект не может быть приведен к новому классу, вы получите исключение времени выполнения (или, если в коде достаточно информации, время компиляции). Таким образом, идея C ++ об отказе от приведений типов C не является хорошей идеей в Java.
источник
В дополнение к удалению уродливых предупреждений о приведении, как уже упоминалось, Class.cast - это приведение во время выполнения, в основном используемое с универсальным приведением, из-за того, что общая информация будет удалена во время выполнения, и некоторым образом каждый общий будет считаться объектом, это приводит к тому, что выбросить раннее исключение ClassCastException.
например serviceLoder использует этот трюк при создании объектов, проверьте S p = service.cast (c.newInstance ()); это вызовет исключение приведения класса, когда SP = (S) c.newInstance (); не будет и может отображать предупреждение «Типовая безопасность: отключенное приведение от объекта к S» . (то же, что и Object P = (Object) c.newInstance ();)
-просто он проверяет, является ли приведенный объект экземпляром класса приведения, затем он будет использовать оператор приведения для приведения и скрытия предупреждения, подавляя его.
Реализация java для динамического приведения:
источник
Лично я использовал это раньше для создания конвертера JSON в POJO. В случае, если JSONObject, обработанный с помощью функции, содержит массив или вложенные JSONObject (подразумевая, что данные здесь не примитивного типа или
String
), я пытаюсь вызвать метод установки, используяclass.cast()
следующим образом:Не уверен, что это чрезвычайно полезно, но, как было сказано здесь ранее, отражение - один из очень немногих законных вариантов использования, которые
class.cast()
я могу придумать, по крайней мере, у вас есть еще один пример.источник