Home > database >  Java : Is this code an example of typecasting or not in java?
Java : Is this code an example of typecasting or not in java?

Time:12-20

public class main {
    public static void main(String[] args) {

        double num = 324.2;

        System.out.println((int)num);
    }
}

Is this code above is an example of typecasting ?

CodePudding user response:

Informally, Yes. Java programmers (myself included) will often refer to that as a type cast.

But strictly speaking, the Java Language Specification (JLS) does not define or even use the phrases "type cast" or "typecast" anywhere. (You can confirm this for yourself by doing a text search of the PDF version of the spec. I am looking at the latest version.)

According to the JLS, (int) num is an example of a cast expression; see JLS 15.16. The operation performs a casting conversion on its operand.

CodePudding user response:

All casts are 'type casts'; in fact, 'type cast' as a term doesn't show up.

It's particularly dangerous to use this term. Cast should almost never be used.

The problem is, this is the 'cast operator': (Type) expression;.

And it does 5 different things, some of which are utterly unrelated to each other. A real guns and grandmas situation. As different as this:

int a = 5   2; // 7
String b = "hello"   "world" // helloworld

They both use , it's both called 'the plus operator', and yet one does numeric addition and the other does the completely unrelated thing of string concatenation.

So too, with the cast operator.

Primitive conversion

If the 'type' in the parens is a primitive type, then java will treat the expression as primitive (it has to be either primitive, or, a boxed type in which case it will unbox it), and then convert. This is the only one of the various things a cast operator can do that converts anything. For example:

double x = 5.5;
int y = (int) x;

This treats x as a primitive (it already is, so that doesn't do anything) and then converts it. double to int conversion lops off the stuff after the decimal separator, so, y is now 5.

Type coercion

Object x = "Hello";
String y = (String) x;

This converts nothing. java generates the following code:

IS expression x in fact pointing at an object that is an instance of String or some subtype of String?

If YES -> Do absolutely nothing and continue; as far as javac is concerned. the expression (String) x is of type String even if x is not.

If NO -> throw a ClassCastException.

In no case does this convert anything. For example:

Double d = 5.5;
String x = (String) d;

does not even compile. Even if you try to make it:

Double d = 5.5;
Object o = d;
String x = (String) o;

you get a ClassCastException.

Type assertion

List<Object> o = new ArrayList<Object>();
o.add(5.5);
List<String> x = (List<String>) o;

Here the only part in the parens that is noteworthy is the <String> part - the generics. That part is just an assertion you make as a programmer. You're telling javac to treat the expression (List<String>) o as being of type List<String>, even if o is not. Java does nothing. This code CANNOT fail at runtime. Even in the above case, where there is a non-string in there! - java will just blindly carry on. But, x is now 'heap polluted' , it is of type List<String> but is in fact pointing at a list that doesn't have strings in it. That means later on if you do:

String y= x.get(0);

You get a ClassCastException, which is weird, because there is no cast on this line! - and yet, that is how it works. Generally you should avoid type assertions. When you do write a type assertion, javac will warn you.

Explicit type widening

Types in java 'widen' automatically; for example, if you have this method:

void foo(Object o) {}

you can invoke it with foo("Hello"). Even though "Hello" is a String - but all Strings are Objects, so a String 'just works' when an Object is needed, you don't need to cast it. However, you can, if you want. Ordinarily this is pointless, but if there are multiple overloads it can matter. Given:

void foo(String o) { System.out.println("String variant"); }
void foo(Object o) { System.out.println("Object variant"); }

You can call foo("Hello") and this will print 'String variant'. But, you can also write:

foo((Object) "Hello")

and this would print 'Object variant'. (Overloading is statically dispatched; it's overrides that are dynamically dispatched).

It's a rather significant code smell if this ever comes up.

Lambda enforcement

In java, closures/lambdas are allowed but have to be placed in a context where it is clear what type you wanted, and that type has to be a Functional Interface type. For example:

Runnable r = () -> System.out.println("Hello!"):

is legal java, but only because the Runnable r = part tells java you want it to be a Runnable (and Runnable is a functional interface, hence, okay). This won't compile:

Object o = () -> System.out.println("Hello!");

Because Object is not a functionalinterface. You can force it with a cast. This DOES compile:

Object o = (Runnable) () -> System.out.println("Hello!");

You rarely need this one.

Closing advice

Never use the term 'cast' unless you are talking about the syntax itself (rare that you need to talk about this). Instead, use the term 'primitive type convert', 'type coerce' or 'type assert'.

NB: Those last 2 exotic cases are using type coerce to accomplish a goal other than actually coercing a type.

  • Related