JAVA中的本地对象创建

时间:2013-12-29 19:09:46

标签: java object

我是java的新手,所以请和我一起玩......

我正在写一些JAVA作业,我现在在校学习了几天,我遇到了一些非常奇怪的东西(好吧,至少对我来说是......)。 由于问题与我的项目无关,我编写了一些代码,提出了我想要询问的行为,因此请忽略您在以下代码中可能遇到的与此特定问题无关的任何问题。
考虑以下课程:

package test;

import java.util.ArrayList;
import java.util.List;

public class Car {

    List<Doors> doors;
    int numOfDoors;

    public Car(int numOfDoors) {
        this.numOfDoors=numOfDoors;
    }

    public void prepare() {
        run(doors);
    }

    public void run(List<Doors> listOfDoors) {
        listOfDoors=new ArrayList<Doors>(numOfDoors);
    }

    public List<Doors> getDoors() {
        return doors;
    }
}

而且:

package test;

import java.util.List;

public class TestDrive {

    public static void main(String[] args) {

        Car car=new Car(5);
        car.prepare();
        List<Doors> listOfDoors=car.getDoors();

        if (listOfDoors==null) {
            System.out.println("This is not the desired behaviour.");
        }
        else {
            System.out.println("This is the desired behaviour.");
        }
    }
} 

我同意,这有点愚蠢而没有意义,但是再一次 - 我写这篇文章只是为了满足我的好奇心。

现在,正如您可能已经猜到的那样,输出是“这不是期望的行为。”,意思是,字段“doors”包含空指针,即使它在“run()中分配了一个新对象” “ 方法。所以我的问题是为什么?为什么它是空的?
我的意思是,我知道创建一个局部变量 - 可能是一个原始变量,一个对象或一个对象的引用 - 当我们离开方法的范围时会导致它失去它,但这不是这里的情况,因为那里是实时对新创建的对象(门)的引用,那么为什么JAVA会破坏它? 感谢所有通过并阅读整篇文章的人。

8 个答案:

答案 0 :(得分:2)

让我们一步一步地分析它。

Car car=new Car(5);
car.prepare();

您创建了一辆新车,并且在prepare之后,您希望它有一个包含5个门的列表。 现在让我们来看看prepare期间发生的事情。

public void prepare() {
    run(doors);
}

public void run(List<Doors> listOfDoors) {
    listOfDoors=new ArrayList<Doors>(numOfDoors);
}

new ArrayList被分配到 本地变量 listOfDoors。 当您编写run(doors)时,您没有将指针传递给变量doors ,正如您在C上下文中所期望的那样。您正在将null(因为doors尚未初始化)传递给run方法。

运行启动时,我们有

List<Doors> listOfDoors = null;

这是在调用时传递null引用的结果。 然后为此局部变量分配一个新列表,仅在方法终止时销毁。 如您所见,doors没有分配任何内容,导致意外行为。

要解决此问题,请删除运行方法并重写准备方法。

public void prepare() {
    doors = new ArrayList<Doors>(numOfDoors);
}

有了这个,你应该得到预期的行为。

答案 1 :(得分:0)

有两件事:

  • 传递参数作为参考

  • 将参数传递为值

在Java中,您只能将参数传递为值 - 这意味着方法run获取doors引用的副本(是的 - 它可能会令人困惑)。现在,您已获得reference doors以及此引用的副本 - listOfDoors。但它还没有提到。所以当你写

listOfDors = new ArrayList<Doors>();

现在listOfDoors引用门的arraylist,但变量doors仍然没有引用任何内容。

顺便说一句 - 如果在传递该引用的副本之前初始化了doors对象,则可以写:

listOfDoors.add(new Door());

,它与

相同
doors.add(new Door());

尽管这些是两个不同的引用,但它们会引用相同的对象。

答案 2 :(得分:0)

问题在于:

public void run(List<Doors> listOfDoors) {
    listOfDoors = new ArrayList<Doors>(numOfDoors);
}

应该是:

public void run(List<Doors> listOfDoors) {
    doors = new ArrayList<Doors>(numOfDoors);
}

了解parameter passing

答案 3 :(得分:0)

在检查传递给构造函数的门数后,您需要在Doors构造函数中初始化Car。 此外,run()需要访问this.doors而不是访问本地门(方法参数)。

答案 4 :(得分:0)

在运行中分配listOfDoors=new ArrayList<Doors>(numOfDoors);时,您不会更改doors,因为它是一个不同的参考。调用run(doors)会创建一个对doors所引用的对象的新引用,然后您将对其进行设置并且不执行任何操作(此引用在run退出时会丢失范围)。 doors引用永远不会设置为您在run中创建的对象。

答案 5 :(得分:0)

方法run可能将您现有的doors作为参数,但在函数中,参数doors会被新列表覆盖(它与不同的对象不同)含量)。

因此原始doors对象仍为null

答案 6 :(得分:0)

Java不是通过引用传递的。所以

public void run(List<Doors> listOfDoors) {
    listOfDoors=new ArrayList<Doors>(numOfDoors);
}

不更新doors中作为变量run(doors)传入的相同列表。相反,run方法会分配给新引用,因此永远不会设置变量doors

这也是通常的交换方法在java

中不起作用的原因

答案 7 :(得分:0)

你正在考虑向错误的方向进行任务,通过将门传递给doorsrun你有一个新的变量/引用,它被声明为该方法的参数,并且是本地的它,然后你初始化它,它只在方法执行时生存。变量doors保持不变。它与CC++不同,您可以在其中传递指针并为其指向的对象指定值。

你需要初始化doors,一个好的地方将在构造函数中:

public Car(int numOfDoors) {
    this.numOfDoors=numOfDoors;
    this.doors = new ArrayList<>(this.numOfDoors);
}

并且没有必要 - 至少如果您的意图是方法run对成员变量doors起作用 - 将对它的引用传递给该方法,只需写:

public void run() {
    // user this.doors here
}