了解Java在用作方法参数时如何处理对象

时间:2014-01-16 20:43:30

标签: java parameters reference parameter-passing pass-by-reference

我一直在使用Java,并且不太了解java方法如何处理传递给它们的对象。

例如,在下面的代码中,我创建了一些包含另一个对象和基元的“Container”对象实例。当我将此“容器”对象传递给方法时,我可以更改容器实例中保存的对象,直接修改其值或使用 new 运算符构造新对象并替换其原始对象。这些更改是永久性的,因为在方法外部检查时,它们的值是新对象的值。

让我感到困惑的是,尽管我可以通过方法更改容器内部对象,但我无法逐步更改容器本身。我的意思是,如果我将容器传递给方法并尝试通过交换或从运算符分配来改变它。

下面是我用来测试对象实例属性的修改然后修改实际实例本身的代码。

class InsideRef{
    char myChar;
    InsideRef(char newVal){
        myChar = newVal;
    }
}

class Container{
    InsideRef myInRef = null;
    int myPrimitive = 0;
    Container(char innerChar, int innerPrim){
        myInRef = new InsideRef(innerChar);
        this.myPrimitive = innerPrim;
    }
    public void myDetails(){
        System.out.format("Container.%s => myPrimitive -> %d || myInRef => %s -> %c.%n",
        this.hashCode(),this.myPrimitive,this.myInRef.hashCode(),this.myInRef.myChar);
    }
}

class AttribRefModder{
    public static void ModObjRefVal(Container toEdit){
        toEdit.myInRef.myChar = 'Z';
    }
    public static void ModNewObjReference(Container toEdit){
        toEdit.myInRef = new InsideRef('Y');
    }
}

class RefSwapper{
    public static void RefSwap(Container A, Container B){
        System.out.println("Swapping....");
        System.out.print("OBJECT A -> ");
        A.myDetails();
        System.out.print("OBJECT B -> ");
        B.myDetails();
        Container temp = A;
        A = B;
        B = temp;
        System.out.print("SWAPPED A -> ");
        A.myDetails();
        System.out.print("SWAPPED B -> ");
        B.myDetails();
        System.out.println("Exiting....");
    }
    public static void RefNew(Container A){
        System.out.println("Assigning Reference New Object....");
        A = new Container('V',999);
        System.out.print("NEW C REF -> ");
        A.myDetails();
        System.out.println("Exiting....");
    }
}

public class ReferenceModding{
    public static void main(String[] args){
        System.out.println("-----------MODDING INNER REFS----------");
        Container C1 = new Container('A', 111);
        System.out.print("ORIGINAL A -> ");
        C1.myDetails();
        AttribRefModder.ModObjRefVal(C1);
        System.out.print("MODDED A.Ref -> ");
        C1.myDetails();
        AttribRefModder.ModNewObjReference(C1);
        System.out.print("NEW A.Ref -> ");
        C1.myDetails();
        System.out.println("----------SWAPPING REFERENCES----------");
        Container C2 = new Container('B',222);
        RefSwapper.RefSwap(C1, C2);
        System.out.print("OBJECT A -> ");
        C1.myDetails();
        System.out.print("OBJECT B -> ");
        C2.myDetails();
        System.out.println("----------ASSIGN NEW OBJECTS----------");
        Container C3 = new Container('C',333);
        System.out.print("OBJECT C -> ");
        C3.myDetails();
        RefSwapper.RefNew(C3);
        System.out.print("OBJECT C -> ");
        C3.myDetails();
    }
}

如果我发布的代码太多,我道歉。这只是我整天都在玩Java,这个对象参数业务让我很困惑。我无法解释为什么Java方法允许我编辑并将新对象分配给容器类中保存的InsideRef引用但不允许我对实际容器类执行相同的操作。

感谢您提供的任何帮助。

4 个答案:

答案 0 :(得分:2)

您已正确说明了Java的特性。

在封面下,您传递一个对象的引用 - 内存地址是一个很好的模型。因此,您可以更改该引用所引用的任何内容。

但你不能改变调用者认为的那个“那个对象” - 调用者有一个包含传递给你的地址的内存地址,你无法改变它。因此,无论您做什么,您都无法更改引用的对象,只能更改该对象的“内部”。

答案 1 :(得分:2)

我认为混淆来自RefSwap中的这一部分:

Container temp = A;
A = B;
B = temp;

在Java中,这只会影响该方法中的变量AB。当方法返回到调用它的位置时,它不会更改AB指向的对象。因此,在main中,对象C1C2仍然引用相同的Container对象,这些对象不会被交换。

答案 2 :(得分:0)

java中的参数传递总是按值传递。这意味着在赋值的左侧有一个参数在方法调用之外根本没有任何影响;它只是更改您在方法调用堆栈上复制的引用(指针)的值,因此您已经丢失了该方法其余部分的值。

例如,如果您声明

,PL / SQL有一个通过引用传递的真实参数
-- True pass-by-reference
procedure my_procedure(my_integer out integer) is
begin
  my_integer := 6;
end;

您将在过程调用后看到您传递的整数已更改其值。但是,java不支持此参数传递。想想C中的这样的事情:

// Just stepping on the values on the method call stack
void my_function(int* my_integer) {
   my_integer = 0;
}

这会改变指针引用的整数的值吗?不,它只是处理指针值。这就是你用

做的
A = new Container('V',999);

我希望这对你有任何帮助:)。

答案 3 :(得分:0)

  

当我通过这个"容器"反对方法

你需要了解的第一件事是不可能通过"传递" "对象"。 Java中唯一的类型是基本类型和引用类型。这意味着每个值都是基元或引用。 A"参考"是指向对象的指针。类型Container是引用类型 - 它是指向对象的指针的类型,特别是指向类Container的实例的指针。