集合框架的特征
- 集合框架均来自于包 Java.util.*
- 集合与数组的区别是数组可以存储基本数据类型与引用数据类型,而集合只可以存储引用数据类型
集合框架的体系
List接口以及其子类的特点为
- 有序
- 有下标
- 元素可重复
Set接口以及其子类的特点为
- 无序
- 无下标
- 元素不可重复
Collection公共方法
Java不提供任何Collection的直接子类实现,但所有继承实现Collection的接口或方法均实现以下方法。
- boolean add(Object obj)//添加一个对象
- boolean add(Collection c)//添加一个集合中的所有对象到此集合中
- void clear()//清空该集合
- boolean contains(Object o)检查集合中是否包含o对象
- boolean equals(Object 0)判断该对象是否与制定对象相等
- boolean isEmpty()//判断此集合是否为空
- boolean remove(Object o )//在此集合中移除o对象
- int size()//返回此集合中的元素个数
- Object[] toArray()//将刺激和转换成数组
List接口
List接口除了实现了Collection的公共方法之外,还新增了四个特有的方法
- void add(int index,Object o)//在index位置插入对象o
- boolean addAll(int index ,Collection c)
- //从index处添加集合c中的所有元素
- Object get(int index)
- //获取集合中下标为index的元素
- List subList(int fromIndex,int toIndex)
//截取fromIndex和toIndex之间的集合元素
List的两个直接实现子类
- ArrayList,其底层数据结构是数组,所以特点是查询快,增删慢
- LinkList,其底层数据结构是链表,所以特点是增删快,查询慢
List的遍历方式
由于List中的元素有下标有顺序,所以有三种遍历方式
- for循环
- foreach(增强for循环)
- iterator(迭代器)
下面举一个遍历的Demo
package com.design;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class listdemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张三");//直接添加
list.add(1,"李四");//add的重载,根据下标添加
list.addAll(2,list);//将集合中所有元素复制并添加进原集合
//集合准备完毕
System.out.println("********第一种遍历方式通过下标遍历********");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("********第二种遍历方式通过增强for********");
for (String str:
list) {
System.out.println(str);
}
System.out.println("********第三种遍历方式通过迭代器********");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext())
{
System.out.println(iterator.next());
}
}
}
注意,iterator迭代的过程中,不可以改变集合的长度,否则会抛出异常
ArrayList源码分析
private static final int DEFAULT_CAPACITY = 10;
transient Object[] elementData; // non-private to simplify nested class access
private int size;
打开ArrayList源码我们可以发现
- ArrayList默认容量是10
- 用来存储的是一个Object数组,数组大小用整形变量size存储
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
grow方法为源代码中的核心
- 我们先取原容量为数组长度,并将讲原容量的3/2的值作为新容量。
- 如果新容量比最小容量要小,就把最小容量作为新容量
- 如果新容量比最大容量要大就调用hugeCapacity方法对minCapacity的值进行修改,最大可达到整形变量的MAX_VALUE,并赋值为新变量
- 最后调用Arrays的copyof方法对原数组进行扩容,扩容后的大小为新容量
LinkList特有方法
由于LinkList底层代码由链表实现,所以他自然具有链表所特有的方法和特点
- addFirst,addLast在头(尾)部增加元素
- getFirst,getLast在头(尾)部获取元素
- removeFirst,getLast在头(尾)部删除元素
也就是所谓的增查删操作,只是由于链表的头部及尾部操作的效率最高,因此有这几个LinkList的特有方法。
以上便是List两个子类LinkList以及ArrayList的介绍
泛型
泛型是JDK5.0引入的,其目的在于提高代码的重用性,防止转化异常,提高代码安全性
常用的泛型有泛型类,泛型接口,泛型方法。
表达形式是<T,…>T为类型占位符,表示一种引用类型
泛型类
package com.design;
public class Demo {
public static void main(String[] args) {
Test<String> t1 = new Test<>();
t1.t = "小玉";
t1.show();
String t = t1.getT();
Test<Integer> t2 = new Test<>();
t2.t = 100;
t2.show();
Integer t3 = t2.getT();
}
}
class Test<T>
{
//1通过泛型创建变量
T t;
//2操作泛型变量
void show()
{
System.out.println(t);
}
//3泛型作为返回值
T getT()
{
return t;
}
}
在泛型类中我们可以
- 创建泛型变量
- 操作泛型变量
- 返回泛型变量
要注意一点的是泛型由于其类型不能确定,所以不能使用new T()的方式进行创建!!!
泛型接口
package com.design;
class DemoImpl<String> implements Demo<String> {
@Override
public String func(String string) {
return null;
}
}
class DemoImpl2<T> implements Demo<T>
{
@Override
public T func(T t) {
return null;
}
}
interface Demo<T>{
T func(T t);
}
值得注意的是在实现接口时,如果指明了接口的泛型为具体的某一种类型,则其实现子类必须也为此泛型。若接口的泛型不指明定,则其实现类也不能指明。
在集合中使用泛型可以在编译时即检查类型是否存在错误而不用等到运行时再检查。