ByteArray是字节数组的实现,顾名思义,该数组的元素大小的一个字节,不过类似js的Uint16Array,Uint32Array数组一样,我们可以把多个元素看做一个,把多个字节合并成一个元素看待。下面我们看一下实现。
class ByteArray: public Array {
public:
// 按照一个元素一个字节的方式存取
inline byte get(int index);
inline void set(int index, byte value);
// 按照一个元素四字节方式取
inline int get_int(int index);
/*
计算长度为length的数组需要多少内存,在分配内存的时候,除了kHeaderSize,
多分配一块存储数组元素的内存
const int kObjectAlignmentBits = 2;
const int kObjectAlignmentMask = (1 << kObjectAlignmentBits) - 1;
#define OBJECT_SIZE_ALIGN(value) ((value + kObjectAlignmentMask) & ~kObjectAlignmentMask)
由此可知,按四个字节对齐。OBJECT_SIZE_ALIGN的作用的是不够4字节的,会多分配几个字节,使得按四字节对齐。~kObjectAlignmentMask是低两位是0,即按四字节对齐。比如value已经4字节对齐了,则(4 + 0 +3) & ~3 =4,如果value没有对齐,假设是5,则(4 + 1 +3) & ~3 = 8;如果value等于6,(4 + 2 + 3) & ~3 = 8;以此类推。
*/
static int SizeFor(int length) {
return kHeaderSize + OBJECT_SIZE_ALIGN(length);
}
// 元素个数
static int LengthFor(int size_in_bytes) {
ASSERT(IsAligned(size_in_bytes, kPointerSize));
ASSERT(size_in_bytes >= kHeaderSize);
return size_in_bytes - kHeaderSize;
}
// 返回数据部分的的虚拟地址,因为数据由元数据和有效数据部分组成,这里返回有效数据部分的首地址
inline Address GetDataStartAddress();
// 根据有效数据的地址address算出对象本身的首地址
static inline ByteArray* FromDataStartAddress(Address address);
// Casting.
static inline ByteArray* cast(Object* obj);
// 自己需要的内存
int ByteArraySize() { return SizeFor(length()); }
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
};
1 数据按字节存取
kCharSize表示按字节操作
byte ByteArray::get(int index) {
ASSERT(index >= 0 && index < this->length());
// 根据索引返回数组中对应元素的值,kHeaderSize是第一个元素的地址,kCharSize是1,即一个字节
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
}
void ByteArray::set(int index, byte value) {
ASSERT(index >= 0 && index < this->length());
WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
}
2 数据按四字节读取
把四个元素(四个字节)的内容作为一个值。即ByteArray变成IntArray。
int ByteArray::get_int(int index) {
ASSERT(index >= 0 && (index * kIntSize) < this->length());
return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
}
3 地址计算
kHeapObjectTag是堆对象的标记,对象是四字节对齐的,所以地址的后两位不使用,而是用于保存一些标记。
// 获取对象首地址。address是数据部分首地址
ByteArray* ByteArray::FromDataStartAddress(Address address) {
ASSERT_TAG_ALIGNED(address);
return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
}
// 获取数据部分首地址
Address ByteArray::GetDataStartAddress() {
/*
typedef uint8_t byte;
typedef byte* Address;
*/
return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
}