Progress-servis55.ru

Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Class cast java

Java > Ask Question

Having being taught during my C++ days about evils of the C-style cast operator I was pleased at first to find that in Java 5 java.lang.Class had acquired a cast method.

I thought that finally we have an OO way of dealing with casting.

Turns out Class.cast is not the same as static_cast in C++. It is more like reinterpret_cast . It will not generate a compilation error where it is expected and instead will defer to runtime. Here is a simple test case to demonstrate different behaviors.

So, these are my questions.

  1. Should Class.cast() be banished to Generics land? There it has quite a few legitimate uses.
  2. Should compilers generate compile errors when Class.cast() is used and illegal conditions can be determined at compile time?
  3. Should Java provide a cast operator as a language construct similar to C++?

8 Answers 8

I’ve only ever used Class.cast(Object) to avoid warnings in «generics land». I often see methods doing things like this:

It’s often best to replace it by:

That’s the only use case for Class.cast(Object) I’ve ever come across.

Regarding compiler warnings: I suspect that Class.cast(Object) isn’t special to the compiler. It could be optimized when used statically (i.e. Foo.class.cast(o) rather than cls.cast(o) ) but I’ve never seen anybody using it — which makes the effort of building this optimization into the compiler somewhat worthless.

First, you are strongly discouraged to do almost any cast, so you should limit it as much as possible! You lose the benefits of Java’s compile-time strongly-typed features.

In any case, Class.cast() should be used mainly when you retrieve the Class token via reflection. It’s more idiomatic to write

EDIT: Errors at compile time

Over all, Java performs cast checks at run time only. However, the compiler can issue an error if it can prove that such casts can never succeed (e.g. cast a class to another class that’s not a supertype and cast a final class type to class/interface that’s not in its type hierarchy). Here since Foo and Bar are classes that aren’t in each other hierarchy, the cast can never succeed.

It’s always problematic and often misleading to try and translate constructs and concepts between languages. Casting is no exception. Particularly because Java is a dynamic language and C++ is somewhat different.

All casting in Java, no matter how you do it, is done at runtime. Type information is held at runtime. C++ is a bit more of a mix. You can cast a struct in C++ to another and it’s merely a reinterpretation of the bytes that represent those structs. Java doesn’t work that way.

Also generics in Java and C++ are vastly different. Don’t concern yourself overly with how you do C++ things in Java. You need to learn how to do things the Java way.

Class.cast() is rarely ever used in Java code. If it is used then usually with types that are only known at runtime (i.e. via their respective Class objects and by some type parameter). It is only really useful in code that uses generics (that’s also the reason it wasn’t introduced earlier).

It is not similar to reinterpret_cast , because it will not allow you to break the type system at runtime any more than a normal cast does (i.e. you can break generic type parameters, but can’t break «real» types).

The evils of the C-style cast operator generally don’t apply to Java. The Java code that looks like a C-style cast is most similar to a dynamic_cast<>() with a reference type in Java (remember: Java has runtime type information).

Generally comparing the C++ casting operators with Java casting is pretty hard since in Java you can only ever cast reference and no conversion ever happens to objects (only primitive values can be converted using this syntax).

Object Type Casting in Java

Last modified: March 14, 2020

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

In the 9 years of running Baeldung, I’ve never, ever done a «sale».
But. we’ve also not been through anything like this pandemic either.
And, if making my courses more affordable for a while is going to help a company stay in business, or a developer land a new job, make rent or be able to provide for their family — then it’s well worth doing.
Effective immediately, all Baeldung courses are 33% off their normal prices!
You’ll find all three courses in the menu, above, or here.

1. Overview

The Java type system is made up of two kinds of types: primitives and references.

We covered primitive conversions in this article, and we’ll focus on references casting here, to get a good understanding of how Java handles types.

Further reading:

The Basics of Java Generics

Java instanceof Operator

2. Primitive vs. Reference

Although primitive conversions and reference variable casting may look similar, they’re quite different concepts.

In both cases, we’re “turning” one type into another. But, in a simplified way, a primitive variable contains its value, and conversion of a primitive variable means irreversible changes in its value:

After the conversion in the above example, myInt variable is 1, and we can’t restore the previous value 1.1 from it.

Reference variables are different; the reference variable only refers to an object but doesn’t contain the object itself.

And casting a reference variable doesn’t touch the object it refers to, but only labels this object in another way, expanding or narrowing opportunities to work with it. Upcasting narrows the list of methods and properties available to this object, and downcasting can extend it.

Читать еще:  Проблема видеодрайвер перестал отвечать и был восстановлен

A reference is like a remote control to an object. The remote control has more or fewer buttons depending on its type, and the object itself is stored in a heap. When we do casting, we change the type of the remote control but don’t change the object itself.

3. Upcasting

Casting from a subclass to a superclass is called upcasting. Typically, the upcasting is implicitly performed by the compiler.

Upcasting is closely related to inheritance – another core concept in Java. It’s common to use reference variables to refer to a more specific type. And every time we do this, implicit upcasting takes place.

To demonstrate upcasting let’s define an Animal class:

Now let’s extend Animal:

Now we can create an object of Cat class and assign it to the reference variable of type Cat:

And we can also assign it to the reference variable of type Animal:

In the above assignment, implicit upcasting takes place. We could do it explicitly:

But there is no need to do explicit cast up the inheritance tree. The compiler knows that cat is an Animal and doesn’t display any errors.

Note, that reference can refer to any subtype of the declared type.

Using upcasting, we’ve restricted the number of methods available to Cat instance but haven’t changed the instance itself. Now we can’t do anything that is specific to Cat – we can’t invoke meow() on the animal variable.

Although Cat object remains Cat object, calling meow() would cause the compiler error:

To invoke meow() we need to downcast animal, and we’ll do this later.

But now we’ll describe what gives us the upcasting. Thanks to upcasting, we can take advantage of polymorphism.

3.1. Polymorphism

Let’s define another subclass of Animal, a Dog class:

Now we can define the feed() method which treats all cats and dogs like animals:

We don’t want AnimalFeeder to care about which animal is on the list – a Cat or a Dog. In the feed() method they are all animals.

Implicit upcasting occurs when we add objects of a specific type to the animals list:

We add cats and dogs and they are upcast to Animal type implicitly. Each Cat is an Animal and each Dog is an Animal. They’re polymorphic.

By the way, all Java objects are polymorphic because each object is an Object at least. We can assign an instance of Animal to the reference variable of Object type and the compiler won’t complain:

That’s why all Java objects we create already have Object specific methods, for example, toString().

Upcasting to an interface is also common.

We can create Mew interface and make Cat implement it:

Now any Cat object can also be upcast to Mew:

Cat is a Mew, upcasting is legal and done implicitly.

Thus, Cat is a Mew, Animal, Object, and Cat. It can be assigned to reference variables of all four types in our example.

3.2. Overr >

In the example above, the eat() method is overridden. This means that although eat() is called on the variable of the Animal type, the work is done by methods invoked on real objects – cats and dogs:

If we add some logging to our classes, we’ll see that Cat’s and Dog’s methods are called:

To sum up:

  • A reference variable can refer to an object if the object is of the same type as a variable or if it is a subtype
  • Upcasting happens implicitly
  • All Java objects are polymorphic and can be treated as objects of supertype due to upcasting

4. Downcasting

What if we want to use the variable of type Animal to invoke a method available only to Cat class? Here comes the downcasting. It’s the casting from a superclass to a subclass.

Let’s take an example:

We know that animal variable refers to the instance of Cat. And we want to invoke Cat’s meow() method on the animal. But the compiler complains that meow() method doesn’t exist for the type Animal.

To call meow() we should downcast animal to Cat:

The inner parentheses and the type they contain are sometimes called the cast operator. Note that external parentheses are also needed to compile the code.

Let’s rewrite the previous AnimalFeeder example with meow() method:

Now we gain access to all methods available to Cat class. Look at the log to make sure that meow() is actually called:

Note that in the above example we’re trying to downcast only those objects which are really instances of Cat. To do this, we use the operator instanceof.

4.1. instanceof Operator

We often use instanceof operator before downcasting to check if the object belongs to the specific type:

4.2. >

If we hadn’t checked the type with the instanceof operator, the compiler wouldn’t have complained. But at runtime, there would be an exception.

To demonstrate this let’s remove the instanceof operator from the above code:

This code compiles without issues. But if we try to run it we’ll see an exception:

java.lang.ClassCastException: com.baeldung.casting.Dog cannot be cast to com.baeldung.casting.Cat

This means that we are trying to convert an object which is an instance of Dog into a Cat instance.

ClassCastException’s always thrown at runtime if the type we downcast to doesn’t match the type of the real object.

Note, that if we try to downcast to an unrelated type, the compiler won’t allow this:

The compiler says “Cannot cast from Animal to String”.

For the code to compile, both types should be in the same inheritance tree.

  • Downcasting is necessary to gain access to members specific to sub >

There’s another way to cast objects using the methods of Class:

In the above example, cast() and isInstance() methods are used instead of cast and instanceof operators correspondingly.

It’s common to use cast() and isInstance() methods with generic types.

Let’s create AnimalFeederGeneric class with feed() method which “feeds” only one type of animals – cats or dogs, depending on the value of the type parameter:

The feed() method checks each animal and returns only those which are instances of T.

Note, that the Class instance should also be passed to the generic class as we can’t get it from the type parameter T. In our example, we pass it in the constructor.

Let’s make T equal to Cat and make sure that the method returns only cats:

6. Conclusion

In this foundational tutorial, we’ve explored what is upcasting, downcasting, how to use them and how these concepts can help you take advantage of polymorphism.

As always, the code for this article is available over on GitHub.

Class cast java

Будучи обученным в течение моих дней C++ о зле оператора приведения C-стиля, я был рад сначала обнаружить, что в Java 5 java.lang.Class приобрел метод cast .

Я думал, что наконец-то у нас есть OO способ борьбы с кастингом.

Оказывается, Class.cast -это не то же самое, что static_cast в C++. Это больше похоже на reinterpret_cast . Он не будет генерировать ошибку компиляции там, где это ожидается, и вместо этого будет отложен до времени выполнения. Вот простой тестовый случай, чтобы продемонстрировать различные модели поведения.

Итак, вот мои вопросы.

  1. Должен ли Class.cast() быть изгнан на Землю дженериков? Там он имеет довольно много законных применений.
  2. Должны ли компиляторы генерировать ошибки компиляции, когда используется Class.cast() и во время компиляции могут быть определены незаконные условия?
  3. Должен ли Java предоставлять оператор приведения в качестве языковой конструкции, подобной C++?

8 Ответов

Я всегда использовал только Class.cast(Object) , чтобы избежать предупреждений в «generics land». Я часто вижу методы, делающие такие вещи:

Часто лучше всего заменить его на:

Это единственный случай использования для Class.cast(Object) , с которым я когда-либо сталкивался.

Что касается предупреждений компилятора: я подозреваю, что Class.cast(Object) не является особенным для компилятора. Он может быть оптимизирован при статическом использовании (т. е. Foo.class.cast(o) , а не cls.cast(o) ), но я никогда не видел, чтобы кто — то его использовал, что делает попытку встроить эту оптимизацию в компилятор несколько бесполезной.

Во-первых, вам категорически не рекомендуется делать практически любой бросок, поэтому вы должны максимально ограничить его! Вы теряете преимущества Java-х строго типизированных функций во время компиляции.

В любом случае, Class.cast() следует использовать в основном при извлечении маркера Class через отражение. Это более идиоматично писать

вместо того чтобы

EDIT: ошибки во время компиляции

Кроме того, Java выполняет проверку приведения только во время выполнения. Однако компилятор может выдать ошибку, если он может доказать, что такие приведения никогда не будут успешными (например приведение класса к другому классу, который не является супертайпом, и приведение конечного типа класса к классу / интерфейсу, который не входит в его иерархию типов). Здесь, поскольку Foo и Bar -это классы, которые не находятся в иерархии друг друга, приведение никогда не может быть успешным.

Всегда проблематично и часто вводит в заблуждение попытка перевода конструкций и концепций между языками. Кастинг-не исключение. Особенно потому, что Java-это динамический язык, а C++ несколько отличается.

Все приведение в Java, независимо от того, как вы это делаете, выполняется во время выполнения. Сведения о типе хранятся во время выполнения. C++ — это немного больше смеси. Вы можете привести структуру в C++ к другой, и это просто переинтерпретация байтов, которые представляют эти структуры. Java так не работает.

Кроме того, дженерики в Java и C++ сильно отличаются. Не беспокойтесь слишком о том, как вы делаете C++ вещи в Java. Вам нужно научиться делать вещи по принципу Java.

Class.cast() редко используется в коде Java. Если он используется, то обычно с типами, которые известны только во время выполнения (т. е. через их соответствующие объекты Class и по некоторому параметру типа). Он действительно полезен только в коде, использующем дженерики (именно поэтому он не был представлен ранее).

Он не похож на reinterpret_cast , потому что он не позволит вам сломать систему типов во время выполнения больше, чем это делает обычное приведение (т. е. вы можете «break» параметры универсального типа, но не можете «break» «real» типы).

Зло оператора приведения в стиле C обычно не распространяется на Java. Код Java, который выглядит как приведение в стиле C, больше всего похож на dynamic_cast<>() со ссылочным типом в Java (помните: Java имеет информацию о типе среды выполнения).

Как правило, сравнение операторов приведения C++ с приведением Java довольно сложно, так как в Java вы можете только привести ссылку, и никакого преобразования никогда не происходит с объектами (только примитивные значения могут быть преобразованы с помощью этого синтаксиса).

C++ и Java-это разные языки.

Оператор приведения в стиле Java C гораздо более ограничен, чем версия C/C++. Фактически приведение Java подобно приведению C++ dynamic_cast, если объект, который вы имеете, не может быть приведен к новому классу, вы получите исключение времени выполнения (или если в коде достаточно информации о времени компиляции). Таким образом, идея C++ не использовать приведения типа C не является хорошей идеей в Java

Лично я использовал это раньше, чтобы построить конвертер JSON в POJO. В случае, если JSONObject, обработанный с помощью функции, содержит массив или вложенный JSONObjects (подразумевая, что данные здесь не имеют примитивного типа или String ), я пытаюсь вызвать метод setter, используя class.cast() таким образом:

Не уверен, что это очень полезно, но, как уже было сказано выше, рефлексия-один из очень немногих случаев законного использования class.cast() , которые я могу придумать, по крайней мере, у вас есть еще один пример.

В дополнение к удалению уродливых предупреждений приведения ,как уже упоминалось, Class.cast является приведением во время выполнения, в основном используемым с общим приведением, из-за того , что общая информация будет удалена во время выполнения, и некоторые из них будут рассматриваться как объект, это приводит к тому, чтобы не выбрасывать ранний ClassCastException.

например serviceLoder используйте этот трюк при создании объектов, проверьте S p = service.cast (c.newInstance()); это вызовет исключение приведения класса когда S P =(S) c.newInstance(); не будет и может показывать предупреждение «тип безопасности: непроверенное приведение от объекта к S».(то же самое, что объект P =(объект) c.newInstance();)

— просто он проверяет, что приведенный объект является экземпляром класса Cast, а затем использует оператор cast для приведения и скрытия предупреждения, подавляя его.

java реализация для динамического литья:

Как правило, оператор cast предпочтительнее метода Class#cast, поскольку он более лаконичен и может быть проанализирован компилятором, чтобы выявить вопиющие проблемы с кодом.

Class#cast берет на себя ответственность за проверку типов во время выполнения, а не во время компиляции.

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

Так как lambda пришел к java, мне лично нравится использовать Class#cast с коллекциями / потоком API, если я работаю с абстрактными типами, например.

Похожие вопросы:

Я пытаюсь написать оператор case в Terdata, если active = ‘Yes’, то 1 elseif active = No, а затем 0 else NULL. Я пытался case when cast(M_ACTIVE as integer)= ‘YES’ then ‘1’ when cast(M_ACTIVE as.

Я пытаюсь отладить проблему, связанную с ClassCastException в Java. В интересах решения этой проблемы мне нужно знать, что происходит, когда я перехожу от объекта к определенному типу. Может ли.

Dynamic casting in Java

I’m a big fan of Baeldung’s blog. One of his latest post is about casting in Java. Unfortunately, I feel it misses one important point: dynamic casting. Since that’s is (very) relatively new, this post will try to fill that gap.

Do not use casting

The first thing is that it should be relatively easy to avoid casting.

Using polymorphism

Polymorphism is a great way not to cast. Consider the following code:

If all object types in the collection inherit from a single type, it’s possible to use polymorphism. Just add one method in this single type and override it in the subtypes.

Using generics

Polymorphism cannot be always applied. For example, this is the case when:

  • Items are not instances of related type
  • The parent type is not within our control sphere
  • etc.

In those cases, generics is another way to avoid casting.

Before Java 5, the following code would be the norm:

1
Casting required. Though the runtime type is Date , the compiler has no way to know about it.

With generics, the above code can be rewritten:

1
No casting: the compiler has enough information thanks to generics.

When casting is mandatory

Despite to what some fanatics think, it happens that sometimes casting cannot be ignored.

One such use-case is the Servlet API. Map storing objects in servlet context/request/session do not use generics. And even if they did, they would be using Object .

Dynamic casting

The only form of casting originally available was static casting. Which means the casting type needs to be known at compile time. For example, let’s imagine a method that accepts a Stream , filters all element of a certain type and returns those elements in the right type. This is an example of the usage:

There’s no way to implement the filter method with static casting. There are actually two issues:

  1. The instanceof operator requires a type, not a Class instance e.g. item instanceof Date
  2. The cast syntax as well e.g. (Date) item

The instanceof operator can be replaced with a call to Class.isInstance(Object) (since JDK 1.1). This is quite well-known, if not widely used.

The API to replace the cast syntax, however, is much more «recent». There’s a Class.cast(Object) method since JDK 1.5 It is a simple wrapper around the legacy syntax.

Using both methods, it’s finally possible to implement the filter method above.

Using the casting API allows dynamic casting. Without it, it’s not possible to implement the above method.

Conclusion

Despite what many people outside the ecosystem think, Java evolves, even if not very fast. However, developers needs to be acquainted with the new capabilities offered by each version.

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Currently working for Hazelcast. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Feature lifecycle in Java

Today, I’d like to tackle a subject that seems to be misunderstood by a sizable fraction of developers, the lifecycle of features. Suppose you design a language, a framework, a library, anything that is provided to third-partys. Because you did a good job, this software is now widely used.

Nicolas Fränkel

Programming by contract on the JVM

This week, I’d like to tackle an interesting approach that is quite useful. Design by contract prescribes that developers should define preconditions, postconditions and invariants. These specifications are referred to as ‘contracts’.

Nicolas Fränkel

Ссылка на основную публикацию
Adblock
detector