调用函数并将对象作为参数传递给它时JAVA的行为是什么?

khic 发布于 4 天前 最后更新 4 天前 0 浏览

下面是我在JAVA中几乎没有疑问的代码,没有通过引用或通过地址传递。那么为什么调用方法后输出会发生变化?还想知道方法调用后JAVA的内部机制?

class Language
{
    String languageID;
    String name;
public Language(){}
public Language(String id, String name)
    {
        this.languageID = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Language id-->" + languageID + " Name-->" + name;
    }
}
public class SwapDemo {
    public static void swap()
    {
        int a = 10, b= 5;
        System.out.println("Before Swap : "+a+" "+b);
        a = a+b;
        b = a-b;
        a = a-b;
        System.out.println("After Swap : "+a+" "+b);
        a = a^b;
        b = a^b;
        a = a^b;
        System.out.println("After Swap : "+a+" "+b);
    }
public static void swap(Language e1, Language e2)
    {
        Language temp = new Language();
        temp = e1;
        e1 = e2;
        e2 = temp;
    }
public static Language method(Language addit)
    {
        addit.name = "C++";
        addit = new Language();
        addit.name = "Harshal";
        return addit;
    }
public static void main(String[] args) {
        Language l1 = new Language("1", "C");
        Language l2 = new Language("2", "Java");
System.out.println("Before swap of employees");
        System.out.println("Language 1-----> "+l1.toString());
        System.out.println("Language 2-----> "+l2.toString());
swap(l1, l2);
        System.out.println("After swap of employees");
        System.out.println("Language 1-----> "+l1.toString());
        System.out.println("Language 2-----> "+l2.toString());
Language t = method(l1);
        System.out.println("Changing "+ l1.name);
        System.out.println("Changing "+ t.name);
    }
}
已邀请:

lquia

赞同来自:

这个问题的前提是有缺陷的。你不能在Java中“传递一个对象”。 Java中唯一的类型是基本类型和引用类型,因此唯一的值是基元和引用。 “对象”不是值,也不能传递。只能通过指向它们的引用来操纵对象。在您的代码中,l1l2等是引用。

jiusto

赞同来自:

Figure 我正在解释以下几行,这将清除你的怀疑。我假设你对Heap和Stack有一点了解。
        Language t = method(l1);
        System.out.println("Changing "+ l1.name);
        System.out.println("Changing "+ t.name);
在这里,当您将“l1”对象传递给方法时,您将REFERENCE传递给该对象。 REFERENCE是一种用于在HEAP SPACE中识别对象的句柄。 考虑,
A a =new A();
这将包含什么?显然有些地址指向新创建的对象。 因此,当您将OBJECT传递给方法时,您将向对象所在的内存位置传递引用。但是如果你尝试将对象更改为某个其他对象,如在swap(l1,l2)方法中所做的那样内部方法,那么它将失败,因为你正在改变地址的值,而不是实际的对象。 因此,语句addit.name =“C++”将更改驻留在addit指向的内存位置的对象的内容。因此这里原始对象已被修改。希望这能清除你的第一个怀疑。 关于你的第二个疑问,一个对象就是生活在它的范围内。一旦方法调用完成,该方法中分配的所有变量都有资格被垃圾收集。但是在这里你正在做什么,你将从方法返回对象的引用。因此,对象不会被垃圾收集,因为它具有指向它的有效引用。因此,在第二个输出中,它会打印新值。希望这有助于理解输出。

vomnis

赞同来自:

Java是按值传递的。它将引用的副本传递给方法。所以这意味着:

List<String> l = new ArrayList<String>();
someMethod(l);
有些方法刚刚传递了l的副本 - 它是对堆上的ArrayList的引用。
public void someMethod(List<String> aList) {
    aList.add("Foo");
}
someMethod可以向该列表添加内容,因为本地引用aList指向调用者范围中与“l”相同的对象。但请注意:
public void someMethod(List<String> aList) {
    aList = new LinkedList<String>();
}
对调用者没有任何影响,所有这一切都使得本地可变“aList”指向堆上的不同对象。请记住,aList是我们称之为方法的引用的副本,因此它们都引用了相同的堆对象,在重新分配之后它们不再这样做。