17

I know the three following methods that can be used for casting objects.

Object o = "str";

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

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

String str3 = String.class.cast(o);      // Method 3
  1. Which approach is better, and what are the pros/cons of one method as compared to the others?
  2. What happens to the object during the time of casting internally?
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Muhammad Suleman
  • 2,892
  • 2
  • 25
  • 33
  • 7
    Actually, `o.toString()` is not a cast, you just get the string representation of an object ;) – NiziL Jun 05 '15 at 07:50
  • Missing: `String str4 = String.valueOf(o);`, which is IMHO the preferred solution, as it does not cast at all, and nicely covers the case that `o` is `null`. – Marco13 Jun 05 '15 at 16:10
  • @Marco13: i have asked this in an answer mentioned by "Rahul Tripathi". this was in my mind but i thought its pretty straight forward method call and doesn't link with casting – Muhammad Suleman Jun 07 '15 at 06:12

5 Answers5

13

The second method that you show is not casting; it's simply calling the toString() method on an object, which is not different than any other method call:

String str2 = o.toString();

The effect of the first and third methods is essentially the same. I would prefer using the first method.

What happened with object on the time of casting internally?

Nothing happens to the object. Casting is not a way to somehow automatically convert objects from one type to another type. The only thing that a cast does, is tell the compiler to accept the assignment statement and not check the types for this statement. You're saying to the compiler "I know better than you what kind of object this is, so let me do this assignment and don't complain about the type".

In your example, the type of the variable o is Object. When you assign o to a variable of type String, the compiler won't allow it because it checks the types, and it can't be sure that o in fact refers to a String object. So you use a cast to tell the compiler "I know this is a String object, so let me do this assignment".

The type will still be checked, but at runtime, not at compile time. If, at runtime, the type of the object is not String, you'll get a ClassCastException.

Jesper
  • 202,709
  • 46
  • 318
  • 350
4

The first one casts the o reference, whose declared type is Object, and whose actual, concrete type is String, to a String. This is the canonical way of casting. That will only work if the object referenced by o is actually of type String. If it isn't, you'll have a ClassCastException.

The second one doesn't cast at all. It calls the toString() on the object referenced by o. That will always work, but it's really really different from a cast.

The third one uses reflection to do a cast. That will have the same effect as the first one, and will work in the same circumstances. But this will generally only be used when the code doesn't actually know the type of the class to cast to:

Class<?> someClassToCastTo = ...; // could be String.class or anything else, you don't know)

String str3 = someClassToCastTo.cast(o);

Nothing happens to the object when it's cast. Casting checks that the object is indeed of class String, and fails otherwise, that's all. But once cast to a variable of type String, you can access the methods that exist in String, and that you couldn't have called when you had a variable of type Object.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
3

Here it goes:

Object o = "str";

String str1 = (String) o;

This works only when the object actually is a string.

String str2 = o.toString();

When you use toString() on a String object, you obtain the string itself. It will throw an exception when object o is null.

String str3 = String.class.cast(o);

Mainly used when using reflection, i.e. when you want to retrieve the Class token via reflection.

user207421
  • 305,947
  • 44
  • 307
  • 483
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • what about : String.valueOf(o); ? – Muhammad Suleman Jun 05 '15 at 07:55
  • 1
    If your object is null then `String.valueOf(o);` will return `null` whereas `o.toString();` will return `NullPointerException`. Note that `String.valueOf()` tries to convert whatever you pass into it to a String. It can handle both primitives and objects – Rahul Tripathi Jun 05 '15 at 07:56
  • 1
    `String.valueOf()` will return `"null"`, not null. There's a difference. `o.toString()` will *throw* `NullPointerException.` Don't bury your answer in the code. – user207421 Jun 05 '15 at 11:51
2

You can actually reason this out yourself.

$ 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
}

As you can see,

  1. Method 1 is just a checkcast opcode.
  2. Method 2 is an invokevirtual opcode.
  3. Method 3 is an ldc (load class), followed by invokevirtual and checkcast.

Obviously, Method 3 is inferior in terms of verbosity, readability, and performance.

Of 1 and 2, which is better?

checkcast means "look at this object: is it really a String?" — if so, proceed with the assignment; if not, throw a ClassCastException.

invokevirtual means "look up which toString() method to call based on the class of o" — in this case, it's String.toString(). The obvious implementation of that method is

public String toString() {
    return this;
}

Given the choice between asking "Is it a String? and "What type is it? which method do we call as a result? Let's execute String.toString() on with str2 as the implied parameter." — Method 1 should be quite a bit simpler.

200_success
  • 7,286
  • 1
  • 43
  • 74
1

Java is strongly typed language and it only allows casting an object to one of it parent classes or interfaces. That is, if you have the following:

class A {}

interface I {}

class B extends A implements I {}

class C {}

You can cast an object of type B like so:

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

This is called upcasting. You can also downcast:

A a = new B();
B b = (B) b;

you need to use explicit cast here and JVM will check in runtime if the cast is really allowed.

The String.class.cast(o) casting is useful, when you don't know the specific type you're casting to in compile time.

The .toString() isn't casting. It's just a method, which is supposed to return a String representation of your object. But the representation isn't the object, it's just a representation. This method is defined in the Object class, so it's present in all classes and is baked in the language somewhat. That is, if you write

String s = "Hell " + o;

JVM will call o.toString() method for you to obtain it representation.

ivant
  • 3,909
  • 1
  • 25
  • 39