在Java中转换对象的不同方法

时间:2015-06-05 07:44:29

标签: java casting

我知道以下三种可用于投射对象的方法。

Object o = "str";

String str1 = (String) o;                // Method 1

String str2 = o.toString();              // Method 2

String str3 = String.class.cast(o);      // Method 3
  1. 哪种方法更好,与其他方法相比,哪种方法的优缺点是什么?
  2. 在内部施放时物体会发生什么?

5 个答案:

答案 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
}

如您所见,

  1. 方法1只是checkcast操作码。
  2. 方法2是invokevirtual操作码。
  3. 方法3是ldc(加载类),后跟invokevirtualcheckcast
  4. 显然,方法3在详细程度,可读性和性能方面都较差。

    1和2,哪个更好?

    checkcast表示“查看此对象:它真的是String吗?” - 如果是的话,继续进行分配;如果没有,请抛出ClassCastException

    invokevirtual表示“根据toString()类查找要调用的o方法” - 在这种情况下,它是String.toString()。该方法的明显实现是

    public String toString() {
        return this;
    }
    

    在询问“它是String?”和“它是什么类型”之间做出选择?我们称之为哪种方法?让我们用String.toString()作为隐含参数执行str2。“ - 方法1应该更简单。