Java Class.cast() 与 cast 运算符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1555326/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Class.cast() vs. cast operator
提问by Alexander Pogrebnyak
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.
在我的 C++ 时代,我学习了 C 风格强制转换运算符的弊端,起初我很高兴地发现在 Java 5 中java.lang.Class
已经获得了一种cast
方法。
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.
事实证明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 );
}
}
}
So, these are my questions.
所以,这些是我的问题。
- Should
Class.cast()
be banished to Generics land? There it has quite a few legitimate uses. - Should compilers generate compile errors when
Class.cast()
is used and illegal conditions can be determined at compile time? - Should Java provide a cast operator as a language construct similar to C++?
- 应该
Class.cast()
被放逐到泛型领域吗?在那里它有很多合法的用途。 - 编译器是否应该在
Class.cast()
使用时产生编译错误并且在编译时可以确定非法条件? - Java 是否应该提供强制转换运算符作为类似于 C++ 的语言结构?
采纳答案by sfussenegger
I've only ever used Class.cast(Object)
to avoid warnings in "generics land". I often see methods doing things like this:
我只习惯于Class.cast(Object)
避免在“泛型领域”中出现警告。我经常看到方法做这样的事情:
@SuppressWarnings("unchecked")
<T> T doSomething() {
Object o;
// snip
return (T) o;
}
It's often best to replace it by:
通常最好将其替换为:
<T> T doSomething(Class<T> cls) {
Object o;
// snip
return cls.cast(o);
}
That's the only use case for Class.cast(Object)
I've ever come across.
这是Class.cast(Object)
我遇到的唯一用例。
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.
关于编译器警告:我怀疑这Class.cast(Object)
对编译器来说并不特殊。它可以在静态使用时进行优化(即Foo.class.cast(o)
而不是cls.cast(o)
),但我从未见过有人使用它 - 这使得将这种优化构建到编译器中的努力变得毫无价值。
回答by cletus
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.
尝试在语言之间翻译结构和概念总是有问题的,而且经常会产生误导。铸造也不例外。特别是因为 Java 是一种动态语言,而 C++ 则有些不同。
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.
Java 中的所有转换,无论您如何操作,都是在运行时完成的。类型信息在运行时保存。C++ 更像是一种混合。您可以将 C++ 中的结构转换为另一个结构,这只是对表示这些结构的字节的重新解释。Java 不是这样工作的。
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.
Java 和 C++ 中的泛型也大不相同。不要过分关心在 Java 中如何做 C++ 的事情。您需要学习如何以 Java 的方式做事。
回答by notnoop
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.
首先,强烈不鼓励您进行几乎任何演员表,因此您应该尽可能地限制它!您失去了 Java 编译时强类型特性的好处。
In any case, Class.cast()
should be used mainly when you retrieve the Class
token via reflection. It's more idiomatic to write
在任何情况下,Class.cast()
主要在Class
通过反射检索令牌时使用。写起来更地道
MyObject myObject = (MyObject) object
rather than
而不是
MyObject myObject = MyObject.class.cast(object)
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.
总的来说,Java 仅在运行时执行强制转换检查。但是,如果编译器可以证明此类转换永远不会成功,则编译器可能会发出错误(例如,将一个类转换为另一个不是超类型的类,并将最终类类型转换为不在其类型层次结构中的类/接口)。由于Foo
和Bar
是不在彼此层次结构中的类,因此演员表永远不会成功。
回答by Joachim Sauer
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).
Class.cast()
在 Java 代码中很少使用。如果使用它,则通常与仅在运行时已知的类型一起使用(即通过它们各自的Class
对象和某些类型参数)。它只在使用泛型的代码中真正有用(这也是之前没有引入它的原因)。
It is notsimilar to reinterpret_cast
, because it will notallow you to break the type system at runtime any more than a normal cast does (i.e. you can breakgeneric type parameters, but can't break"real" types).
这是不是类似reinterpret_cast
,因为它会不会让你在运行任何超过普通投不打破类型系统(即你可以打破泛型类型参数,但不能打破“真正”的类型)。
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).
C 风格的强制转换运算符的缺点通常不适用于 Java。看起来像 C 样式转换的 Java 代码dynamic_cast<>()
与 Java 中的具有引用类型的最相似(请记住:Java 具有运行时类型信息)。
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).
通常,将 C++ 转换运算符与 Java 转换进行比较是非常困难的,因为在 Java 中您只能转换引用并且不会对对象进行转换(只能使用此语法转换原始值)。
回答by user151019
C++ and Java are different languages.
C++ 和 Java 是不同的语言。
The Java C-style cast operator is much more restricted than the C/C++ version. Effectively the Java cast is like the C++ dynamic_cast if the object you have cannot be cast to the new class you will get a run time (or if there is enough information in the code a compile time) exception. Thus the C++ idea of not using C type casts is not a good idea in Java
Java C 风格的强制转换运算符比 C/C++ 版本受到更多限制。实际上,Java 转换就像 C++ dynamic_cast 如果您拥有的对象无法转换为新类,您将获得运行时(或者如果代码中有足够的信息编译时)异常。因此,不使用 C 类型转换的 C++ 想法在 Java 中不是一个好主意
回答by Amjad Abdul-Ghani
In addition to remove ugly cast warnings as most mentioned ,Class.cast is run-time cast mostly used with generic casting ,due to generic info will be erased at run time and some how each generic will be considered Object , this leads to not to throw an early ClassCastException.
除了删除大多数提到的丑陋的强制转换警告之外,Class.cast 是运行时强制转换,主要与泛型强制转换一起使用,由于泛型信息将在运行时被删除,以及每个泛型将如何被视为 Object,这导致不抛出一个早期的 ClassCastException。
for example serviceLoder use this trick when creating the objects,check S p = service.cast(c.newInstance()); this will throw a class cast exception when S P =(S) c.newInstance(); won't and may show a warning 'Type safety: Unchecked cast from Object to S'.(same as Object P =(Object) c.newInstance();)
例如 serviceLoder 在创建对象时使用这个技巧,检查 S p = service.cast(c.newInstance()); 这将在 SP =(S) c.newInstance(); 时抛出类转换异常;不会并且可能会显示警告“类型安全:未检查从 Object 到 S 的强制转换”。(与 Object P =(Object) c.newInstance(); 相同)
-simply it checks that the casted object is instance of casting class then it will use the cast operator to cast and hide the warning by suppressing it.
- 简单地检查被转换的对象是否是转换类的实例,然后它将使用转换运算符通过抑制它来转换和隐藏警告。
java implementation for dynamic cast:
动态转换的java实现:
@SuppressWarnings("unchecked")
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
回答by Wep0n
Personally, I've used this before to build a JSON to POJO converter. In the case that the JSONObject processed with the function contains an array or nested JSONObjects (implying that the data here isn't of a primitive type or String
), I attempt to invoke the setter method using class.cast()
in this fashion:
就个人而言,我以前使用过它来构建 JSON 到 POJO 转换器。如果使用函数处理的 JSONObject 包含数组或嵌套的 JSONObjects(暗示这里的数据不是原始类型或String
),我尝试以class.cast()
这种方式调用 setter 方法:
public static Object convertResponse(Class<?> clazz, JSONObject readResultObject) {
...
for(Method m : clazz.getMethods()) {
if(!m.isAnnotationPresent(convertResultIgnore.class) &&
m.getName().toLowerCase().startsWith("set")) {
...
m.invoke(returnObject, m.getParameters()[0].getClass().cast(convertResponse(m.getParameters()[0].getType(), readResultObject.getJSONObject(key))));
}
...
}
Not sure if this is extremely helpful, but as said here before, reflection is one of the very few legitimate use case of class.cast()
I can think of, at least you have another example now.
不确定这是否非常有帮助,但正如之前所说,反射是class.cast()
我能想到的极少数合法用例之一,至少你现在有另一个例子。
回答by Caleb
Generally the cast operator is preferred to the Class#cast method as it's more concise and can be analyzed by the compiler to spit out blatant issues with the code.
通常,强制转换运算符比 Class#cast 方法更受欢迎,因为它更简洁,并且可以被编译器分析以吐出代码中的明显问题。
Class#cast takes responsibility for type checking at run-time rather than during compilation.
Class#cast 负责在运行时而不是在编译期间进行类型检查。
There are certainly use-cases for Class#cast, particularly when it comes to reflective operations.
Class#cast 肯定有用例,特别是在涉及反射操作时。
Since lambda's came to java I personally like using Class#cast with the collections/stream API if I'm working with abstract types, for example.
例如,由于 lambda 来到 Java,我个人喜欢将 Class#cast 与集合/流 API 一起使用,例如,如果我正在使用抽象类型。
Dog findMyDog(String name, Breed breed) {
return lostAnimals.stream()
.filter(Dog.class::isInstance)
.map(Dog.class::cast)
.filter(dog -> dog.getName().equalsIgnoreCase(name))
.filter(dog -> dog.getBreed() == breed)
.findFirst()
.orElse(null);
}