Java/C++中数组的差异

Java/C++中数组的区别

1. 数组名区别

--------------------------------------

1. java中不用说,本着一切皆对象的原则,所以java中的数组也是对象.那么数组类是哪个,当然不是java.util.Arrays.详见Java数组方法的思考

2. 而在c++中数组名其实是一种数据结构,有人会说不是指针吗,关于这一点见(C++中数组名其实是一种数据结构)。

从上面两点中我们可以看出java数组名是对象,而c++数组名是数据结构。那么有人又会问对象和数据结构又有什么区别呢?详见数据结构与对象的区别。


2. 原理区别

-----------------------------------

JAVA里数组的内存分配是在堆里面的,必须用new来分配,而C++里面是在栈里面分配的,定义的时候会自动分配

java中的数组

1、数组不是集合,它只能保存同种类型的多个原始类型或者对象的引用。数组保存的仅仅是对象的引用,而不是对象本身。数组声明的两种形式:一、int[] arr; 二、int arr[];  推荐使用前者,这是一个int数组对象,而不是一个int原始类型。

2、数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的

4、在数组声明中包含数组长度永远是不合法的!如:int[5] arr; 。因为,声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。

5、在数组构造的时候必须指定长度,因为JVM要知道需要在堆上分配多少空间。例:int[] arr = new int[5];

7、一维数组的构造。形如:String[] sa = new String[5];  或者分成两句:String[] sa;  sa = new String[5];

8、原始类型数组元素的默认值。对于原始类型数组,在用new构造完成而没有初始化时,JVM自动对其进行初始化。默认值:byte、short、 int、long--0  float--0.0f double--0.0  boolean--false  char--'"u0000'。(无论该数组是成员变量还是局部变量)

10、对象类型的数组虽然被默认初始化了,但是并没有调用其构造函数。(C++中则会调用)也就是说:Car[] myCar = new Car[10];只创建了一个myCar数组对象!并没有创建Car对象的任何实例!

11、多维数组的构造。float[][] ratings = new float[9][]; 第一维的长度必须给出,其余的可以不写,因为JVM只需要知道赋给变量ratings的对象的长度。

12、数组索引的范围。数组中各个元素的索引是从0开始的,到length-1。每个数组对象都有一个length属性,它保存了该数组对象的长度。(注意和String对象的length()方法区分开来)

13、Java有数组下标检查,当访问超出索引范围时,将产生ArrayIndexOutOfBoundsException运行时异常。注意,这种下标检查不是在编译时刻进行的而是在运行时!也就是说int[] arr = new int[10];  arr[100] = 100; 这么明显的错误可以通过编译,但在运行时抛出!

Java中的数组中既可以存储基本的值类型,也可以存储对象。对象数组和原始数据类型数组在使用方法上几乎是完全一致的,唯一的差别在于对象数组容纳的是引用而原始数据类型数组容纳的是具体的数值。在讨论关于数组的问题时,一定要先确定数组中存储的是基本值类型还是对象。特别是在调试程序时,要注意这方面。


3. 类数组是否调用构造函数

-------------------------------------------------

对于上面提到的第10点对象类型的数组虽然被默认初始化了,但是并没有调用其构造函数。我必须要重点解释下,因为在c++中会调用其构造函数,这里最容易搞混。

public class Test extends JPanel {
    private static final long serialVersionUID = 4767050156491994899L;
    public static void main(String[] args) {
        AnimApp[] array = new AnimApp[3]; // 没有执行构造函数, 在这里只是申请了空间.
        array[0] = new AnimApp(3); // 构造一个对象
    }
}

class AnimApp {
    public AnimApp(int times) {
        System.out.println("class AnimApp");
    }
}

看下上面这段java代码,当执行AnimApp[] array = new AnimApp[3];时并不会调用构造函数,仅仅申请了空间。构造对象的时候才会调用构造函数。

Java中,定义一个数组, new[]时, 并没有执行构造函数, 只是申请了一段内存空间, 与C++中的allocator<T>.allocate(size)(因为allocator<T>的类型在运行时确定, 所以不是指定空间的字节数, 而是用元素个数, 每个元素的大小allocator中有记录)相似. 然后在构造一个对象的时候, 即如上new AnimApp(3)时, 才真正的构造对象, 似allocator<T>.construct(param).


C++中, new[]操作符(默认的)就会去
先申请空间, 接着执行构造函数, 申请了多少个对象的空间, 执行多少次(每个对象一次), 所以想为无无参构造函数的类使用默认的new[]来定义一个数组是不行的, 这点与Java不同, 他是即申请空间, 同时也要构造对象, Java只是申请一段空间, 对于空间中的每个对象, 得自己显示的用new ClassName(param)来构造.


对于Java这种与C++不同之处的原因要归为它们之间的实现不同。


1)Java的数组不是集合,它只能保存同种类型的多个原始类型或者对象的引用。数组保存的仅仅是对象的引用,而不是对象本身。
2)数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
3)在Java中,官方推荐的声明方式是Object []array,并且不能指定长度,只有new的时候才指定长度。
4)对象类型数组中的引用被默认初始化为null。如:Object [] myobj= new Object [10]; 相当于从myobj[0]到myobj[9]都这样被自动初始化为myCar[i] = null;并没有调用构造函数。在myobj[1] = new Object的时候才调用。

至于Java为什么要选择这种方式,则是其刻意避免指针(容易犯错),符号都是引用类型。


几乎所有的程序设计语言都支持数组。在C和C++中使用数组是很危险的。因为C和C++中的数组就是内存块。如果一个程序要访问其自身内存块之外的数组,或者在数组初始化之前使用它,都会产生难以预料的后果。

     java的主要目标之一就是安全性。java确保数组会被初始化,而且不能在它的范围之外被访问。这种范围检查,是以每个数组上少量的内存开销以及运行时的下标检查为代价的。但是由此换来的安全性和效率的提高,也是值得的。

     当java创建一个数组对象时,实际上就是创建了一个引用数组,并且每个引用都会被自动初始化一个特殊值。该值拥有自己的关键字null,一旦java看见了null,就知道这个引用还没有指向某个对象。如果使用某个指向null的引用,就会在运行时报错。