Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: which is faster overloading or if/else

I have child classes, each carries a different type of value along with other members. There may be a LongObject, IntObject, StringObject, etc.

I will be given a value, which can be a long, int, string, etc., and I have to create a LongObject, IntObject, StringObject, etc., respectively.

Would it be faster to overload a method as shown below (a) or just use a elseif as shown below (b)?

It may not be a noticeable performance difference. It may be that the overloaded methods are implemented in a similar manner to the if/else anyway. I don't know.

I can also hear some of you saying to just test it. Sure, I ought to. I would also like to know how this type of overloading is handled under the hood, if anyone knows.

Please let me know what you think.

Thanks, jbu

a)

BaseObject getObject(long l)
{
     return new LongObject(l);
}

BaseObject getObject(int i)
{
     return new IntObject(i);
}

BaseObject getObject(String s)
{
     return new StringObject(s);
}

...

b)

BaseObject getObject(Object x)
{
    if(value is a long)
         return new LongObject((Long)x);
    else if(value is an int)
         return new IntObject((Int)x);
    else if(value is a String)
         return new StringObject((String)x);
    ...
}

edit: I guess I didn't completely add all the details, some of you caught it. For both choices, I still have to get an object/value and from the value determine what type it is. Therefore, I still have to do an if/else of some sort to even use the overloaded methods.

like image 688
jbu Avatar asked Apr 16 '09 21:04

jbu


2 Answers

There's a massive discrepancy here: overloads are chosen at compile-time whereas your "if (value is a long)" would be an execution-time test.

If you know the type at compile-time, I strongly suggest you use that information. If you don't, then the overloading option isn't really feasible anyway.

EDIT: The comment suggests I elaborate a bit about overloads being chosen at compile-time.

The compiler picks which method signature is called based on compile-time information about the arguments. This is unlike overriding where the method implementation to use is determined by the type of the actual target of the method.

Here's an example:

public class Test
{
    public static void main(String[] args)
    {
        Object x = "I'm a string";
        foo(x);
    }

    public static void foo(String x)
    {
        System.out.println("foo(String)");
    }

    public static void foo(Object x)
    {
        System.out.println("foo(Object)");
    }
}

This prints foo(Object) because the compile-time type of x is Object, not String. The fact that the execution-time type of the object that x refers to is String doesn't mean that foo(String) is called.

like image 127
Jon Skeet Avatar answered Oct 12 '22 03:10

Jon Skeet


The overloading solution is much faster (and better) because it is resolved at compile time.

Basically the compiler figure out which method to invoke when you pass a value to it. When you call getObject("abc"), the compiler will emit calls to method:

BaseObject getObject(String s)
{
     return new StringObject(s);
}

rather than trying to go through your if ... else state and evaluate the object type (which is a slow activity) at run time.

like image 24
oscarkuo Avatar answered Oct 12 '22 03:10

oscarkuo