ArrayList(List接口的实现类)
ArrayList注意事项
- 可以存储空值,但是遍历会出错
- ArrayList存储数据底层由数组来实现
- ArrayList基本等同于Vector,但是ArrayList是线程不安全的,多线程不建议使用
1 | import java.util.ArrayList; |
ArrayList的底层结构和源码分析
无参构造器的扩容
首先我们运行以下代码
1 | import java.util.ArrayList; |
但我们调用无参构造器时,调用了以下方法,并且定义的类型为Object[]数组类型,我们可以确认ArrayList的底层使用的是数组存储
我们可以看到在运行到add方法时,进入到了一个boolean的方法,此方法先决定是否要进行扩容,而add方法的第一行的函数如下一张图
首先判断该存储的数组是否为空,如果为空,则进行比较,并且选取两个数的一个最大数作为初始集合的大小,应该为10。而该方法的最后一行的代码,则是确定是否还进行底层扩容,大于minCapacity则进行扩容。
当我们决定扩容时,则调用下面的函数,扩容为原来的1.5倍,而copyof方法会保持地址不变,直接增加数。
当我们运行之后
15个空间不够时,我们许需要扩容,扩容之后
其实在这个过程中进行扩容这么大,是因为在这个arraylist添加和删除的过程中,成本比较大,每一次添加个删除都要不可避免的移动元素,保证空间的连续性,每一次大小变为原来的两倍,避免不得不再一次改变容量
有参构造器
有参构造器,我们可以给他附上初始值,而每一次扩容依然是原来的1.5倍,运行的原理和上面的一样,只是初始值为我们赋值的那个数,而不是10.
System类
System常见的方法和案例解析
- 退出当前程序EXIT,0表示正常状态退出
- 获取当前的时间
- 拷贝,数组拷贝底层用此代码
1 | package Learn; |
包装类
针对8中基本数据类型相应的引用类型——包装类,有了类的特点,就可以调用类中的方法是
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Interger |
long | Long |
float | Float |
double | Double |
- 案例展示
int与Interger之间的转换,jdk5之前采用手动装箱与拆箱,其中装箱:基本数据类型——>包装类型,相反的则为拆箱。而jdk5之后采用自动装箱与拆箱的方法。自动装箱底层掉哦用的valueof()方法,比如Interger.valueOf()。
1 | package Learn; |
- 练习
结果为1.0,其中三元运算符为一个整体,所以最终要进行类型提升,最终的输出类型为double类型。
1 | package Learn; |
- 包装类型与String类型的转换
1 | package Learn; |
- 常用的方法
1 | package Learn; |
- 练习
1 | package Learn; |
但是注意只要存在基本数据类型,==就是判断的值是否相等,就不要去管对象的事情了。
日期类
第一代日期类
Date:精确到毫秒i,代表特定的瞬间
SimpleDateFormate:格式和解析日期的类
1 | package Learn; |
第二代日期类
Calendar日历类,是一种抽象类,构造器私有化,通过getInstance得到实例
1 | package Learn; |
第三代日期类
jdk8之后存在
- LocalDate(只有年月日)
- LocalTime(只有时间)
- LocalDateTime(日期+时间)
- DateTimeFormat格式化日期类
- Instant 时间戳
- 除了上述之外还增加了是否闰年,增加时间等等方法
1 | package Learn; |
BigInteger和BigDecimal
BigInteger和BigDecimal
- BigInteger适合保存比较大的整型(同时他的也就只能专用的加减乘除来操作,而且也是这个类型)
- BigDecimal适合保存精度更高的浮点型(小数)
1 | package Learn; |
应用
在实际应用中double类型进行相加减,会存在精度的问题,比如
此时我们就需要运行BigDecimal来进行运算
1 | private Double xj; |
Arrays类
Arrays常见方法案例与解析
toString源码
1 | public static String toString(int[] a) { |
使用tostring与不使用的区别
1 | package Learn; |
首先我们排序的对象为数组,数组在堆中存储,我们排序之后就会影响到其中的实参,位置不变,储存的顺序改变
1 | package Learn; |
sort方法是重载的,也可以传入一个接口Comparadetor,要求实现compare方法,从而改变排序的规则,在这里debug中,我们可以发现其中会进入到二分排序方法中(如下),而二分排序中0与1会影响到最终的排序结果。
1 | private static <T> void binarySort(T[] a, int lo, int hi, int start, |
1 | package Learn; |
通过二分搜索查找,要求必须排好序(而且是正序),如果没有找到,则返回-(low+1),low表示查找的目标应该在的位置。注意有时候二分查找法不一定找出第一个数。
1 | package Learn; |
当范围不超出时,进行正常的赋值,当大于时,则用null来代替
1 | package Learn; |
1 | package Learn; |
也是包含顺序的
1 | package Learn; |
1 | package Learn; |
练习:按照书的价格大小顺序输出
1 | package Learn; |
Java中Type类
Java中Type
Type时Java语言中所有类型的公共高级接口,也就是Java中所有类型的“爹”;其中所有的类型并不是我们经常使用的int,String等类型,而是对基本数据类型,引用类型向上的抽象。
Type体系中的类型包括:原始类型(Class)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)、类型变量(TypeVariable)、基本类型(Class);
原始类型,不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
参数化类型,就是我们平常所用到的泛型List、Map;
数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;
基本类型,也就是我们所说的java的基本类型,即int,float,double等
ParameterizedType
分别为获得实际的类型,获得前面的类型,这个类型是否某个类型所属,获得这个所有者的类型,否则返回null
参数泛型化,即泛型;例如List
1 | package com.zss.test; |
getActualTypeArguments
当我们包含有多个泛型的时候,会返回一个数组用来保存这些数组
1 | public class Test<T> implements Type { |
getRawType
获取声明泛型或者接口,就是泛型中<>前面的值
1 | Type types= parameterizedType.getRawType(); |
getOwnerType
获得内部类的拥有者
1 | public class Test<T> implements Type { |
GenericArrayType
泛型数组类型List
1 | public class Test<T> implements Type { |
getGenericComponentType
返回数组中元素的Type类型,即去除数组之后的
1 | public class Test<T> implements Type { |
TypeVariable
指List
1 | public class Test<T> implements Type { |
当然还有别的方法进行调整
在TypeVariable接口中,有3个方法,分别为getBounds()、getGenericDeclaration()、getName();
Class
Type接口的实现类,是我们工作中常用到的一个对象;在Java中,每个.class文件在程序运行期间,都对应着一个Class对象,这个对象保存有这个类的全部信息;因此,Class对象也称之为Java反射的基础;
1 | public class Test<T> implements Type { |
1 | package com.zss.test; |
Java中枚举类
我们现在需要一个枚举出四季以及他们各自的特点,四季只有春夏秋冬这四个季节,而且特点固定,所以我们不需要用户去创建新的季节对象。
自定义枚举
1 | package Learn; |
- 不需要提供set方法,因为枚举对象值通常为只读。
- 对枚举对象属性使用final+static共同修饰,实现底层优化
- 枚举对象属于常量,通常全部大写
enum关键字枚举
将定义的常量对象定义在最前面
1 | package Learn; |
注意事项:
当我们使用enum关键字时,默认会继承enum类,我们反编译一下文件,可以发现同时也是final类型
如果使用无参构造器,则实参列表与小括号都可以省略。例如下面的OTHER
- 这个也是正确的,默认调用的无参构造器。
枚举中常用的方法
上面我们说到,enum其实是继承了ENUM类的,所以也会继承其方法
方法名 | 作用 |
---|---|
name | 输出对象的名字 |
ordinal | 输出该对象在枚举中的位置(从0开始) |
hascode | 输出对应的对象地址编号 |
value | 将枚举填入数组中 |
valueof | 到对应的对象中去寻找,如果找到了,返回该对象,否则为false |
compareTo | 比较两个对象的枚举编号,是他们顺序号的差值,可以crtl+B查看源码 |
1 | package Learn; |
练习:输出每一周的星期
1 | package Learn; |
注意:
如果我们使用enum关键字之后,就不可以继承其他类了,Java是单继承机制。但是实质上enum还是一个类,所以可以继承实现接口。