Return-Path: <env_26473261488414516@hermes.java.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id UAA07319; Tue, 9 Oct 2001 20:58:40 -0400 (EDT)
Received: from hermes.java.sun.com (hermes.java.sun.com [64.124.140.163])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id UAA19498
	for <alexp@mit.edu>; Tue, 9 Oct 2001 20:58:36 -0400 (EDT)
Message-Id: <200110100058.UAA19498@pacific-carrier-annex.mit.edu>
Date: Wed, 10 Oct 2001 00:58:36 GMT+00:00
From: "JDC Tech Tips" <body_26473261488414516@hermes.java.sun.com>
To: alexp@mit.edu
Subject: JDC Tech Tips  October 9, 2001
Precedence: junk
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Beyond Email 2.2


 J  D  C    T  E  C  H    T  I  P  S

                      TIPS, TECHNIQUES, AND SAMPLE CODE


WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, 
October 9, 2001. This issue covers:

         * How Arguments are Passed to Java(tm) Methods
         * Converting C Programs to the Java Programming Language
                 
These tips were developed using Java(tm) 2 SDK, Standard Edition, 
v 1.3.

You can view this issue of the Tech Tips on the Web at
http://java.sun.com/jdc/JDCTechTips/2001/tt1009.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
HOW ARGUMENTS ARE PASSED TO JAVA METHODS

Suppose you're doing some Java programming, and you have a
simple program like this:

    public class CallDemo1 {
        static void f(int arg1) {
            arg1 = 10;
        }
    
        public static void main(String args[]) {
            int arg1;
    
            arg1 = 5;
    
            f(arg1);
    
            System.out.println("arg1 = " + arg1);
        }
    }

In the main method, the variable arg1 is given the value 5, and 
then passed as an argument to the method f. This method declares 
a parameter of the same name, arg1, used to access the argument.

What happens when you run this simple program? The method f
modifies the value of arg1, so what value gets printed, 5 or 10? 
It turns out that 5 is the right answer. This implies that 
setting arg1 to 10 in method f has no effect outside of the 
method.

Why does it work this way? The answer has to do with the
distinction between the pass-by-value and pass-by-reference
approaches to passing arguments to a method. The Java language 
uses pass-by-value exclusively. Before explaining what this 
means, let's look at an example of pass-by-reference, using 
C++ code:

    // CallDemo1.cpp
    
    #include <iostream>
    
    using namespace std;
    
    void f(int arg1, int& arg2)
    {
        arg1 = 10;
        arg2 = 10;
    }
    
    int main()
    {
        int arg1, arg2;
    
        arg1 = 5;
        arg2 = 5;
    
        f(arg1, arg2);
    
        cout << "arg1 = " << arg1 << " arg2 = " 
                                       << arg2 << endl;
    }

Function f has two parameters. The first parameter is a 
pass-by-value parameter, the second a pass-by-reference one. When 
you run this program, the first assignment in function f has no 
effect in the caller (the main function). But the second 
assignment does, in fact, change the value of arg2 in main. The 
& in int& says that arg2 is a pass-by-reference parameter. This 
particular example has no equivalent in Java programming.

So what does pass-by-value actually mean? To answer this, it's
instructive to look at some JVM* bytecodes that result from the
following two commands:

    javac CallDemo1.java

    javap -c -classpath . CallDemo1

Here is an excerpt from the output:

    Method void f(int)
        0 bipush 10
        2 istore_0
        3 return

    Method void main(java.lang.String[])
        0 iconst_5
        1 istore_1
        2 iload_1
        3 invokestatic #2 <Method void f(int)>

In the main method, the instruction iconst_5 pushes the value 5 
onto the operand stack of the Java virtual machine. This value is 
then stored in the second local variable (arg1, with args as the
first local variable). iload_1 pushes the value of the second 
local variable onto the operand stack, where it will serve as an 
argument to the called method.

Then the method f is invoked using the invokestatic instruction. 
The argument value is popped from the stack, and is used to 
create a stack frame for the called method. This stack frame 
represents the local variables in f, with the method parameter 
(arg1) as the first of the local variables.

What this means is that the parameters in a method are copies
of the argument values passed to the method. If you modify a 
parameter, it has no effect on the caller. You are simply 
changing the copy's value in the stack frame that is used to hold
local variables. There is no way to "get back" at the arguments 
in the calling method. So assigning to arg1 in f does not change 
arg1 in main. Also, the arg1 variables in f and in main are 
unrelated to each other, except that arg1 in f starts with a copy 
of the value of arg1 in main. The variables occupy different 
locations in memory, and the fact that they have the same name is 
irrelevant.

By contrast, a pass-by-reference parameter is implemented by 
passing the memory address of the caller's argument to the called 
function. The argument address is copied into the parameter. The 
parameter contains an address that references the argument's 
memory location so that changes to the parameter actually change 
the argument value in the caller. In low-level terms, if you have 
the memory address of a variable, you can change the variable's 
value at will.

The discussion of argument passing is complicated by the fact 
that the term "reference" in pass-by-reference means something 
slightly different than the typical use of the term in Java 
programming. In Java, the term reference is used in the context 
of object references. When you pass an object reference to a 
method, you're not using pass-by-reference, but pass-by-value. 
In particular, a copy is made of the object reference argument 
value, and changes to the copy (through the parameter) have no 
effect in the caller. Let's look at a couple of examples to 
clarify this idea:

    class A {
        public int x;
    
        A(int x) {
            this.x = x;
        }
    
        public String toString() {
            return Integer.toString(x);
        }
    }
    
    public class CallDemo2 {
        static void f(A arg1) {
            arg1 = null;
        }
    
        public static void main(String args[]) {
            A arg1 = new A(5);
    
            f(arg1);
    
            System.out.println("arg1 = " + arg1);
        }
    }

In this example, a reference to an A object is passed to f. 
Setting arg1 to null in f has no effect on the caller, just as in 
the previous example. The value 5 gets printed. The caller passes 
a copy of the object reference value (arg1), not the memory 
address of arg1. So the called method cannot get back at arg1 and 
change it.

Here's another example:

    class A {
        public int x;
    
        public A(int x) {
            this.x = x;
        }
    
        public String toString() {
            return Integer.toString(x);
        }
    }
    
    public class CallDemo3 {
        static void f(A arg1) {
            arg1.x = 10;
        }
    
        public static void main(String args[]) {
            A arg1 = new A(5);
    
            f(arg1);
    
            System.out.println("arg1 = " + arg1);
        }
    }

What gets printed here is 10. How can that be? You've already 
seen that there's no way to change the caller's version of arg1 
in the called method. But this code shows that the object 
referenced by arg1 can be changed. Here, the calling method and 
the called method have an object in common, and both methods can 
change the object. In this example, the object reference (arg1) 
is passed by value. Then a copy of it is made into the stack 
frame for f. But both the original and the copy are object 
references, and they point to a common object in memory that can 
be modified.

In Java programming, it's common to say things like "a String 
object is passed to method f" or "an array is passed to 
method g." Technically speaking, objects and arrays are not 
passed. Instead, references or addresses to them are passed. For 
example, if you have a Java object containing 25 integer fields, 
and each field is 4 bytes, then the object is approximately 100 
bytes long. But when you pass this object as an argument to a 
method, there is no actual copy of 100 bytes. Instead, a pointer, 
reference, or address of the object is passed. The same object is 
referenced in the caller and the called method. By contrast, in 
a language like C++, it's possible to pass either an actual 
object or a pointer to the object.

What are the implications of pass-by-value? One is that when you
pass objects or arrays, the calling method and the called method
share the objects, and both can change the object. So you might
want to employ defensive copying techniques, as described in
the September 4, 2001 Tech Tip, "Making Defensive Copies of 
Objects" 
(http://java.sun.com/jdc/JDCTechTips/2001/tt0904.html#tip1).

You can fix the case above, where the called method modifies an 
object, by making the class immutable. An immutable class is one
whose instances cannot be modified. Here's how you to do this:

    final class A {
        private final int x;
    
        public A(int x) {
            this.x = x;
        }
    
        public String toString() {
            return Integer.toString(x);
        }
    }
    
    public class CallDemo4 {
        static void f(A arg1) {
            //arg1.x = 10;
        }
    
        public static void main(String args[]) {
            A arg1 = new A(5);
    
            f(arg1);
    
            System.out.println("arg1 = " + arg1);
        }
    }
    
The printed result is 5. Now uncomment the modification of A
in f and recompile the program.  Notice that it results in a  
compile error. You have made A immutable, so it can't be
legally modified by f.

Another implication of pass-by-value is that you can't use method
parameters to return multiple values from a method, unless you 
pass in a mutable object reference or array, and let the method 
modify the object. There are other ways of returning multiple 
values, such as returning an array from the method, or creating 
a specialized class and returning an instance of it.

For more information about how arguments are passed to Java 
Methods, see Section 1.8.1, Invoking a Method, and section 2.6.4, 
Parameter Values, in "The Java(tm) Programming Language Third 
Edition" by Arnold, Gosling, and Holmes 
http://java.sun.com/docs/books/javaprog/thirdedition/. Also see
item 13, Favor immutability, and item 24, Make defensive copies 
when needed, in "Effective Java Programming Language Guide" by 
Joshua Bloch 
(http://java.sun.com/docs/books/effective/).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CONVERTING C PROGRAMS TO THE JAVA PROGRAMMING LANGUAGE

Imagine that you have a large body of C code, and you're thinking
about recoding it using Java features. What are some of the "big
picture" issues that you need to consider when you do this? This
tip presents a series of examples, and covers some of the issues
in converting C code to the Java language. It focuses, in 
particular, on program and data structuring.

One preliminary note about this kind of conversion. The C and 
Java languages are very different. C is targeted toward systems
programming and the ability to perform low-level manipulations. 
By comparison, the Java language takes a higher-level view, and 
has better facilities for writing large, well-structured, 
hardware-independent applications. So understand that some 
features in each language do not exist or are very different in 
the other.

Let's start by looking at a simple C program, one that contains a
global variable whose value is set and then retrieved and printed:

    /* ConvDemo1.c */
    
    #include <stdio.h>
    
    int current_month;  
    /* current month as a value 1-12 */
    
    int main()
    {
        current_month = 9;
    
        printf("current month = %d\n", current_month);
    
        return 0;
    }

When you run the program, the result is:

    current month = 9

There is no Java equivalent to a global variable, so how would 
you write a corresponding program? Here's one way of doing it:

    class Globals {
        private Globals() {}
    
        public static int current_month;
    }
    
    public class ConvDemo1 {
        public static void main(String args[]) {
            Globals.current_month = 9;
    
            System.out.println("current month = " +
                Globals.current_month);
        }
    }

The class Globals has a private constructor (so that no instances 
of the class can be created), and defines a public static field. 
Once this is done, Globals.current_month can be accessed 
throughout the application, just as a global variable would be in 
C. As is the case with other names, you might need to qualify 
Globals with a package name, depending on how you structure your
program. And you might want to replace the 9 with a symbolic
constant name like SEPTEMBER, or use an enumerated type for the
month.

ConvDemo1 is a very simple program that works, but there is an 
immediate issue. The current_month field is public, and it's
possible to say something like:

    Globals.current_month = -37;

and cause havoc by doing so. Typically, when you do Java
programming, you make fields like current_month private. You then 
control access to these private fields by means of constructors 
or accessor and mutator methods. Here's a program that takes
this approach -- it makes the current_month field private, and 
defines two methods to set and get the field's value:

    class Globals {
        private Globals() {}
    
        private static int current_month;
    
        public static void setCurrentMonth(int m) {
            if (m < 1 || m > 12) {
                throw new IllegalArgumentException();
            }
            current_month = m;
        }
    
        public static int getCurrentMonth() {
            return current_month;
        }
    }
    
    public class ConvDemo2 {
        public static void main(String args[]) {
            Globals.setCurrentMonth(9);
    
            System.out.println("current month = " +
                Globals.getCurrentMonth());
        }
    }

The approach illustrated in ConvDemo2 raises a question: how far 
do you want to diverge from the original structure of your C 
program when you convert it to use Java features? There's more 
than one right answer.

There's yet another way to write this program. The ConvDemo2
program does not actually use Java objects. No instances of 
the Globals class are created. Here's an alternative, one that 
defines a Globals class and creates a Globals object:

    class Globals {
        private int current_month;
    
        private static final Globals globlist = 
                                         new Globals();
    
        private Globals() {
            current_month = 1;
        }
    
        public static Globals getInstance() {
            return globlist;
        }
    
        public void setCurrentMonth(int m) {
            if (m < 1 || m > 12) {
                throw new IllegalArgumentException();
            }
            current_month = m;
        }
  
        public int getCurrentMonth() {
            return current_month;
        }
    }
    
    public class ConvDemo3 {
        public static void main(String args[]) {
            Globals.getInstance().setCurrentMonth(9);
    
            System.out.println("current month = " +
              Globals.getInstance().getCurrentMonth());
        }
    }

In the ConvDemo3 example, Globals is a singleton class, that is,
it's instantiated exactly once. The getInstance method is called 
a "static factory method." The program could have instead made 
globlist a public static final field, but doing it this way 
allows the singleton property to be broken if needed at some 
later time.

This approach is perhaps the most natural in Java terms. Here a 
set of globals is represented as an object that you manipulate in 
the usual object-oriented way, but it's the furthest from the 
original C code.

You can use a Java class to structure global functions in a 
similar way to what's been shown so far with global data. Classes 
can be used simply as packaging vehicles. Note that when you use 
singletons and static fields, there are some issues with 
serialization that you might need to consider.

Let's look at a totally different area: the Java equivalent of C
unions. A union is something like a class structure, but the 
fields overlap in memory, and only one of a set of fields is 
active at a time. Usually there is a tag field that says which 
field is active. Here's a C program that uses a union:

    /* ConvDemo4.c */

    #include <stdio.h>
    
    enum Type {DAYS, HOURSMINUTES};
    
    struct Days {
        int num_days;
    };
    
    struct HoursMinutes {
        int num_hours;
        int num_minutes;
    };
    
    struct Time {
        enum Type tag;
        union {
            struct Days days;
            struct HoursMinutes hm;
        } u;
    };
    
    void print(struct Time ti)
    {
        int minutes;
    
        if (ti.tag == DAYS) {
            minutes = ti.u.days.num_days * 24 * 60;
        }
        else {
            minutes = ti.u.hm.num_hours * 
                              60 + ti.u.hm.num_minutes;
        }
    
        printf("number of minutes = %d\n", minutes);
    }
     
    
    int main()
    {
        struct Time ti;
    
        ti.tag = DAYS;
        ti.u.days.num_days = 10;
        print(ti);
    
        ti.tag = HOURSMINUTES;
        ti.u.hm.num_hours = 15;
        ti.u.hm.num_minutes = 59;
        print(ti);
    }

In this program, an interval of time is represented by either a
number of days or by an hours/minutes object. The union within 
the Time structure contains an instance of each of these objects.
However, the objects overlap, and only one of them is valid at 
any time.

When you run the program, the output is:

    number of minutes = 14400

    number of minutes = 959

How would you create an equivalent Java program? From studying 
the C program, it's clear that there are multiple data 
representations, and for each representation, you want to obtain 
the number of elapsed minutes from the corresponding object.

One Java approach is to define an abstract class called Time that
specifies a getMinutes method. You then define concrete 
subclasses of Time called Days and HoursMinutes. Each subclass 
defines a specific data representation, and implements getMinutes 
accordingly.

Here's what the code looks like:

    abstract class Time {
        abstract int getMinutes();
    }
    
    class Days extends Time {
        private final int num_days;
    
        public Days(int num_days) {
            this.num_days = num_days;
        }
    
        public int getMinutes() {
            return num_days * 24 * 60;
        }
    }
    
    class HoursMinutes extends Time {
        private final int num_hours;
        private final int num_minutes;
    
        public HoursMinutes(int num_hours, int num_minutes) {
            this.num_hours = num_hours;
            this.num_minutes = num_minutes;
        }
    
        public int getMinutes() {
            return num_hours * 60 + num_minutes;
        }
    }
    
    public class ConvDemo4 {
        public static void main(String args[]) {
            Time t = new Days(10);
            System.out.println("minutes = " + t.getMinutes());
    
            t = new HoursMinutes(15, 59);
            System.out.println("minutes = " + t.getMinutes());
        }
    }

The ConvDemo4 program uses a variable of the abstract class type 
(Time) to hold a reference to either a Days or an HoursMinutes 
object. There's no tag field used with the Java code. Run-time 
type information is available, so that if you have a variable of 
type Time, you can find out what the real type is, for example, 
by using the instanceof operator.

So far the examples have used global variables and functions, and 
the Java equivalent of unions. Let's consider one final example, 
one where you have some type of global data object, using
structures and arrays. Here's the C code:

    /* ConvDemo5.c */

    #include <stdio.h>
    
    struct A {
        int x;
        int y;
    };
    
    struct B {
        struct A a1;
        int b[5];
        struct A a2;
    };
    
    struct B b = {
        {37, 47},
        {1, 2, 3, 4, 5},
        {57, 67}
    };
    
    int main()
    {
        printf("%d %d\n", b.a2.y, b.b[2]);
    }

The ConvDemo5.c program defines a structure A, with two integer 
fields. It then defines a structure B that contains an A object, 
an array, and another A object. An instance of the B structure is 
initialized as global data. When you run the program, the output 
is:

    67 3

What's the Java equivalent to the ConvDemo5.c program? The Java 
language has no global variables, as mentioned earlier. 
Furthermore, objects and arrays are always dynamically allocated
in the Java language. So the corresponding program looks like
this:

    class A {
        public int x;
        public int y;
        A(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    
    class B {
        public A a1;
        public int b[];
        public A a2;
        B(A a1, int b[], A a2) {
            this.a1 = a1;
            this.b = b;
            this.a2 = a2;
        }
    }
    
    class Globals {
        private Globals() {}
        public static B b = new B(
            new A(37, 47),
            new int[]{1, 2, 3, 4, 5},
            new A(57, 67)
        );
    }
    
    public class ConvDemo5 {
        public static void main(String args[]) {
            System.out.println(Globals.b.a2.y + " " +
                Globals.b.b[2]);
        }
    }

This Java code is a simple translation of the C code. You might
want to modify it as discussed earlier, for example, by making 
some of the fields private instead of public.

With C programming, if you say:

    struct B {
        struct A a1;
        int b[5];
        struct A a2;
    };

    struct B b;

then the b object really does contain two A objects and an array
laid out together in memory. But the equivalent Java object
contains three fields, with each field a reference; the actual A 
objects and the array are stored elsewhere in memory. A corollary
to this point is that there's no Java equivalent to some of the
low-level manipulations you can do with C objects. For example,
there are no Java equivalents to obtaining the size of an object, 
figuring out the memory offset of a field, making assumptions 
that fields are together in memory, and so on.

The examples above illustrated several issues that you need to 
consider when converting C code to the Java language. There are 
some tradeoffs here. You really need to decide how closely the
Java code should match the corresponding C, and how much you want 
to employ Java features to improve the robustness of your 
application.

For more information about Converting C Programs to the Java 
Language, see Section 2.2, Fields, in "The Java(tm) Programming 
Language Third Edition" by Arnold, Gosling, and Holmes 
http://java.sun.com/docs/books/javaprog/thirdedition/. Also see
item 20, Replace unions with class hierarchies, in "Effective 
Java Programming Language Guide" by Joshua Bloch 
(http://java.sun.com/docs/books/effective/).
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

IMPORTANT: Please read our Terms of Use and Privacy policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/ 

* FEEDBACK
  Comments? Send your feedback on the JDC Tech Tips to: 
  jdc-webmaster@sun.com

* SUBSCRIBE/UNSUBSCRIBE
  - To subscribe, go to the subscriptions page,
    (http://developer.java.sun.com/subscription/), choose
    the newsletters you want to subscribe to and click "Update".
  - To unsubscribe, go to the subscriptions page,
    (http://developer.java.sun.com/subscription/), uncheck the
    appropriate checkbox, and click "Update".
  - To use our one-click unsubscribe facility, see the link at 
    the end of this email:
    
- ARCHIVES
You'll find the JDC Tech Tips archives at:

http://java.sun.com/jdc/TechTips/index.html


- COPYRIGHT
Copyright 2001 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.

This document is protected by copyright. For more information, see:

http://java.sun.com/jdc/copyright.html

This issue of the JDC Tech Tips is written by Glen McCluskey.

JDC Tech Tips 
October 9, 2001

* As used in this document, the terms "Java virtual machine" or 
  "JVM" mean a virtual machine for the Java platform. 

Sun, Sun Microsystems, Java, and Java Developer Connection are 
trademarks or registered trademarks of Sun Microsystems, Inc. in 
the United States and other countries.

To use our one-click unsubscribe facility, select the following URL:
http://hermes.java.sun.com/unsubscribe?26473261488414516
