面向对象的时候学了类的概念以及使用。其实在类的内部,还可以创建类,这种叫内部类。
内部类有四种:
1、成员内部类
2、局部内部类
3、静态内部类
4、匿名内部类(重点)
成员内部类。在类的内部,再创建一个类,就是成员内部类:
想要调用内部类,需要先创建外部类,通过外部类创建内部类,再去调用内部类的属性跟方法:
局部内部类,就是在类中的方法里面,再创建类,因为这个类的作用范围在方法里面,所以是局部内部类:
通过外部类调用方法即可调用。
类中再创建一个静态的类,就是静态内部类。
类比静态方法/属性,类可以直接调用,所以静态类,也可以被类直接调用:
作用:减少了类的创建,只适用于对象的方法只调用一次或者少次。
集合分为两大块:
一个是Collection,一个是Map。
迭代器(只服务于Collection以及底下的那些集合)
Collection:
List:(有序可重复)
ArrayList
LinkedList
Vector
Stack
Set:
TreeSet
HashSet
Queue:
LinkedList
Map:
TreeMap
HashMap
ArrayList 数组与之前那个数组不同,该数组当容量满了会自动扩容。且该数组储存不再需要同一类型,而是不同类型的都能存储,因为该数组存储的是对象。
ArrayList 数组与之前用过的数组使用方式不太一样。下面了解该数组的增删改查方式:
在索引1 这个位置插入 ’ f '。
这里删除用 remove 关键字,这里是删除索引为 2 处的位置。
数组里面有个 1 ,如果想要删除 1,不能直接用数字1去删,因为这里面的元素不再是属性,而是一个个对象:
再创建一个集合,并把这个集合加到前面的集合中去:
可以看到里面多了个集合,有个中括号。
ArrayList动态数组如何自动扩容呢?直接查看其源码:
下面代码注释中,红色为第一次执行,蓝色为第二次执行,绿色为第三次执行:
解释:
ArrayList 底层是动态数组,通过无参构造方法创建集合对象,第一次添加对象时,容量会扩容到10,当容量满的时候再添加对象会扩容到原来的1.5倍。
缺陷:
1、长度有限:数组哪怕可以扩容,也有其最大限制。该限制就是 int 类型的最大值。
2、当删除中间元素时,后面的所有元素都需要往前挪一位,意味着整体结构需要改变。中间增加元素也一样的。
用法跟上面的 ArrayList 数组一模一样,用 LinkedList 去替换即可。
同样的,红色是第一次执行,蓝色是第二次执行、绿色是第三次执行。
LinkedList :底层是双向链表,first属性指向第一个节点,不存在索引,理论上长度无限。
1、ArrayList 底层是动态数组,LinkedList 底层是双向链表。
2、ArrayList 查询比 LinkedList 更快。
3、如果不需要扩容,ArrayList 末尾追加比 LinkedList 更快。
4、修改对象 ArrayList 比 LinkedList 更快。
5、中间插入和中间删除不同情况效率不一致。
6、ArrayList 长度有限,LinkedList 理论上长度无限。
Vector:元老级别的集合,底层是动态数组,线程安全的集合。
了解即可
栈的特点是:用完即删,后进先出(LIFO)。
注意:此处取出数据不可用 for 循环,因为取出栈顶数据后,栈顶就变成 null ,而 for 循环时,会循环到 null 这部分,导致不能把所有元素都遍历出来。
用 for 循环和 foreach 循环遍历 ArrayList 数组,可以发现输出结果。如果查看其编译文件,就会发觉有很大不同:
foreach 循环这种遍历方式,就是迭代器。foreach 循环本质上就是调用迭代器。
既然 foreach 循环本质上是调用迭代器,那么何不自己写,自己调用呢?
其中,hashNext 指向的方向根据 next 指向的方向,意思是,next 指哪,hashNext 就指哪。
ArrayList 数组可以存不同类型的对象,如果只想让它存一种类型的呢?
可以看到,即便只想存储对象类型,后面还是可以存储其他类型,因为少了约束。
这里就需要用到泛型,因为泛型可以限制集合的类型。
可以看到,一加上,其他不是这种类型的都有红线。
为什么能够这样去使用呢?
可以看到类那里多了个尖括号,传递 User 进来,这里就会变成User。再查看 add 方法:
也是同样的。
所以,泛型就是约束了集合存储对象的数据类型。
静态方法这么写会报错,因为静态方法优先于对象加载进内存,所以这么写不行,这么写这个static 后面的 K,意味着由对象来决定返回值类型。所以这里需要自己定义类型,所以需要自己在前面加: