我知道以下三种可用于投射对象的方法。
Object o = "str";
String str1 = (String) o; // Method 1
String str2 = o.toString(); // Method 2
String str3 = String.class.cast(o); // Method 3
答案 0 :(得分:11)
您展示的第二种方法不是强制转换;它只是在一个对象上调用toString()
方法,这与任何其他方法调用没有什么不同:
String str2 = o.toString();
第一种和第三种方法的效果基本相同。我更喜欢使用第一种方法。
在内部施放时物体发生了什么?
对象没有任何反应。转换不以某种方式自动将对象从一种类型转换为另一种类型。转换的唯一作用是告诉编译器接受赋值语句而不检查此语句的类型。你对编译器说'#34;我比你更了解这是什么类型的对象,所以让我做这个任务并且不要抱怨类型"。
在您的示例中,变量o
的类型为Object
。当您将o
分配给String
类型的变量时,编译器不会允许它,因为它会检查类型,并且无法确定o
in事实是指String
个对象。所以你使用强制转换告诉编译器"我知道这是一个String
对象,所以让我做这个任务"。
仍会检查类型,但是在运行时,而不是在编译时。如果在运行时,对象的类型不是String
,那么您将获得ClassCastException
。
答案 1 :(得分:4)
第一个引用o
引用,其声明类型为Object,其实际具体类型为String,为String。这是规范的铸造方式。只有当o
引用的对象实际上是String类型时,这才有效。如果不是,那么您将遇到ClassCastException。
第二个根本就没有。它调用toString()
引用的对象上的o
。这将永远有效,但它与演员阵容真的不同。
第三个使用反射进行演员表演。这将与第一个具有相同的效果,并将在相同的情况下工作。但这通常只在代码实际上不知道要转换为类的类型时使用:
Class<?> someClassToCastTo = ...; // could be String.class or anything else, you don't know)
String str3 = someClassToCastTo.cast(o);
对象在投射时没有任何反应。转换检查对象确实是String类,否则失败,这就是全部。但是一旦强制转换为String类型的变量,就可以访问String中存在的方法,并且当你有一个Object类型的变量时,你就无法调用它。
答案 2 :(得分:2)
这就是:
Object o = "str";
String str1 = (String) o;
仅当对象实际上是字符串时才有效。
String str2 = o.toString();
在String对象上使用toString()时,您将获得字符串本身。当object o为null时,它将抛出异常。
String str3 = String.class.cast(o);
主要在使用反射时使用,即当您想通过反射检索类标记时。
答案 3 :(得分:1)
Java是强类型语言,它只允许将对象转换为其中一个父类或接口。也就是说,如果您有以下内容:
class A {}
interface I {}
class B extends A implements I {}
class C {}
您可以像这样强制转换B类对象:
B b = new B();
A a = b; // no need for explicit casting
I i = b;
Object o = b; // Object is implicit parent of A
C c = b; // ERROR C isn't a parent class of b
这称为向上转播。你也可以垂头丧气:
A a = new B();
B b = (B) b;
你需要在这里使用显式强制转换,如果真的允许强制转换,JVM将在运行时检查。
当你不知道在编译时你要投射到的特定类型时,String.class.cast(o)
投射很有用。
.toString()
不是施法者。它只是一个方法,它应该返回对象的String表示。但是表示不是 对象,它只是一种表示。此方法在Object
类中定义,因此它存在于所有类中,并在某种程度上用语言烘焙。也就是说,如果你写
String s = "Hell " + o;
JVM将为您调用o.toString()
方法来获取它的表示。
答案 4 :(得分:1)
你可以自己解释一下。
$ cat Cast.java
public class Cast {
private Cast() {}
public static void main(String[] args) {
Object o = "str";
String str1 = (String) o; // Method 1
String str2 = o.toString(); // Method 2
String str3 = String.class.cast(o); // Method 3
}
}
$ javac Cast.java
$ javap -c Cast
Compiled from "Cast.java"
public class Cast {
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String str
2: astore_1
3: aload_1
4: checkcast #3 // class java/lang/String
7: astore_2
8: aload_1
9: invokevirtual #4 // Method java/lang/Object.toString:()Ljava/lang/String;
12: astore_3
13: ldc #3 // class java/lang/String
15: aload_1
16: invokevirtual #5 // Method java/lang/Class.cast:(Ljava/lang/Object;)Ljava/lang/Object;
19: checkcast #3 // class java/lang/String
22: astore 4
24: return
}
如您所见,
checkcast
操作码。invokevirtual
操作码。ldc
(加载类),后跟invokevirtual
和checkcast
。显然,方法3在详细程度,可读性和性能方面都较差。
1和2,哪个更好?
checkcast
表示“查看此对象:它真的是String
吗?” - 如果是的话,继续进行分配;如果没有,请抛出ClassCastException
。
invokevirtual
表示“根据toString()
类查找要调用的o
方法” - 在这种情况下,它是String.toString()
。该方法的明显实现是
public String toString() {
return this;
}
在询问“它是String
?”和“它是什么类型”之间做出选择?我们称之为哪种方法?让我们用String.toString()
作为隐含参数执行str2
。“ - 方法1应该更简单。