Os fields primitivos são passados como valor, mas para os objetos é passado uma cópia da referência por valor, ou apenas uma cópia da referência como queira. Qdo se tira uma cópia de um objeto, a referência original e a cópia feita apontam para o mesmo objeto, se vc usar um método que altera o objeto, as duas referências perceberão esta alteração, mas se na cópia vc atribuir um novo objeto, esta perderá a referência para o objeto original e começará a apontar para esta nova atribuição, existem vários exemplos a respeito disso, abaixo existem alguns retirados da própria página da sun, o endereço é http://developer.java.sun.com/developer/JDCTechTips/2001/tt1009.html, eu fiz um outro (PassRef3) tb que vcs poderão testar a alteração do mesmo objeto, abaixo ...

class PassRef3 {
  public static void main(String args[]) {
    int val;
    StringBuffer sb1, sb2;
 
    val = 10;
    sb1 = new StringBuffer("PRIMEIRA STRING");
    sb2 = new StringBuffer("LUIZ");
    System.out.println("val: " + val);
    System.out.println("sb1: " + sb1);
    System.out.println("sb2: " + sb2);
    System.out.println("");
 
    System.out.println("chamando a metodo modify");
    //todos os parâmetros passados por valor (by val)
    modify(val, sb1, sb2);
    System.out.println("retornado da modify");
    System.out.println("");
 
    System.out.println("val: " + val);
    System.out.println("sb1: " + sb1);
    System.out.println("sb2: " + sb2);
   
    //r2 foi realmente alterado, pois foi usado um método
    //do próprio objeto, e todo método disparado de qq objeto
    //mesmo que este seje uma cópia, será alterado o objeto
    //de origem, ou seja, o mesmo objeto.
 
   
  }
 
  public static void modify(int a, StringBuffer r1, StringBuffer r2) {
    System.out.println("estou na modify...");
    a = 0;
    r1 = null;  //1
    r2.append(" EH UM CARA LEGAL !");
    System.out.println("a: " + a);
    System.out.println("r1: " + r1);
    System.out.println("r2: " + r2);
  }
}
 

 
 

 

http://developer.java.sun.com/developer/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 JVM1 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"

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 JavaTM Programming Language Third Edition" by Arnold, Gosling, and Holmes. Also see item 13, Favor immutability, and item 24, Make defensive copies when needed, in "Effective Java Programming Language Guide" by Joshua Bloch

 

 

 
 

Responder a