我最近偶然发现了一段这样的代码:
Object o = .. ;
Foo foo = Foo.class.cast(o);
我实际上甚至不知道 java.lang.Class 有一个强制转换方法,所以我查看了文档,根据我收集的信息,这只是简单地强制转换为Class 对象代表的类。所以上面的代码大致相当于
Object o = ..;
Foo foo = (Foo)o;
所以我想知道为什么我想使用强制转换方法而不是简单地“以旧方式”进行强制转换。有没有人有一个很好的例子,其中使用强制转换方法比进行简单强制转换更有好处?
I recently stumbled upon a piece of code that went like this:
Object o = .. ;
Foo foo = Foo.class.cast(o);
I was actually not even aware that java.lang.Class had a cast method, so I looked into the docs, and from what I gather this does simply do a cast to the class that the Class object represents. So the code above would be roughly equivalent to
Object o = ..;
Foo foo = (Foo)o;
So I wondered, why I would want to use the cast method instead of simply doing a cast "the old way". Has anyone a good example where the usage of the cast method is beneficial over doing the simple cast?
发布评论
评论(8)
我认为它并不像您所展示的那样经常使用。我见过的最常见的用途是使用泛型的人们试图做与此等效的事情:
由于类型擦除,这并没有真正做任何有用的事情。
而这有效,并且类型安全(模
ClassCastExceptions
):编辑:来自 google guava 的几个使用示例:
通用投掷规格
I don't think it's often used exactly as you have shown. Most common use I have seen is where folks using generics are trying to do the equivalent of this:
Which doesn't really do anything useful because of type erasure.
Whereas this works, and is type safe (modulo
ClassCastExceptions
):EDIT: Couple of examples of use from google guava:
generic throw spec
在 Java 中,剥猫皮的方法通常不止一种。如果您有框架代码,此类功能可能会很有用。想象一个方法,它接受一个 Class 对象实例和一个 Object 实例,并返回 Object 实例作为类:
通常,使用更简单的转换,除非它不够。
In Java there is often more than one way to skin a cat. Such functionality may be useful in cases where you have framework code. Imagine a method which accepts a Class object instance and an Object instance and returns the Object case as the class:
In general, use the simpler casting, unless it does not suffice.
在某些情况下,您只知道在运行时将对象强制转换为的类型,此时您必须使用强制转换方法。
In some cases, you only know the type to cast an object to during runtime, and that's when you have to use the cast method.
完全没有理由写
Foo.class.cast(o)
,它相当于(Foo)o
。一般来说,如果
X
是可具体化的类型,并且Class是可具体化的类型。 clazz
,则clazz.cast(o)
与(X)o
相同。如果所有类型都是可具体化的,则方法
Class.cast()
是多余且无用的。不幸的是,由于当前版本的 Java 中的擦除,并非所有类型都是可具体化的。例如,类型变量是不可具体化的。
如果
T
是类型变量,则不选中强制转换(T)o
,因为在运行时,JVM 不知道T
的确切类型, JVM 无法测试o
是否确实是T
类型。可能会错误地允许强制转换,这可能会在以后引发问题。这不是什么大问题;通常,当程序员执行
(T)o
时,他已经推断出强制转换是安全的,并且不会在运行时引起任何问题。应用逻辑检查转换。假设一个
Class clazz
在强制转换时可用,那么我们在运行时就知道T
是什么;我们可以添加额外的运行时检查以确保o
确实是T
。这本质上就是 Class.cast() 的作用。
我们永远不会期望转换在任何情况下都会失败,因此在正确实现的应用程序中,检查
clazz.isInstance(o)
必须始终成功,因此clazz.cast(o)
code> 相当于(T)o
- 再次假设代码是正确的。如果可以证明代码是正确的并且转换是安全的,出于性能原因,人们可能会更喜欢
(T)o
而不是clazz.cast(o)
。在另一个答案中提出的MutableClassToInstanceMap
示例中,我们显然可以看到强制转换是安全的,因此简单的(T)o
就足够了。There is absolutely no reason to write
Foo.class.cast(o)
, it is equivalent to(Foo)o
.In general, if
X
is a reifiable type, andClass<X> clazz
, thenclazz.cast(o)
is same as(X)o
.If all types are reifiable, method
Class.cast()
is therefore redundant and useless.Unfortunately, due to erasure in current version of Java, not all types are reifiable. For example, type variables are not reifiable.
If
T
is a type variable, cast(T)o
is unchecked, because at runtime, the exact type ofT
is unknown to JVM, JVM cannot test ifo
is really typeT
. The cast may be allowed erroneously, which may trigger problems later.It is not a huge problem; usually when the programmer does
(T)o
, he has already reasoned that the cast is safe, and won't cause any problem at runtime. The cast is checked by app logic.Suppose a
Class<T> clazz
is available at the point of cast, then we do know whatT
is at runtime; we can add extra runtime check to make sureo
is indeed aT
.And this is essentially what
Class.cast()
does.We would never expect the cast to fail in any case, therefore in a correctly implemented app, check
clazz.isInstance(o)
must always succeed anway, thereforeclazz.cast(o)
is equivalent to(T)o
- once again, under the assumption that the code is correct.If one can prove that the code is correct and the cast is safe, one could prefer
(T)o
toclazz.cast(o)
for performance reason. In the example ofMutableClassToInstanceMap
raised in another answer, we can see obviously that the cast is safe, therefore simple(T)o
would have sufficed.class.cast 是为泛型类型设计的。
当你构造一个带有泛型参数T的类时,你可以传入一个
班级。然后您可以使用静态和动态进行转换
检查,(T)不会给你。它也不会产生未经检查的
警告,因为它已被检查(此时)。
class.cast is designed for generics type.
When you construct a class with generic parameter T, you can pass in a
Class. You can then do the cast with both static and dynamic
checking, which (T) does not give you. It also doesn't produce unchecked
warnings, because it is checked (at that point).
常见的示例是当您从持久层检索使用类对象和某些条件引用的实体集合时。返回的集合可能包含未经检查的对象,因此如果您只是将其强制转换为指向 G_H,则此时将抛出强制转换异常,而不是在访问值时抛出强制转换异常。
一个示例是,当您从返回未经检查的集合的 DAO 检索集合并在您的服务上对其进行迭代时,这种情况可能会导致 ClassCastException。
解决这个问题的一种方法是,当您拥有所需的类和未检查的集合时,对其进行迭代并将其投射到 DAO 中,将集合转换为检查的集合,然后返回它。
The common sample for that is when you retrieve from persistent layer a collection of entity referenced with a Class Object and some conditions. The returned collection could contain unchecked objects, so if you just cast it as pointed G_H, you will throw the Cast Exception at this point, and not when the values are accessed.
One example for this is when you retrieve a collection from a DAO that returns an unchecked collection and on your service you iterate over it, this situation can lead to a ClassCastException.
One way to solve it, as you have the wanted class and the unchecked collection is iterate over it and cast it inside the DAO transforming the collection in a checked collection and afterwards return it.
因为你可能有这样的东西:
Because you might have something this:
Java 中的“强制转换”,例如
(Number)var
,其中括号内的内容是引用类型,实际上由两部分组成:要使用语法,您需要在编写代码时了解类。假设您在编译时不知道要转换为哪个类;你只有在运行时才知道。
现在你可能会问,那么铸造的意义是什么?转换的目的不就是在编译时将表达式转换为所需的类型吗?因此,如果您在编译时不知道类型,那么在编译时就没有任何好处,对吧?确实如此,但这只是上面的第一项。您忘记了强制转换的运行时组件(上面的第二项):它根据类检查对象。
因此,运行时强制转换(即
Class.cast()
)的目的是检查该对象是否是该类的实例,如果不是,则抛出异常。它大致相当于这个,但更短:有些人提到
Class.cast()
也有一个很好的返回类型,它基于传入的类的类型参数,但这只是一个无论如何,编译时功能都是由编译时强制转换提供的。因此,为了这个目的,使用 Class.cast() 是没有意义的。A "cast" in Java, e.g.
(Number)var
, where the thing inside the parentheses is a reference type, really consists of two parts:ClassCast Exception
(if the thing you're casting to is a type variable, then the class it checks would be the lower bound of the type variable)To use the syntax, you need to know the class at the time you write the code. Suppose you don't know at compile-time what class you want to cast to; you only know it at runtime.
Now you would ask, then what is the point of casting? Isn't the point of casting to turn the expression into the desired type at compile time? So if you don't know the type at compile time, then there is no benefit at compile-time, right? True, but that is just the first item above. You're forgetting the runtime component of a cast (second item above): it checks the object against the class.
Therefore, the purpose of a runtime cast (i.e.
Class.cast()
) is to check that the object is an instance of the class, and if not, throw an exception. It is roughly equivalent to this but shorter:Some people have mentioned that
Class.cast()
also has a nice return type that is based on the type parameter of the class passed in, but that is just a compile-time feature that is provided by a compile-time cast anyway. So for that purpose there is no point in usingClass.cast()
.