Java集合框架
集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
- 和数组区别:
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
Collection
Collection体系集合
Collection父接口
-
特点:代表一组任意类型的对象,无序、无下标、不能重复
-
方法:
- 添加一个对象:boolean add(Object obj)
- 将一个集合中的所有对象添加到此集合中:boolean addAll(Collection c)
- 清空此集合中的所有对象:void clear()
- 判断此集合中是否包含o对象:boolean contains(Object o)
- 比较此集合是否与指定对象相等:boolean equals(Object o)
- 判断此集合是否为空:boolean isEmpty()
- 在此集合中移除o对象:boolean remove(Object o)
- 返回此集合中的元素个数:int size()
- 将此集合转换成数组:Object[] toArray()
Collections工具类
-
概念:集合工具类,定义了除了存取意外的集合常用的方法
-
方法:
-
void reverse(List<?> list)//反转集合中元素的顺序
Collections.reverse(list);
-
void shuffle(List<?> list)//随机重置集合元素的顺序
Collections.shuffle(list);
-
void sort(List
list)//升序排列(元素类型必须实现Comparable接口) Collections.sort(list);
-
int binarySearch((List
list,Object obj) int i = Collections.binarySearch(list, 13); System.out.println(i);
-
Collection的使用
Collection元素增加
Collection collection = new ArrayList();
// (1)添加元素
collection.add("苹果");
collection.add("西瓜");
collection.add("榴莲");
System.out.println("元素个数"+collection.size());
System.out.println(collection);
Collection元素的删除
collection.remove("榴莲");
System.out.println("删除后元素个数"+collection.size());
collection.clear();
System.out.println("删除后元素个数"+collection.size());
Collection 遍历
使用增强for循环
for (Object o : collection) {
System.out.println(o);
}
使用迭代器
- 迭代器专门用来遍历集合的一种方式
- 3个方法:
- hasNext():有没有下一个元素
- next():获取下一个元素
- remove():删除当前元素
Iterator it = collection.iterator();
while(it.hasNext()){
String s = (String)it.next();
System.out.println(s);
}
- 在迭代器中不能使用collection的删除方法,会出现并发修改异常,可以使用迭代器的remove方法
Collection的判断
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
List子接口
-
特点:有序、有下标、元素可以重复
-
方法:
- 在index位置插入对象o:void add(int index,Object o)
- 讲一个集合中的元素添加到此集合中的index位置:boolean addAll(int index,Collection c)
- 返回集合中指定位置的元素:Object get(int index)
- 返回fromIndex和toIndex之间的集合元素:List subList(int fromIndex,int toIndex)
List接口的使用
- List元素的增加、删除、判断同上述Collection
List的遍历
-
其他三种遍历方法同上述Collection
-
使用列表迭代器
- ListIterator可以向前或向后遍历,添加、删除、修改元素
ListIterator list = list.listIterator(); while(list.hasNext()){ System.out.println(lit.nextIndex()+":"+lit.next());//从前往后遍历 } while(list.hasPrevios()){ System.out.println(lit.previousIndex()+":"+lit.previous());//从后往前遍历 }
List实现类
-
ArrayList【重点】:
- 数组结构实现,遍历查询快、增删慢
- 运行效率快、线程不安全
-
Vector:
- 数组结构实现,查询快、增删慢
- 运行效率慢、线程安全
-
LinkedList:
- 链表结构实现,增删快、查询慢
ArrayList【重点】
- 默认容量大小:10
- 存放元素的数组:elementData
- 实际的元素个数:size
ArrayList的使用
创建集合:
- 如果没有向集合中添加任何元素时,容量为0
ArrayList arrayList = new ArrayList<>();
添加元素:
- 添加一个元素后,容量变为10
- 再往后扩容大小为原来的1.5倍
Student s1 = new Student("刘德华",20);
Student s2 = new Student("郭富城",22);
Student s3 = new Student("吴彦祖",18);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
删除元素:
-
可以根据下标删除
arrayList.remove(0);
-
也可以通过元素删除
arrayList.remove(s1);
-
也可以通过属性删除(重写equals方法)
arrayList.remove(new Student("刘德华",20));
遍历元素【重点】:
-
使用迭代器
Iterator it = arrayList.iterator(); while(it.hasNext()){ Student s = (Student)it.next(); System.out.println(s.toString()); }
-
列表迭代器
ListIterator lit = arrayList.listIterator(); while(lit.hasNext()){ Student s = (Student)lit.next(); System.out.println(s.toString()); }
判断元素(重写equals方法)
System.out.println(arrayList.contains(new Student("刘德华",20)));
System.out.println(arrayList.isEmpty());
查找元素位置(重写equals方法)
System.out.println(arrayList.indexOf(new Student("刘德华",20)));
LinkedList
- size:集合的大小
- Node first:链表的头节点
- Node last:链表的尾节点
LinkedList的使用
创建集合:
LinkedList linkedList = new LinkedList<>();
添加元素:
Student s1 = new Student("刘德华",20);
Student s2 = new Student("郭富城",22);
Student s3 = new Student("吴彦祖",18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
删除元素:
-
可以根据下标删除
linkedList.remove(s1);
-
也可以通过元素删除
linkedList.remove(s1);
-
也可以通过属性删除(重写equals方法)
linkedList.remove(new Student("刘德华",20));
遍历元素【重点】:
-
使用for循环
for (int i = 0; i < linkedList.size(); i++) { System.out.println(linkedList.get(i)); }
-
使用增强for
for (Object o : linkedList) { Student s = (Student) o; System.out.println(s.toString()); }
-
使用迭代器
Iterator it = linkedList.iterator(); while(it.hasNext()){ Student s = (Student)it.next(); System.out.println(s.toString()); }
-
列表迭代器
ListIterator lit = linkedList.listIterator(); while(lit.hasNext()){ Student s = (Student)lit.next(); System.out.println(s.toString()); }
判断元素(重写equals方法)
System.out.println(linkedList.contains(new Student("刘德华",20)));
System.out.println(linkedList.isEmpty());
查找元素位置(重写equals方法)
System.out.println(linkedList.indexOf(new Student("刘德华",20)));
泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 好处:
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性
泛型类
-
将类变成泛型类:在类名后面加上
,类就变成了泛型类,T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开 -
不可以实例化泛型,以下是错误示范
T t1 = new T();
T表示数据类型,不能确定,不能实例化对象。
-
注意
- 泛型只能是引用类型
- 不同泛型对象之间不能相互复制
- 在实例化泛型类对象时需要说明泛型的具体数据类型
public class MyGeneric<T> {
//使用泛型
//1创建变量
T t;
//2作为方法的参数
public void show(T t){
System.out.println(t);
}
//3泛型作为方法的返回值
public T getT(){
return t;
}
}
public static void main(String[] args) {
//使用泛型类创建对象
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t = "hello";
myGeneric.show("大家好");
String s = myGeneric.getT();
System.out.println(s);
MyGeneric<Integer> myGeneric1 = new MyGeneric<Integer>();
myGeneric1.t = 100;
myGeneric1.show(200);
Integer integer = myGeneric1.getT();
System.out.println(integer);
}
泛型接口
- 将接口变成泛型接口:在接口后面加上
,接口就变成了泛型接口 - 不能使用静态泛型常量
- 在继承泛型接口的时候需要说明泛型的具体数据类型
public interface MyInterface<T>{
String name= "张三";
T server(T t);
}
public class MyInterfaceImpl implements MyInterface<String>{
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
- 或者创建泛型类继承泛型接口不需要说明泛型的具体数据类型,但是在实例化泛型类的时候需要说明泛型的具体数据类型。
泛型方法
- 语法和泛型类不同:声明泛型方法的时候将
放在返回值类型前面
public <T> void show(T t){
System.out.println("泛型方法");
}
public static void main(String[] args) {
MyGenericMethod myGenericMethod= new MyGenericMethod();
myGenericMethod.show("加油学习!");
myGenericMethod.show(20);
myGenericMethod.show(3.1415926);
}
- 方法的传入类型由传入的类型决定
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
- 特点:
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
ArrayList<Student> arrayList = new ArrayList<Student>();
Set子接口
-
特点:无序、无下表、元素不可重复
-
方法:全部继承自Collection中的方法
-
Set实现类
-
HahSet【重点】:
-
基于HashCode实现元素不重复
-
当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,啧拒绝后者存入
-
-
TreeSet:
- 基于排列顺序实现元素不重复
-
Set的使用
Set元素添加
Set<String> set = new HashSet<>();
//1添加数据
set.add("华为");
set.add("苹果");
set.add("小米");
System.out.println("数据个数"+set.size());
System.out.println(set.toString());
Set元素的删除
//2删除数据
set.remove("小米");
System.out.println("数据个数"+set.size());
System.out.println(set.toString());
Set元素的遍历
-
使用增强for遍历
//3.1增强for for (String s : set) { System.out.println(s); }
-
使用迭代器遍历
//3.2使用迭代器 Iterator<String> it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
Set元素的判断
System.out.println(set.contains("华为"));
System.out.println(set.isEmpty());
Set实现类
HashSet【重点】
- 基于HashCode计算元素存放位置:
- 如果此位置为空,则直接保存,如果不为空则执行第二步
- 再执行equals方法,如果equals方法为true,则认为是重复,否则形成链表
- 当存入元素的哈希码相同时,会调用 equals进行确认,如结果为true,则拒绝后者存入
- 所以如果要根据年龄和姓名判断两人是否相同的话,需要重写HashCode方法和equals方法
创建
HashSet<String> hashSet = new HashSet<>();
添加元素
hashSet.add("刘德华");
hashSet.add("梁朝伟");
hashSet.add("彭于晏");
hashSet.add("周润发");
System.out.println(hashSet.size());
System.out.println(hashSet.toString());
删除元素
hashSet.remove("刘德华");
System.out.println("删后"+hashSet.toString());
遍历元素
//3.1增强for
for (String s : hashSet) {
System.out.println(s);
}
//3.2使用迭代器
Iterator<String> it = hashSet.iterator();
while(it.hasNext()){
System.out.println(it.next());;
}
判断
System.out.println(hashSet.contains("郭富城"));;
System.out.println(hashSet.isEmpty());
TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素,如果返回值为0,认为是重复元素
创建
TreeSet<Person> treeSet = new TreeSet<>();
//其中Person类必须继承Comparable接口
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age-o.getAge();
return n1==0?n2:n1;
}
或者声明比较规则
TreeSet<Person> person = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1==0?n2:n1;
}
});
添加元素
treeSet.add("刘德华");
treeSet.add("梁朝伟");
treeSet.add("彭于晏");
treeSet.add("周润发");
System.out.println(treeSet.size());
System.out.println(treeSet.toString());
删除元素
treeSet.remove("刘德华");
System.out.println("删后"+treeSet.toString());
不用重写HashCode和equals方法也可以删除
treeSet.remove(new treeSet("刘德华"));
遍历元素
//3.1增强for
for (String s : treeSet) {
System.out.println(s);
}
//3.2使用迭代器
Iterator<String> it = treeSet.iterator();
while(it.hasNext()){
System.out.println(it.next());;
}
判断
System.out.println(treeSet.contains("郭富城"));;
System.out.println(treeSet.isEmpty());
Map集合
- Map接口的特点:
- 用于储存任意键值对(Key-Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
Map集合的使用
元素的添加
//创建Map集合
Map<String,String> map = new HashMap<>();
//1添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println("元素个数为"+map.size());
System.out.println(map.toString());
- 注意:如果key的值重复,则会把前面的value值覆盖掉
元素的删除
map.remove("usa");
System.out.println("元素个数为"+map.size());
元素的遍历【重点】
- entrySet效率高于keySet
使用keySet()方法
Set<String> keyset = map.keySet();
for (String s : keyset) {
System.out.println(s+":"+map.get(s));
}
- 使用keySet()方法得到key的Set集合,再用增强for循环遍历得到的Set集合,使用get方法得到key对应的value值
使用entrySet()方法
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
- 使用entrySet方法得到entrySet的包装集合,再用增强for循环遍历得到的集合。使用getKey和getValue方法分别得到key和value
元素的判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("泰国"));
判断有没有key,判断有没有value
Map集合的实现类
HashMap【重点】:
-
线程不安全,运行效率快;允许用null作为key或是value
-
初始大小为16,最大容量为1<<30
-
超过目前容量的75%开始扩容(加载因子)
-
HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table的容量调整为16
-
当元素个数大于阈值(16*0.75=12)时,扩容为原来大小的2倍,目的是为了减少调整元素的个数
-
当每个链表长度大于8时,并且数组元素个数大于等于64时,会调整为红黑树,目的提高执行效率
-
当哈希表长度小于6时,调整为链表
-
jdk1.8以前,链表插入为头插入,jdk1.8以后是尾插入
Hashtable
- 线程安全,运行效率慢;不允许null作为key或是value
- Properties为Hashtable的子类,要求key和value都是String。通常用于配置文件的读取
TreeMap
-
实现了SortedMap接口,可以对key自动排序
-
TreeMap的使用同上述Map的使用