Java: Passing Variables into Methods

Java use pass-by-value semantics, instead of pass-by-reference, when passing variables to methods. This means that Java copies the variable values used by the caller to pass them to the method. If the variable has a primitive type, the value of the variable is passed. So, if the method does change the value received as argument, the variable value on the caller will not change. Otherwise, when the argument is an object, since Java copies the variable values and in this case the value is a reference (the address of the object on the heap), operations made on the object will take effect on the caller.

Examples showed on this post were built using a JDK 6.

Wrappers

Wrappers are Java objects which encapsulate primitive types. Wrappers have two main purposes:

  • Provide utility functions for primitive types
  • Allow primitive types to be used where only objects are accepted

Every primitive type has a wrapper class associated.

Since Java 5, we can use a feature called autoboxing to perform conversions between primitive types and wrappers automatically. The autoboxing feature allow us to assign wrappers to primitive types and vice-versa without the necessity of calling wrapper methods to unwrap and re-wrap. These operations are usually called boxing and unboxing.

public class Wrappers {

    public static void main(String... args) {

        // Before Java 5
        Integer i = new Integer(5); // create
        int x = i.intValue();       // unwrap
        x += 10;                    // use
        i = new Integer(x);         // re-wrap

        // After Java 5
        Integer j = new Integer(5); // create
        j += 10;                    // use
    }
}

Observation: two autoboxed instances of Boolean, Byte, Character from \u000 to \u007f (7f is 127 in decimal), Short and Integer (from -128 to 127) always pass a == test when their primitive values are the same. More about this can be found here.

Pop quiz: what is the output of the code below?

public class PopQuiz {
    public static void main(String... args) {
        Integer i1 = 1000;
        Integer i2 = 1000;

        if(i1 != i2) {
            System.out.print("1 ");
        }

        if(i1.equals(i2)) {
            System.out.print("2 ");
        }

        Integer i3 = 10;
        Integer i4 = 10;

        if(i3 == i4) {
            System.out.print("3 ");
        }

        if(i3.equals(i4)) {
            System.out.print("4");
        }
    }
}

Overloading

Overloading methods in Java can be a little bit difficult when many methods are eligible to match to a certain call. When this kind of situation happens, the Java compiler uses the following order of factors to determine which method will be invoked:

  • Widening
  • Autoboxing
  • Var-args

When there is a dispute widening is the winner over autoboxing and var-args. When there is a dispute between autoboxing and var-args, autoboxing wins.

public class Overloading {

    static void doSomething(long x) {
        System.out.println("long");
    }

    static void doSomething(Integer i) {
        System.out.println("Integer");
    }

    static void doSomething(Integer i, Integer j) {
        System.out.println("Integer Integer");
    }

    static void doSomething(int... ints) {
        System.out.println("ints...");
    }

    public static void main(String[] args) {
        int i = 10;
        int j = 20;

        doSomething(i);
        doSomething(i, j);
    }
}

In the example above, we first call the method doSomething passing an int as argument. As we have a widening and an autoboxing as options, widening wins and the argument is casted from int to long. In the second call, compilers need to decide between autoboxing and var-arg. Since the first one has higher priority, autoboxing will be used. The result of the execution of the code above is:

long
Integer Integer

Widening reference variables is also possible in Java. In this case, widening depends on inheritance and the IS-A test is used to perform the operation. The code below compiles normally.

class Vehicle {}

class Car extends Vehicle {}

public class OverloadingReferences {

    static void doSomething(Vehicle vehicle) {}

    public static void main(String[] args) {
        Car car = new Car();
        doSomething(car);
    }
}

Observation: type castings using references are called upcast when the object is casted to one of the classes or interfaces it inherits or implements, respectively. When the cast is made in the opposite direction (towards a more specific object) it is called downcast.

Advertisements

About Diego Lemos

Trainer, coach and polyglot programmer. Agile and software craftsmanship enthusiast.
This entry was posted in Java and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s