Java Pass值的问题?

时间:2009-12-17 08:43:41

标签: java

我们知道Java只支持“按值传递”。如果我将一个哈希表传递给函数,那么函数内部对此集合的修改不应该在此函数之外更新。但这不是Java中的情况?。我们如何做到这一点?

请任何人以证据结束本次讨论......

9 个答案:

答案 0 :(得分:8)

通过值将对象传递给方法意味着该方法被赋予对该对象的引用的副本,但仍然可以从传递的引用副本中访问对象成员。在集合的情况下,这包括调用添加和删除对象的方法,当然还包括修改包含的对象本身。

答案 1 :(得分:4)

你对“价值”的含义感到困惑。如果您正在处理对象,这意味着引用的的任何更改都不会反映到外部。显示此行为的简单示例如下所示:

public void foo() {
  String s = "example";
  String param = s;
  bar(param);
  assert s == param : "The value of parameter reference was not modified";
  assert param.equals("example");
}

public void bar(String param) {
  param = "something different";
}

按值传递并不意味着您无法更改对象的内部状态。这是完全可能的,并对外界产生影响:

public void foo() {
  List<String> l = Arrays.asList("example");
  List<String> param = l;
  bar(param);
  assert s == param : "The value of parameter reference was not modified";
  assert !param.get(0).equals("example") : "bar changed the internal state of the parameter";
  assert !l.get(0).equals("example") : "bar changed the internal state of the list that is reference equal to the parameter";
}

public void bar(List<String> param) {
  param.set(0, "something different");
}

当然,对象内部状态的这种变化会在调用者堆栈中一直反映出来,这可能会导致无法预料的副作用。这就是immutable object pattern被引入的原因。在Java标准库中,java.lang.Objectjava.lang.String是实现此模式的类的示例。但是,Java没有提供语言功能,您可以在其中声明类实现此模式,因此您必须依赖JavaDoc和/或类的源代码来确保对象是不可变的。

答案 2 :(得分:3)

如果您想要对象的“按值传递”行为,则可以传递方法clone对象,因此即使方法更改了传递的对象,原始对象仍保持不变。

答案 3 :(得分:2)

虽然它的“按值传递” - 在基元变量的情况下,变量的值被复制到函数中。在对象引用的情况下,在Hash表为真的情况下,引用中的值只是传递给堆上对象的地址。因此,在您传递“哈希表”的函数中的引用实际上是获取哈希表对象的地址的副本。因此,在函数中所做的任何更改都会反映在主对象中。

答案 4 :(得分:1)

在Java中,您永远不会传递对象,只传递对象的引用/指针。所以在通话中

Object x = new Object();
int y = 42;

foo(x,y)

传递x的值,即对象的(引用),以及y的值,即整数42.“按引用传递”意味着您可以更改变量的值,x和y,withing foo()。

答案 5 :(得分:1)

证据:

public static void main(String[] args) {
    int i = 1;
    addOne(i);
    System.out.println("after addOne: " + i);

    // now for Objects
    String text = "a text";
    addText(text);
    System.out.println("after addText: " + text);
}


private static void addOne(int i) {
    i += 1;
    System.out.println("in addOne: " + i);
}

private static void addText(String text) {
    text += ", more text";
    System.out.println("in addText: " + text);
}

应该导致

in addOne: 2
after addOne: 1
in addText: a text, more text
after addText: a text

你可以看到main中的变量没有被改变,也就是说,变量是按值传递的。

答案 6 :(得分:0)

Java是按值传递但是当我们传递对象引用时,引用值是传递给方法,从那里方法可以改变对象成员的值。

查看以下代码

公共类Passbyvalue {

public static void main(String[] args) {
    // TODO code application logic here
    Animal animal=new Animal();
    animal.name="Dog";
    System.out.println(animal.name);
    testIt(animal);
    System.out.println(animal.name);
}


public static void testIt(Animal animal){
    animal.name="Cat";
}

}

输出

犬 猫

这是因为两个引用(原始和方法)都在同一个对象上。

    __________
   |          |                 
   |          |<------------- Orignal Refernce 
   | Object   |   
   |          |<------------- Method Refernce
   |          |
   |__________|

如果您想更清楚地看到此效果,请在方法

中创建新对象

公共类Passbyvalue {

public static void main(String[] args) {
    Animal animal=new Animal();
    animal.name="Dog";
    System.out.println(animal.name);
    testIt(animal);
    System.out.println(animal.name);
}


public static void testIt(Animal animal){
    animal=new Animal();
    animal.name="Cat";
}

}

输出 狗 狗

现在方法引用正在灌输堆中的其他Object。

    __________
   |          |                 
   |          |
   | Orignal  |<------------- Orignal Refernce    
   | Object   |
   |          |
   |__________|



    __________
   |          |                 
   |          |
   | Method   |<------------- Method Refernce    
   | Object   |
   |          |
   |__________|

希望这会有所帮助

答案 7 :(得分:-1)

这是一个很好的写一些例子。 http://javadude.com/articles/passbyvalue.htm

这是我对这个问题的简单看法。 Java始终是一种按值传递的语言。在谈论对象时,将其视为传递参考语言会有所帮助。但这不完全正确。它正在做的是传递内存地址的值。

编辑:感谢投票。也许你应该先阅读这篇文章。因为没有人愿意冒昧地举一个例子:

public class Dog {

    public String name;

    public Dog(String name) {
        this.name = name;
    }

    public static void main(String []args) {

        Dog newDog = new Dog("Max");
        newDog.test(newDog);
        System.out.println(newDog.name);

    }

    public void test(Dog dog) {
        dog = new Dog("Gotcha");
    }

}

那么上面输出到控制台是什么?现在,如果你们尖叫传递引用是正确的,它将打印“Gotcha”,但它不打印“Max”。但是等等,这就像是按值传递行为。但为什么?因为在Java对象中没有通过引用传递。正确的陈述是对象引用按值传递。

答案 8 :(得分:-1)

讨论的重点是什么?

如果您想保护传递给其他方法的论据,请按照Thilo的评论进行操作,这就是