在Java中创建一个对象数组

219

我是Java的新手,最近创建了一个对象数组。

举个例子,我有一个名为A的类 -

A[] arr = new A[4];

但是这只创建了指向 A 的指针(引用),并没有 4 个对象。这样做正确吗?当我尝试访问创建的对象中的函数/变量时,会出现空指针异常。为了能够操作/访问对象,我不得不这样做:

A[] arr = new A[4];
for (int i = 0; i < 4; i++) {
    arr[i] = new A();
}

这是否正确,还是我做错了什么?如果这是正确的,那么它真的很奇怪。

编辑:我认为这很奇怪,因为在C++中,你只需说new A[4],它就会创建四个对象。


18
我只想说这是一个异常有帮助的问题,感谢您提问。 - pandorym
9个回答

281

这是正确的。

A[] a = new A[4];

...创建了4个A的引用,类似于执行以下操作:

A a1;
A a2;
A a3;
A a4;

现在你无法像这样调用a1.someMethod()而不分配a1

a1 = new A();

同样地,对于数组你需要这样做:

a[0] = new A();

在使用之前,请先对其进行处理。


11
这个答案让我少了很多困惑,感谢它的存在。 - pandorym
1
我也曾经有这个困惑,因为我来自C++背景,我一直认为像在C++中一样,Java的new关键字也会调用构造函数并分配内存。我猜在Java中,new只是创建引用而不是实际对象,与C++相比。感谢您的答案。 - Krishna Oza
1
@Krishna_Oza,这里和C++没有任何区别。第一个new创建了一个数组对象。这些是动态分配的对象("堆")。所以相应的C++代码将是 A **a = new A*[4]; for (int i = 0; i < 4; ++i) { a[i] = new A(); } - Vsevolod Golovanov
1
我知道new会创建引用,但为什么不像C++一样初始化数组的每个元素的构造函数呢?这可能很傻,但我想问一下,如果我们这样做会有什么问题吗?@MeBigFatGuy - Jasser
3
@Jasser - 你会调用哪个元素的构造函数?如果唯一的元素构造函数需要传入很多参数,你该如何创建这些对象? - MeBigFatGuy

87

这是正确的。你也可以做:

A[] a = new A[] { new A("args"), new A("other args"), .. };

这种语法也可以用于在任何地方创建和初始化数组,比如在方法参数中:

someMethod( new A[] { new A("args"), new A("other args"), . . } )

39

是的,它只会创建引用,并将其设置为默认值null。这就是为什么您会得到NullPointerException。您需要单独创建对象并分配引用。在Java中创建数组有3个步骤:

Declaration – In this step, we specify the data type and the dimensions of the array that we are going to create. But remember, we don't mention the sizes of dimensions yet. They are left empty.

Instantiation – In this step, we create the array, or allocate memory for the array, using the new keyword. It is in this step that we mention the sizes of the array dimensions.

Initialization – The array is always initialized to the data type’s default value. But we can make our own initializations.

Declaring Arrays In Java

This is how we declare a one-dimensional array in Java –

int[] array;
int array[];

Oracle recommends that you use the former syntax for declaring arrays. Here are some other examples of legal declarations –

// One Dimensional Arrays
int[] intArray;             // Good
double[] doubleArray;

// One Dimensional Arrays
byte byteArray[];           // Ugly!
long longArray[];

// Two Dimensional Arrays
int[][] int2DArray;         // Good
double[][] double2DArray;

// Two Dimensional Arrays
byte[] byte2DArray[];       // Ugly
long[] long2DArray[];

And these are some examples of illegal declarations –

int[5] intArray;       // Don't mention size!
double{} doubleArray;  // Square Brackets please!

Instantiation

This is how we “instantiate”, or allocate memory for an array –

int[] array = new int[5];

When the JVM encounters the new keyword, it understands that it must allocate memory for something. And by specifying int[5], we mean that we want an array of ints, of size 5. So, the JVM creates the memory and assigns the reference of the newly allocated memory to array which a “reference” of type int[]

Initialization

Using a Loop – Using a for loop to initialize elements of an array is the most common way to get the array going. There’s no need to run a for loop if you are going to assign the default value itself, because JVM does it for you.

All in One..! – We can Declare, Instantiate and Initialize our array in one go. Here’s the syntax –

int[] arr = {1, 2, 3, 4, 5};

Here, we don’t mention the size, because JVM can see that we are giving 5 values.

因此,在我们实例化之前,这些引用将保持为空。希望我的答案能帮到你..! :)
来源 - Java中的数组

6

您是正确的。除此之外,如果我们想要创建一个由某个“工厂”提供元素填充的特定大小的数组,自Java 8以来(引入了流API),我们可以使用这个一行代码:

A[] a = Stream.generate(() -> new A()).limit(4).toArray(A[]::new);
  • Stream.generate(() -> new A()) 类似于工厂,用lambda表达式描述了每个新的A实例应该如何创建,即() -> new A()Supplier<A>的实现。
  • limit(4) 设置流将要生成的元素数量。
  • toArray(A[]::new)(也可以重写为toArray(size -> new A[size]))- 它让我们决定/描述应该返回哪种类型的数组。

对于一些原始类型,你可以使用DoubleStreamIntStreamLongStream,它们还提供了像rangerangeClosed等几个生成器。


5
这是一个创建包含10个员工对象的数组的明确示例,构造函数带有参数:
public class MainClass
{  
    public static void main(String args[])
    {
        System.out.println("Hello, World!");
        //step1 : first create array of 10 elements that holds object addresses.
        Emp[] employees = new Emp[10];
        //step2 : now create objects in a loop.
        for(int i=0; i<employees.length; i++){
            employees[i] = new Emp(i+1);//this will call constructor.
        }
    }
}

class Emp{
    int eno;
    public Emp(int no){
        eno = no;
        System.out.println("emp constructor called..eno is.."+eno);
    }
}

1
声明一个新的Java数组的一般形式如下:

type arrayName[] = new type[numberOfElements];

其中,type是原始类型或对象。numberOfElements是您将存储到数组中的元素数量,这个值不能更改,因为Java不支持动态数组(如果您需要一个灵活和动态的结构来保存对象,则可以使用一些Java集合)。让我们初始化一个数组,以存储5人小公司所有员工的薪水:

int salaries[] = new int[5];

数组的类型(在本例中为int)适用于数组中的所有值。您不能在一个数组中混合类型。 现在,我们有了初始化的薪水数组,我们想把一些值放进去。我们可以在初始化期间这样做:

int salaries[] = {50000, 75340, 110500, 98270, 39400};

或者稍后这样做:
salaries[0] = 50000;
salaries[1] = 75340;
salaries[2] = 110500;
salaries[3] = 98270;
salaries[4] = 39400;

数组创建的更多视觉示例: 在此输入图片描述

了解更多有关数组的信息,请查看指南


0

对于通用类,需要创建一个包装器类。例如:

Set<String>[] sets = new HashSet<>[10]

结果为:"无法创建泛型数组"

请改用:

        class SetOfS{public Set<String> set = new HashSet<>();}
        SetOfS[] sets = new SetOfS[10];  

这行代码的意思是,您是否正在尝试创建一个由Set组成的数组,其中Set类型为String? - sofs1

0

是的,在Java中制作对象数组有几个步骤:

  1. 声明一个数组并进行实例化(创建存储“4”个对象的内存):

    A[] arr = new A[4];
    
  2. 初始化对象(在这种情况下,您可以初始化类A的4个对象)

    arr[0] = new A();
    arr[1] = new A();
    arr[2] = new A();
    arr[3] = new A();
    

    或者

    for (int i = 0; i<4; i++)
       arr[i] = new A();
    

现在你可以从刚刚创建的对象中开始调用已有的方法等。

例如:

  int x = arr[1].getNumber();

或者

  arr[1].setNumber(x);

0

假设类A是这样的:

class A{
int rollno;
int DOB;
}        

而且你想创建类A对象的数组。所以你可以这样做,

    A[] arr = new A[4];    //Statement 1
    for (int i = 0; i < 4; i++) {
    arr[i] = new A();      //Statement 2
    }

这是绝对正确的。

在语句1中,A是一个类,并且A类是数组的数据类型。当执行此语句时,由于new关键字,将创建一个对象并为其动态分配内存,该内存将等于4个数据类型A块所需的空间,即(对于数组中的一个块,所需的空间为8字节(4 + 4),我假设int占用4字节的空间。因此,为数组分配了4 * 4字节的总空间)。 然后将对象的引用赋给arr变量。这里需要注意的重要一点是,语句1与创建A类的对象无关,不会为此类创建任何对象,它仅用作数据类型,以便为数组的内存分配提供所需的类A的大小。

然后,当运行for循环并执行语句2时,JVM现在为Class A分配内存(即创建一个对象)并将其引用赋给arr [i]。每次调用循环时都会创建一个对象,并将其引用赋给arr [i]。

因此,arr [0] 占用了 8 字节的空间,并被赋予了类 A 的对象的引用。每次循环运行时都会创建一个新的对象,并将引用赋给该对象,以便它现在可以访问该对象中的数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接