ArraryList学习(一)
ArraryList 特性
- ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长。
**数组:**下标查询,连续内存,存储相同类型元素,长度确定后不可改变,每一个元素占用相同的内存大小
查询公式:get(i)->内存起始位置+(i)*单个元素内存大小
时间复杂度:o(1)
- ArrayList不是线程安全的, ArrayList实现了Serializable接口,因此它支持序列化。
- 实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问。
- 实现了Cloneable接口,能被克隆
继承了AbstractList,实现了三个标记接口 RandomAccess, Cloneable, java.io.Serializable
*标记接口:标记是否具有某种特性
继承类
AbstractList : 继承了AbstractList ,说明它是一个列表,拥有相应的增,删,查,改等功能。提供ArraryList的操作方法,其中部分抽象类方法子类实现
实现接口
- **RandomAccess:**该实现类支持随机访问(下标访问),使用get(i)方法时,通过instanseof(RandomAccess)判断底层for/迭代器
- **Cloneable:**克隆
- **浅拷贝:**拷贝的都是栈里面的东西,跟参数传值类似
int a=0;
User user=null;
String str="ggg"
f(int a,User user,String str)
{
a=1;
user=new User();
user.setId(1)
str="zzz"
}
java的传参,基本类型和引用类型传参
java在方法传递参数时,是将变量复制一份,然后传入方法体去执行。复制的是栈中的内容
所以基本类型是复制的变量名和值,值变了不影响源变量
引用类型复制的是变量名和值(引用地址),对象变了,会影响源变量(引用地址是一样的)
String:是不可变对象,重新赋值时,会在常量表新生成字符串(如果已有,直接取他的引用地址),将新字符串的引用地址赋值给栈中的新变量,因此源变量不会受影响
此时内存模型图
基础类型的变量拷贝之后是独立的,不会随着源变量变动而变
String类型拷贝之后也是独立的
引用类型拷贝的是引用地址,拷贝前后的变量引用同一个堆中的对象
public Object clone() throws CloneNotSupportedException {
Study s = (Study) super.clone();
return s;
}
-
深拷贝:
变量的所有引用类型变量(除了String)都需要实现Cloneable(数组可以直接调用clone方法),clone方法中,引用类型需要各自调用clone,重新赋值
public Object clone() throws CloneNotSupportedException {
Study s = (Study) super.clone();
s.setScore(this.score.clone());
return s;
}
完全隔离开来,就必须使用深拷贝
- **Serializable:**将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据,在Java中的这个Serializable接口其实是给jvm看的,通知jvm,我不对这个类做序列化了,你(jvm)帮我序列化就好了。如果我们没有自己声明一个serialVersionUID变量,接口会默认生成一个serialVersionUID,默认的serialVersinUID对于class的细节非常敏感,反序列化时可能会导致InvalidClassException这个异常(每次序列化都会重新计算该值)
- 序列化:转成二进制(网络传输/存盘)
- 反序列化:将二进制文件读取成对象到内存中(读取网络传输的流和读盘),反序列化会检查serialVersionUID,如果不指定版本号,类在不同jvm虚拟机,序列化和反序列化版本号不一致,反序列化会出现问题
序列版本号的作用
在 序列化存储/反序列化读取 或者是 序列化传输/反序列化接收 时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常
扩容:将老数组copy一份到新数组,且elementData指向新的数组(新容量)