在 Java 中转换变量

Casting variables in Java

提问人:user626912 提问时间:3/13/2011 最后编辑:ivanleonczuser626912 更新时间:2/20/2020 访问量:321374

问:

我想知道有没有人能告诉我选角是如何工作的?我明白什么时候应该这样做,但不知道它是如何工作的。关于原始数据类型,我部分理解,但是当涉及到转换对象时,我不明白它是如何工作的。

假设(只是一个例子)如何突然将 Object 类型的对象强制转换为,然后获取所有方法?MyType

Java 转换

评论

0赞 spongebob 6/8/2015
为您推荐: 继承
0赞 Nisal Edu 10/31/2017
javaseeeedu.blogspot.com/2015/12/casting-part-1.html

答:

7赞 sandrstar 3/13/2011 #1

实际上,选角并不总是有效。如果对象不是要将其转换为的类,则在运行时将获得一个。instanceofClassCastException

3赞 asgs 3/13/2011 #2

仅当引用为该类型时,强制转换引用才有效。不能强制转换随机引用。另外,您需要阅读更多关于 铸造对象.instanceof

例如

String string = "String";

Object object = string; // Perfectly fine since String is an Object

String newString = (String)object; // This only works because the `reference` object is pointing to a valid String object.
188赞 Michael Berry 3/13/2011 #3

在 Java 中强制转换不是魔术,而是你告诉编译器一个 A 类型的对象实际上是更具体的 B 类型,从而获得对 B 上所有方法的访问权,否则你就不会有这些方法。在执行强制转换时,您没有执行任何魔术或转换,您实际上是在告诉编译器“相信我,我知道我在做什么,我可以向您保证,这一行的这个对象实际上是一个<在此处插入强制转换类型>。例如:

Object o = "str";
String str = (String)o;

以上很好,不是魔术,一切都很好。存储在 o 中的对象实际上是一个字符串,因此我们可以毫无问题地转换为字符串。

有两种方式可能会出错。首先,如果你在完全不同的继承层次结构中转换两种类型,那么编译器会知道你在傻,并阻止你:

String o = "str";
Integer str = (Integer)o; //Compilation fails here

其次,如果它们位于同一层次结构中,但仍然是无效的强制转换,则将在运行时抛出:ClassCastException

Number o = new Integer(5);
Double n = (Double)o; //ClassCastException thrown here

这实质上意味着您违反了编译器的信任。你已经告诉它,你可以保证对象是特定类型的,但事实并非如此。

为什么需要铸造?好吧,首先,只有在从更通用的类型转到更具体的类型时才需要它。例如,继承自 ,所以如果你想将 存储为 ,那没关系(因为所有整数都是数字。然而,如果你想反过来,你需要一个转换 - 并非所有的数字都是整数(以及我们有的整数、、、等)。即使你的项目或 JDK 中只有一个子类,有人可以很容易地创建另一个子类并分发它,所以即使你认为这是一个单一的、显而易见的选择,你也无法保证!IntegerNumberIntegerNumberDoubleFloatByteLong

关于用于铸造,您仍然在某些库中看到对它的需求。在 Java-5 之前,它被大量用于集合和其他各种类中,因为所有集合都致力于添加对象,然后转换你从集合中得到的结果。然而,随着泛型的出现,强制转换的大部分用途已经消失了 - 它已被泛型所取代,泛型提供了一种更安全的替代方案,而没有 ClassCastExceptions 的可能性(事实上,如果你干净地使用泛型并且它编译时没有警告,你可以保证你永远不会得到 ClassCastException。

评论

0赞 user626912 3/13/2011
谢谢你的解释。如果我理解正确,可能我没有,当你转换一个对象时,你只是在告诉编译器我知道这个内存地址上的对象知道如何响应这些方法等,所以不要否认我?这是对的吗?
1赞 Michael Berry 3/14/2011
@user626912 有点 - 不过不要从内存地址的角度来考虑它。你不只是告诉编译器给定的对象符合一个接口,因此具有给定方法的实现(你可以用相同的方法创建一个完全不同的对象,而强制转换不一定有效。您告诉编译器,一种类型的对象实际上是一种更具体的类型,因此您可以使用该更具体对象上可用的方法。如果你还没有读过多态性,这可能有助于使一些事情更清楚。
0赞 林果皞 4/16/2016
我怀疑你的说法“只有在从更通用的类型到更具体的类型时才需要它”。((Object) gpsLastLoc.getLatitude()).getClass().getSimpleName() 将在运行时返回“double”名称,这是从更具体的类型转换为更通用类型的示例用法。
1赞 Michael Berry 4/16/2016
@林果皞 在这种情况下,你只是使用强制转换来提升基元 - 这与使用更通用的类型不同,并且是一种非常奇怪的做事方式。更正常(更好)的方式是.无论哪种情况,您都不需要动态获取基元的类,因为如果返回双基元,您始终知道它将提升为对象。Double.valueOf(gpsLastLoc.getLatitude()).getClass().getSimpleName()getLatitude()Double
0赞 JonyD 5/19/2017
@berry120 所以,在这里:永远不会调用 NumericSubmodel 构造函数,对吧?并且不会设置其附加字段(子模型中不存在)。for (final Submodel submodel : submodels) { final NumericSubmodel numericSubmodel = (NumericSubmodel) submodel; ...}
5赞 Christophe Roussy 3/13/2011 #4

假设你想将 a 转换为 a(是的,这没有任何意义),你不能直接转换它,因为该类不是子类,也不是该类的父类(编译器会抱怨)。StringFileFileString

但是你可以将你的 转换为 ,因为 a 是 ( 是父级)。然后,您可以将此对象转换为 ,因为 File 是 .StringObjectStringObjectObjectFileObject

因此,从编译时的键入角度来看,您的所有操作都是“合法的”,但这并不意味着它会在运行时工作!

File f = (File)(Object) "Stupid cast";

编译器将允许这样做,即使它没有意义,但它会在运行时崩溃,并出现以下异常:

Exception in thread "main" java.lang.ClassCastException:
    java.lang.String cannot be cast to java.io.File
3赞 yegor256 9/24/2019 #5

正确的方法是:

Integer i = Integer.class.cast(obj);

该方法是编译时强制转换更安全的替代方法。cast()