Java用Object实现数组队列的泛思与理解
1、数组队列:能够限定只存一种数据或(不限定数据类型)同时存储多种数据的一个数组封装类
2、实现:使用泛型,创建对象时若指定数据类型,则只能存储一种数据,否则可以存储多种数据;
2.1、前者:类似于C++的(泛型程序设计)构建模板类,创建对象时指定数据类型,类模板实例化为具体的类,再生成相应的对象;
2.2、后者:java中有一个神奇的顶端父类(所有类的父亲Object),其他类都是它的子类。开辟一个Object数组,那么它就可以存储任意的其他类型的数据了;
3、疑问:但一个Object对象,就是开辟那么这么大的内存,随着继承关系的深入(继承树的枝离Object类越远),数据与方法愈加丰富,单对象的占用内存必定更大,那么如何保证能存下这个大对象;
4、理解:
4.1、数据类型:根据变量存储的不同,Java中只有基本数据类型与引用数据类型(类类型)
4.1.1、变量:当定义一个变量,该变量名是一块内存区域的标识符(别名),便于 编译器直接操作;
4.1.2、基本数据类型:如int,long,变量名中直接存储数据,直接操作数据;
4.1.3、引用数据类型:如Integer,Long,变量名中存储的是地址(类似于C++的指针), 访问时需要跳转到所指向的内存区域,是间接操作数据,如:A a=new A();
开辟 (new)一块内存,进行属性初始化(赋默认值),调用构造方法,在堆或栈内存中形成一个 对象,在便于编译器操作的内存区(应是栈区)开辟一块标识为a的内存空间,将对象 的内存地址存入;操作时,就通过标识为a的内存中的地址找到被操作对象,再进行操作;
4.2、创建数组:
4.2.1、基本数据数组:如:A[] a=new A[size]; 先开辟size个A数据的连续内存(大小由size与每个基本数据内存的字节数决定),赋默认值,再开辟一块标识为a的内存存入地址(a的使用类似于引用类型);
4.2.2、引用数据类型数组:
在C++中
开辟对象数组,均如上方式,直接创建size个连续对象(开辟了固定的空间),所以对于开辟Object数组,存数据量更大的子类数据,才会有存储不下的担忧;
在java中
Object子类对象的占用内存大小无法确定,但它们都可以初始化父类 Object的引用,而Object的引用的占用内存大小编译器知道(4字节),所以
Object[] obj = new Object [size];
就是创建了一个引用数组,长度为size,数组首地址赋给obj(类似于 C++中的指针数组)。
此时,并没有对象;
执行obj[0]=。。。。;obj[1]=。。。。;obj[2]=。。。。;
然后可以根据需要,让数组里的引用指向已存在的不同的对象(如下图的灰色箭头)
5、再疑:父类的引用只能操作子类中属于父类的部分,对于其它部分无能为力;只有强转为相应子类的引用,才能进行操作,其中是怎么实现的?安全性如何?
6、解释:假设有ExExObject extends ExObject extends Object (java中只有单继承),如下:
执行
ExExObject eeo =new ExExObject();
Object o = eeo ;
eeo中原地址为对象首地址d3,允许对整个对象进行操作;
隐含转换后,o中的地址为d1,只允许对Object部分进行操作;
已知子类对象,其中必含有父类部分,向上(向父类)转换是安全的;
如果执行
ExObject eo = (ExObject)o;
由于编译器只了解当前的情况,一个对象的引用可以说是它的标识,它被标识为什么编译器就将它当什么处理;
强制转换后就是硬是将父类对象当子类对象处理;
eo中的地址为d2,可以操作ExObject范围内的数据;
但如果它实际上并不是一个ExExObject对象,那就是强行将范围外的的数据当对象内的数据来操作,可能修改其他数据,引发运行异常;
所以强转要知道转的是什么,它是不安全的;