集合框架
什么是集合
概念:对象的容器,定义了对多个对象进行操作的常用方法。可以实现数组的功能
和数组的区别:
- 数组的长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
Collection体系集合
如图所示:
Collection:该体系结构的跟接口,代表一组对象,称为“集合”
List接口特点:有序,有下标,元素可重复
Set接口特点:无序,无下标,元素不可重复
Collection父接口
特点:代表一组任意类型的对象,无序,无下标,不能重复
方法:
boolean add (Object obj) // 添加一个对象
boolean addAll (Collection c) // 将一个集合中的所有对象添加到此集合中
void clear () // 清空此集合中的所有对象
boolean contains (Object o) // 检查此集合中是否包含o对象
boolean equals (Object o) // 比较此集合是否与指定对象相等
boolean isEmpty () // 判断此集合是否为空
boolean remove (Object o) // 在此集合中移除o对象
int size () // 返回此集合中的元素个数
Object [ ] toArray () // 将此集合转换成数组
下面是保存字符串的代码验证:
package com.collection.Demo01; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Demo01 { public static void main(String[] args) { // 创建集合 // 一、 保存字符串 Collection collection = new ArrayList(); // 1. 添加元素 collection.add("苹果"); collection.add("西瓜"); collection.add("榴莲"); System.out.println("添加之后的元素个数:" + collection.size()); // 添加之后的元素个数:3 System.out.println(collection); // [苹果, 西瓜, 榴莲] // 2. 删除元素 // collection.remove("榴莲"); // collection.remove("西瓜"); // System.out.println("删除之后剩余的元素个数:"+ collection.size()); // 删除之后剩余的元素个数:1 // 2.1 清空元素 // collection.clear(); // System.out.println("清空元素剩余:" + collection.size()); // 清空元素剩余:0 // 3. 遍历元素 // 3.1 使用增强for System.out.println("----------3.1 使用增强for-------------"); for (Object obj:collection ) { System.out.println(obj); } /* ----------3.1 使用增强for------------- 苹果 西瓜 榴莲 */ // 3.2 使用迭代器(迭代器是专门用来遍历集合的一种方式) // hasNext(); 有没有下一个元素 // next(); 获取下一个元素 // remove(); 删除当前元素 System.out.println("----------3.2 使用迭代器-------------"); Iterator it = collection.iterator(); while(it.hasNext()){ String s = (String)it.next(); System.out.println(s); // 不能使用collection删除方法 // collection.remove(s); // ConcurrentModificationException 并发修改异常 // it.remove(); // 迭代器提供的方法 } System.out.println("剩余的元素个数: "+ collection.size()); /* ----------3.2 使用迭代器------------- 苹果 西瓜 榴莲 剩余的元素个数: 3 */ // 4. 判断 System.out.println(collection.contains("xigua")); // false System.out.println(collection.contains("西瓜")); // true System.out.println(collection.isEmpty()); // false 判断是否为空// null空 为 true ; not null非空 为 false } }
下面是保存学生信息的代码实现:
学生类 Student:
package com.collection.Demo01;
/**
* 学生类
*/
public class Student {
private String name ;
private int age ;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override // 重写方法
public String toString() {
return "学生信息:[name=" + name + ",age="+age + "]";
}
@Override // 重写方法
public boolean equals(Object obj) {
// 1 判断是不是同一个对象
if (this==obj){
return true;
}
// 2 判断是否为空
if (obj==null){
return false;
}
// 3 判断是否是Student类型
if(obj instanceof Student){
Student s = (Student) obj;
// 4 比较属性
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
// 5 不满足条件返回false
return false;
}
}
代码验证:
package com.collection.Demo01;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
// 新建 Collection 对象
Collection collection = new ArrayList();
Student s1 = new Student("张三",18);
Student s2 = new Student("李四",17);
Student s3 = new Student("王五",19);
// 1. 添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println("元素个数:" + collection.size()); // 元素个数:3
System.out.println(collection); // [学生信息:[name=张三,age=18], 学生信息:[name=李四,age=17], 学生信息:[name=王五,age=19]]
// 2. 删除数据
// collection.remove(s2);
// collection.remove(new Student("王五",19)); // 并没有删除
// collection.clear();
// System.out.println("删除之后的剩余元素:" + collection.size()); // 删除之后的剩余元素:0 // 只是删掉了地址
// 3. 遍历
// 3.1 增强for
System.out.println("--------增强for------");
for (Object obj:collection) {
Student s = (Student) obj;
System.out.println(s.toString());
}
/*
--------增强for------
学生信息:[name=张三,age=18]
学生信息:[name=李四,age=17]
学生信息:[name=王五,age=19]
*/
// 3.2 迭代器
// hasNext(); next(); remove(); 迭代过程中不能使用collection的删除方法
System.out.println("--------迭代器------");
Iterator it = collection.iterator();
while (it.hasNext()){
Student s = (Student)it.next();
System.out.println(s);
}
/*
--------迭代器------
学生信息:[name=张三,age=18]
学生信息:[name=李四,age=17]
学生信息:[name=王五,age=19]
*/
// 4. 判断
System.out.println(collection.contains(s1)); // true
System.out.println(collection.isEmpty()); // false
}
}
List子接口
特点:有序,有下标,元素可以重复
方法:
- void add (int index,Object o) // 在index位置插入对象
- boolean addAll (int index,Collection c) 将一个集合中的元素添加到此集合中的index 位置
- Object get (int index) // 返回集合中指定位置的元素
- List subList (int fromIndex,int toIndex) // 返回fromIndex和toIndex之间的集合元素
下面是字符串案例:
package com.collection.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Demo01 {
public static void main(String[] args) {
// 先创建集合对象
List list = new ArrayList();
// 1. 添加元素
list.add("小米");
list.add("华为");
list.add(0,"苹果");
System.out.println("元素个数:" + list.size()); // 元素个数:3
System.out.println(list.toString()); // [苹果, 小米, 华为]
// 2. 删除元素
// list.remove("华为");
// list.remove(1);
// System.out.println("删除之后还剩余:" + list.size()); // 删除之后还剩余:1
// System.out.println(list); // [苹果]
// 3. 遍历
// 3.1 使用for遍历
System.out.println("--------使用for遍历--------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
/*
--------使用for遍历--------
苹果
小米
华为
*/
// 3.2 使用增强for
System.out.println("--------使用增强for--------");
for (Object obj:list
) {
System.out.println(obj);
}
/*
--------使用增强for--------
苹果
小米
华为
*/
// 3.3 使用迭代器
Iterator it = list.iterator();
System.out.println("--------使用迭代器--------");
while (it.hasNext()){
System.out.println(it.next());
}
/*
--------使用迭代器--------
苹果
小米
华为
*/
// 3.4 使用列表迭代器,和Iterator的区别: ListIterator可以向前或者向后遍历,添加,删除,修改元素
ListIterator lit = list.listIterator();
System.out.println("--------使用列表迭代器==从前往后--------");
while(lit.hasNext()){
System.out.println(lit.nextIndex()+":" +lit.next());
}
/*
--------使用列表迭代器==从前往后--------
0:苹果
1:小米
2:华为
*/
System.out.println("--------使用列表迭代器==从后往前--------");
while (lit.hasPrevious()){
System.out.println(lit.previousIndex()+": "+lit.previous());
}
/*
2: 华为
1: 小米
0: 苹果
*/
// 4. 判断
System.out.println(list.contains("苹果")); // true
System.out.println(list.isEmpty()); // false
// 5.获取位置
System.out.println(list.indexOf("苹果")); // 0
System.out.println(list.indexOf("华为")); // 2
}
}
下面是数字,基本类型(自动装箱):
package com.collection.list;
import java.util.ArrayList;
import java.util.List;
public class Demo02 {
public static void main(String[] args) {
// 创建集合
List list = new ArrayList();
// 1. 添加数字数据(自动装箱)
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
System.out.println("元素个数:"+list.size()); // 元素个数:5
System.out.println(list); // [10, 20, 30, 40, 50]
// 2. 删除操作
// list.remove(2);
// list.remove(new Integer(20));
// list.remove((Object) 40);
// System.out.println("删除元素:" + list.size()); // 删除元素:2
// System.out.println(list); // [10, 50]
// 3. 补充方法:subList 返回子集合,左闭右开区间 [ )
List subList = list.subList(1,4);
System.out.println(subList); // [20, 30, 40]
}
}
下面是学生信息:
学生类同上:
package com.collection.list;
import com.collection.Demo01.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class Demo03 {
public static void main(String[] args) {
// 创建集合
ArrayList arrayList = new ArrayList();
// 1. 添加元素
Student s1 = new Student("源氏",18);
Student s2 = new Student("艾什",18);
Student s3 = new Student("狂鼠",19);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size()); // 元素个数:3
System.out.println(arrayList); // [学生信息:[name=源氏,age=18], 学生信息:[name=艾什,age=18], 学生信息:[name=狂鼠,age=19]]
// 2. 删除元素
// arrayList.remove(new Student("狂鼠",19)); // equals(this==obj)
// arrayList.remove(s2);
// System.out.println("删除之后:" + arrayList.size()); // 删除之后:1
// System.out.println(arrayList); // [学生信息:[name=源氏,age=18]]
// 3. 遍历元素 ⭐
// 使用迭代器
System.out.println("----------使用迭代器----------");
Iterator it = arrayList.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
/*
----------使用迭代器----------
学生信息:[name=源氏,age=18]
学生信息:[name=艾什,age=18]
学生信息:[name=狂鼠,age=19]
*/
// 使用列表迭代器
ListIterator lit = arrayList.listIterator();
System.out.println("----------使用列表迭代器==顺序----------");
while (lit.hasNext()){
Student s = (Student) lit.next();
System.out.println(s.toString());
}
/*
----------使用列表迭代器==顺序----------
学生信息:[name=源氏,age=18]
学生信息:[name=艾什,age=18]
学生信息:[name=狂鼠,age=19]
*/
System.out.println("----------使用列表迭代器==逆序----------");
while (lit.hasPrevious()){
Student s = (Student) lit.previous();
System.out.println(s.toString());
}
/*
----------使用列表迭代器==逆序----------
学生信息:[name=狂鼠,age=19]
学生信息:[name=艾什,age=18]
学生信息:[name=源氏,age=18]
*/
// 4. 判断
System.out.println(arrayList.contains(new Student("狂鼠",19))); // true
System.out.println(arrayList.contains(s2)); // true
System.out.println(arrayList.isEmpty()); // false
// 5. 查找
System.out.println(arrayList.indexOf(new Student("狂鼠",19))); // 2
System.out.println(arrayList.indexOf(new Student("源氏",19))); // -1 // 年龄应为18 ,没有查找到返回-1
}
}
List 实现类
ArrayList [重点]:
数组结构实现,查询快,增删慢
JDK1.2版本,运行效率快,线程不安全
Vector:
数组结构实现,查询快,增删慢
JDK1.0版本,运行效率慢,线程安全
LinkedList:
链表结构实现,增删快,查询慢
ArrayList
源码分析:
DEFAULT_CAPACITY = 10 ; 默认容量
注意:如果没有向集合中添加任何元素时,容量为0;
添加一个元素之后,容量为10;
每次扩容的大小是原来的1.5倍
elementDate 存放元素的数组
size 实际元素个数
add () 添加元素
Vector
Vector简介
Vector 是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。
Vector 继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能。
Vector 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。
和ArrayList不同,Vector中的操作是线程安全的。
(01) Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10。
(02) 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。
(03) Vector的克隆函数,即是将全部元素克隆到一个数组中。
package com.collection.vector;
import java.util.Enumeration;
import java.util.Vector;
public class Demo01 {
public static void main(String[] args) {
// 创建集合
Vector vector = new Vector();
// 1. 添加元素
vector.add("苹果");
vector.add("草莓");
vector.add("葡萄");
System.out.println("元素个数:"+vector.size()); // 元素个数:3
System.out.println(vector); // [苹果, 草莓, 葡萄]
// 2. 删除元素
// vector.remove(0);
// vector.remove("葡萄");
// vector.clear();
// System.out.println("元素个数:" + vector.size()); // 元素个数:0
// 3. 遍历
// 使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String str = (String)en.nextElement();
System.out.println(str);
}
/*
苹果
草莓
葡萄
*/
// 4. 判断
System.out.println(vector.contains("葡萄")); // true
System.out.println(vector.isEmpty()); // false
// 5. 其他方法
System.out.println(vector.firstElement()); // 苹果
System.out.println(vector.lastElement()); // 葡萄
System.out.println(vector.elementAt(1)); // 草莓
}
}
LinkedList
LinkedList官方文档
LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,而是存储在单独的节点中,然后通过引用将节点连接起来了,因此在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
注意:
LinkedList实现了List接口
LinkedList的底层使用了双向链表
LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
LinkedList比较适合任意位置插入的场景
package com.collection.vector;
import java.util.Enumeration;
import java.util.Vector;
public class Demo01 {
public static void main(String[] args) {
// 创建集合
Vector vector = new Vector();
// 1. 添加元素
vector.add("苹果");
vector.add("草莓");
vector.add("葡萄");
System.out.println("元素个数:"+vector.size()); // 元素个数:3
System.out.println(vector); // [苹果, 草莓, 葡萄]
// 2. 删除元素
// vector.remove(0);
// vector.remove("葡萄");
// vector.clear();
// System.out.println("元素个数:" + vector.size()); // 元素个数:0
// 3. 遍历
// 使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String str = (String)en.nextElement();
System.out.println(str);
}
/*
苹果
草莓
葡萄
*/
// 4. 判断
System.out.println(vector.contains("葡萄")); // true
System.out.println(vector.isEmpty()); // false
// 5. 其他方法
System.out.println(vector.firstElement()); // 苹果
System.out.println(vector.lastElement()); // 葡萄
System.out.println(vector.elementAt(1)); // 草莓
}
}
ArrayList和LinkedList的区别
ArrayList的物理存储空间是连续的,LinkedList物理上不一定连续。
ArrayList支持随机访问,LinkedList不支持随机访问。
ArrayList在插入和删除的时候时间复杂度O(N),LinkedList时间复杂度O(1);所以LinkedList适合频繁插入和删除的场景。
ArrayList空间不够需要动态扩容,LinkedList不需要。
泛型
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
常见形式有:泛型类、泛型接口、泛型方法
语法: T 称为类型占位符,表示一种引用类型
好处:1 提高代码的重(chong)用性
2 防止类型转换异常,提高代码的安全性
下面是泛型类:
package com.collection.generic;
public class Generic<T> {
// 泛型类:Generic<T>
// 语法: 类名<T>
// T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
// 使用泛型 T
// 1. 创建变量
// 泛型不能实例化
T t ;
// 2. 泛型作为方法的参数
public void show(T t){
System.out.println("泛型作为方法的参数:" + t);
}
// 3. 泛型作为方法的返回值
public T getT(){
// return (T)("泛型作为方法的返回值" + t);
return t;
}
}
下面是泛型方法:
package com.collection.generic;
/**
*
* 泛型方法
* 语法:<T>返回值类型
*
*/
public class GenericMethod {
// 泛型方法
public <T> T show(T t){
System.out.println("泛型方法 "+ t);
return t;
}
}
下面是泛型接口:
接口
package com.collection.generic;
/**
* 泛型接口
* 语法:接口名<T>
* 注意:不能创建静态常量
* @param <T>
*/
public interface GenericService<T> {
String name = "张三";
T server(T t);
}
package com.collection.generic;
public class GenericServiceImpl implements GenericService<String>{
@Override
public String server(String t) {
System.out.println(t);
return t;
}
}
package com.collection.generic;
public class GenericServiceImpl2<T> implements GenericService<T>{
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
泛型测试:
package com.collection.generic;
public class TestGeneric {
public static void main(String[] args) {
// 使用泛型类创建对象
/*
注意:
1. 泛型只能使用引用类型
2. 不同泛型类型对象之间不能相互赋值
*/
Generic<String> generic = new Generic<String>();
generic.t = "Java";
generic.show("我爱学习Java,大家加油!"); // 泛型作为方法的参数:我爱学习Java,大家加油!
String string = generic.getT();
System.out.println(string); // Java
Generic<Integer> generic1 = new Generic<>();
generic1.t = 18;
generic1.show(180); // 泛型作为方法的参数:180
Integer integer = generic1.getT();
System.out.println(integer); // 18
// 泛型接口
GenericService gs = new GenericServiceImpl();
gs.server("java"); // java
GenericService gs2 = new GenericServiceImpl2();
gs2.server(10086); // 10086
// 泛型方法
GenericMethod gm = new GenericMethod();
gm.show("java is best!"); // 泛型方法 java is best!
gm.show(10086); // 泛型方法 10086
gm.show(3.1415926); // 泛型方法 3.1415926
}
}
泛型集合
概念:参数化类型、类型安全的集合、强制集合元素的类型必须一致
特点:
- 编译时即可检查,而非运营时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态