集合
一:集合概念
对象的容器,实现了对对象常用的方法,类似数组功能
二:和数组的区别
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
位置:java.util.*;
Collection体系集合
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();//将此集合转换成数组
//创建集合
//Collection 是接口,不能被实例化
Collection c=new ArrayList<>();//父类调用指向子类对象
//添加元素
c.add("苹果");
c.add("丝瓜");
c.add("草莓");
System.out.println(c.size());//打印个数 3
System.out.println(c);// [苹果,丝瓜,草莓]
//删除
c.remove("丝瓜");
System.out.println(c.size());//打印个数 2
//清空 c.clear();
//遍历元素(重点)
for(Object object : c){
System.out.println(object); //打印每一个对象
}
//法二 使用迭代器,专门用来遍历集合
Iterator it = c.iterator();
//该迭代器有三个方法
//hasNext();有没有下一个元素
//next(); 获取下一个元素
//remove();删除当前元素
while(it.hasNext()){
Object ob= it.next();
System.out.println(ob);
}
//迭代过程中是不能使用 collection的方法改变元素
//只能用 Iterator 的remove方法 删除元素
//判断
c.contains("丝瓜");
c.isEmpty();
保存学生信息
//Student 类中 有name age属性
//新建Collection对象
Collection c = new ArrayList<>();
//添加数据
Student s1 = new Student("zhangsan",18);
Student s2 = new Student("zhang",19);
Student s3 = new Student("lisan",22);
c.add(s1);
c.add(s2);
c.add(s3);
//打印输出结果
//删除
c.remove(s1);
//clear方法只是把对象从集合里删除,对象还是存在的
//遍历1
for(Object ob :c){
Student s=(Student)ob;//强转类型
System.out.println(s.toString());
}
//遍历2
Iterator it = c.iterator();
while(it.hasNext){
Student s = (Student)it.next();
System.out.println(s.toString());
}
//判断
c.contains(s1);//true;
List 子接口
特点:有序、有下标、元素可以重复
方法:
- void add(int index,Object o)//在index位置插入对象o
- boolean addAll(int index,Collection c)//将一个集合中的元素添加到此集合中的index位置
- Object get(int index) //返回集合中指定位置的元素
- List subList(int fromIndex,int toIndex)//返回fromIndex和toIndex之间的集合元素
/*
有下标,可重复
*/
//创建集合
List list=new ArrayList<>();
//添加元素
list.add("苹果");
list.add("水蜜桃");
list.add("香蕉");
list.add(0,"橘子");
System.out.println(list.toString());
//[橘子,苹果,水蜜桃,香蕉]
//删除元素
list.remove("苹果");
//删除第一个元素
list.remove(0);
//遍历
//for
for(int i=0;i<list.size();i++){
Object ob=list.get(i);
}
//增强for
for(Object ob:list){
// ob;
}
//迭代器
Iterator it = list.iterator();
while(it.hasNext()){
//
}
//列表迭代器 ListIterator
/*
和Iterator区别
可以向前向后遍历,添加删除
*/
ListIterator lit = list.listIterator();
//从前往后
while(lit.hasNext()){
//下标
System.out.println(lit.nextIndex());
//打印内容
System.out.println(lit.next());
}
//从后往前
while(lit.hasPrevious()){
lit.previousIndex();
lit.previous();
}
//判断
list.contains("");
list.isEmpty();
//获取位置
list.indexOf("苹果");
添加数字(基本)类型(会自动装箱)
list.add(20);
list.add(30);
list.remove(20);//会报错,没有20的下标,
想删除20 :
list.remove(new Integer(20));
或者
list.remove((Object)20)
//补充方法 subList 返回子集合 含头不含尾
List sublist = list.subList(1,3);//从下标1到下标2
List实现类
-
ArrayList【重点】
- 数组结构实现,查询快、增删慢
- JDK1.2版本,运行效率快、线程不安全
-
Vector:
- 数组结构实现,查询快,增删慢
- JDK1.0版本,效率慢,线程安全
-
LinkedList:
- 链表结构实现,增删快,查询慢
ArrayList 的使用
有序有下标可重复
存储结构是数组,查找遍历速度快,增删速度慢
ArrayList arrayList = new ArrayList<>();
//添加
Student s1=new Student("liudehua",22);
Student s2=new Student("guofucheng",23);
Student s3=new Student("liangchaowei",18);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
//删除
arrayList.remove(s1);//删除s1
arrayList.remove(new Student("liudehua",22));//删不掉
//需要删除内容相同的对象
//要重写Student类的equals方法
//遍历 重点
//使用迭代器
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());
}
//判断
contains();
isEmpty();
//查找
indexOf();
//分析源码可知
没有添加任何元素,空间为0
添加一个元素后,空间开阔为10
添加第十一个元素后,空间开阔为15
Vertor
数组结构实现,查询快、增删慢
JDK1.0版本,运行效率慢、线程安全
//创建集合
Vector vector = new Vector<>();
//添加元素
vector.add();
//删除
vector.remove();
vector.clear();
//遍历 使用枚举器
Enumeration en = vector.elements();
while(en.hasMoreElements()){
en.nextElement();
}
//判断
vector.contains();
//补充
firsetElements
LinkedList
链表结构实现,增删快,查询慢
双向链表
//创建集合
LinkedList linkedList = new LinkedList<>();
//添加元素
linkedList.add();
//元素个数
linkedList.size();
//删除元素
linkedList.remove();
linkedList.clear();
//遍历元素
for(int i=0;i<linkedList.size();i++){
linkedList.get(i);
}
//增强for
for(Object object : linkedList){
object;
}
//迭代器
Iterator it = linkedList.iterator();
while(it.hasNext()){
it.next();
}
//迭代器2
ListIterator lit =linkedList.listIterator();
//判断元素
linkedList.contains();
linkedList.isEmpty();
//获取 对象在链表中的下标
linkedList.indexOf();
泛型
- JDK1.5的新特性,本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 语法 <T,…> T 称为类型占位符,表示一种引用类型
- 好处
- 提高代码的复用性
- 防止类型转换异常,提高代码的安全性
//泛型类 在类名后面 <T>
// T 是类型占位符,是一种引用类型,如果多个用逗号隔开
public class MyGeneric<T> {
//使用泛型T
//1.创建变量
T t;
//作为方法参数
public void show(T t){
//不能实例化,可以创建变量
System.out.println(t);
}
//泛型作为方法的返回值
public T getT(){
return t;
}
}
使用泛型类
public class TestGeneric{
public static void main(String[] args){
//使用泛型类创建对象
//1.泛型只能是引用类型
//2.不同泛型类型对象之间不能相互复制
MyGeneric<String> myGeneric = new Mygeneric<String>();
myGeneric.t="hahaha";
myGeneric.show("123");
String string = myGeneric.getT();
MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
myGeneric2.t=100;
myGeneric2.show(200);
Integer integer = myGeneric2.getT();
//使用泛型接口
MyInterfaceImp imp1=new MyInterfaceImp();
imp1.server("xxx");
MyInterfaceImp2 imp2=new MyInterfaceImp2<>();
imp2.server(1000);
}
}
泛型接口
/*
泛型接口
语法 接口名<T>
注意:不能泛型静态常量
*/
public interface MyInterFace<T>{
String name = "zhangsan";
T server(T t);
}
实现类
//方式一 已经确定类型
public class MyInterfaceImp implements MyInterface<String> {
public String server(String t){
System.out.println(t);
return t;
}
}
//方式2 不确定类型
public class MyInterfaceImp2<T> implements MyInterface<T> {
public T server(T t){
System.out.println(t);
return t;
}
}
泛型方法
/*
泛型方法
语法 <T>方法的返回值类型
*/
public class MyGenericMethod{
//泛型方法
public <T> T show(T t){
System.out.println("泛型方法");
return t;
}
}
测试泛型方法
MyGenericMethod my=new MyGenericMethod();
//类型由传递值的类型决定
my.show("lalalala");
my.show(200);
my.show(3.14);
泛型集合
- 概念:参数化类型,类型安全的集合,强调集合元素的类型必须一致
- 特点
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
ArrayList<String> arrayList=new ArrayList<String>();
//这样做限制了 类型
arrayList.add("sss");
arrayList.add(123);//会报错
ArrayList<Student> arrayList2=new ArrayList<Student>();
//只能添加Student类型数据
//泛型不同的对象不能相互赋值
set
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
set接口实现
/*
测试Set接口的使用
没有顺序,没有下标,不能重复
*/
import java.util.Set;
public class Demo1{
public static void main(String[] args){
//创建集合
Set<String> set =new HashSet<>();
//添加
set.add("sss");
//数据个数
set.size();
//删除
set.remove("sss");
//清空
set.clear();
//遍历
// 增强for
for(String string : set)
System.out.println(string);
//迭代器
Iterator<String> it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
set实现类
-
HashSet(重点)
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果是true,则拒绝后者存入
-
TreeSet
- 基于排序顺序实现
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
HashSet集合的使用
/*
存储结构:哈希表(数组+链表+红黑树)
无序的,和添加顺序无关
不能重复
存储过程:
1)根据hashcode计算保存的位置,如果此位置为空,则之间保存,如果不为空则执行第二步
2)再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
*/
//创建集合
HashSet<String> hashSet = new HashSet<>();
//添加元素
hashSet.add("zhangsan");
hashSet.add("lisi");
hashSet.add("wangwu");
hashSet.add("zhaoliu");
//删除
hashSet.remove("lisi");
//清空
hashSet.clear();
//增强for遍历
for(String string : hashSet){
System.out.println(string.toString());
}
//迭代器遍历
Iterator it = hashSet.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
//判断
hashSet.contains("lisi");
//判断是否为空
hashSet.isEmpty();
//元素个数
hashSet.size();
Person p1 = new Person(“zhangsan”,23);
persons.add(p1);
//即使年龄和姓名相同,但是是一个新的对象
//默认会添加到hashset集合中
persons.add(new Person(“zhangsan”,23));
//为了使相同名字和年龄的对象不能重复添加
//1.重写hashCode方法
//若名字和年龄一样,则返回的哈希值也一样
//会形成链表加入
public int hashCode(){
int n1=this.name.hashCode();
int n2=this.age;
return n1+n2;
}
//2.还需要重写equals
public boolean equals(Object obj){
if(obj==null){
return fasle;
}
if(this==obj){
return true;
}
//类型是 Person类
if(obj instanceof Person){
//强制类型转换
Person p =(Person)obj;
//判断属性
if(this.name.equals(p.getName()) && this.age=p.getAge()){
return true;
}
}
return fasle;
}
TreeSet集合的使用
/*
存储结构:红黑树
*/
TreeSet<String> treeSet = new TreeSet<>();
//添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("hello");
//没有重复
//元素个数
treeSet.size();
//删除
treeSet.remove("xyz");
//遍历
for(String string: treeSet){
string;
}
Iterator it = treeSet.iterator();
while(it.hasNext()){
it.next();
}
//判断
treeSet.contains();
补充:
用Person类 添加到TreeSet类 会出错
需要创建一个接口,给定要比较的是什么
给定比较的规则
要求:元素必须实现Comparable接口,compareTo()方法返回值为0
认为是重复元素
//Person类实现接口
//先按姓名比,再按年龄比
public int compareTo(Person o){
int n1=this.getName().compareTo(o.getName());
int n2=this.age-o.getAge();
return n1==0?n2:n1;
}
comparator定制比较
比较器,实现定制比较
comparable::可比较的
//创建集合,并指定比较规则:先比较年龄再比较名字
TreeSet<Person> persons = new TreeSet<>(new Comparator(){
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;
}
});
Person s1=new Person("zhangsan",23);
Person s2=new Person("lisi",24);
Person s3=new Person("wangwu",22);
persons.add(s1);
persons.add(s2);
persons.add(s3);
案例:使用TreeSet集合实现字符串按照长度进行排序
TreeSet<String> treeSet=new TreeSet<>(new Comparator<String>(){
//定制比较规则
public int compare(String o1,String o2){
int n1=o1.length()-o2.length();
int n2=o1.compare(o2);
return n1==0?n2:n1;
}
});
//添加数据
treeSet.add("helloworld");
treeSet.add("lisi");
treeSet.add("beijing");
treeSet.add("code");
//打印数据
Map集合
特点:
- 用于存储任意键值对
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
Map父接口使用
/*
存储的是键值对
键不能重复,值可以重复
无序
*/
//创建Map集合 Map是接口不能实例化
Map<String,String> map=new HashMap<>();
//添加元素
// "cn" 是键 “中国”是值
map.put("cn","zhongguo");
map.put("uk","yingguo");
map.put("usa","meiguo");
//打印元素个数
map.size();
//删除
//根据键删除
map.remove("usa");
//遍历
//keyset方法 返回的是一个集合
Set<String> keyset=map.keySet();
for(String key : keyset){
System.out.println(key);
map.get(key);//通过key 获得value
}
//使用 entrySet() 效率高与keySet()
//返回的是 entry类型的 set集合
Set<Map.Entry<String,String>> entries=map.entrySet();
for(Map.Entry<String,String> entry : entries){
entry.getKey() ;
entry.getValue();
}
//判断
//值判断
map.containsValue("zhongguo");
//键判断
map.containsKey("cn");
Map集合的实现类
-
HashMap 【重点】
- JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value
-
Hashtable
- JDK1.0版本,线程安全,允许效率慢;不允许null作为key或是value
-
Properties
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取
-
TreeMap
- 实现了SortedMap接口(Map的子接口),可以对key自动排序
HashMap集合的使用
//默认初始容量 16 加载因子0.75
/*
存储结构:哈希表(数组+链表+红黑树)
*/
//先创建好学生类 Student 有姓名和学号
//集合
HashMap<Student,String> stu=new HashMap<Student,String>();
Student s1=new Student("zhangsan",100);
Student s2=new Student("lisi",101);
Student s3=new Student("wangwu",102);
stu.put(s1,"beijin");
stu.put(s2,"shanghai");
stu.put(s3,"hangzhou");
//键不能重复,新值会替代旧值
//个数
stu.size();
//虽然键相同,但是还是加进去了
//因为new了新对象
stu.put(new Student("liusi",101),"hangzhou");
//需要 重写 hashCode 和equals方法
//在Student类中 重写
//就可以去重
//删除
stu.remove(s1);
//遍历
//keySet
for(Student key : stu.keySet()){
key.toString(); //键
stu.get(key);//值
}
//entrySet
for(Map.Entry<Student,String> entry : stu.entrySet()){
entry.getKey();//键
entry.getValue();//值
}
//判断
stu.containsKey();
总结:
- HashMap刚创建时,table是null,为了节省空间。当添加第一个元素时,table容量调整为16
- 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小变为原来的两倍,目的是减少调整元素的个数
- jdk1.8当每个链表长度大于8,并且数组个数大于等于64时,会调整为红黑树,目的是提高执行效率
- jdk1.8 当链表长度小于6时,调整成链表
- jdk1.8 以前,链表时头插入,jdk1.8后是尾插入
TreeMap
TreeMap<Student,String> treeMap=new TreeMap<Student,String>();
Student s1=new Student("zhangsan",100);
Student s2=new Student("lisi",101);
Student s3=new Student("wangwu",102);
//添加元素
treeMap.put(s1,"beijin");
treeMap.put(s2,"shanghai");
treeMap.put(s3,"shenzen");
//会出异常 树的结构,需要定义比较规则
//在Studnet类中 实现接口 定义比较规则
public int compareTo(Student o){
int n2=this.stuNo-o.getStuNo();
return n2;
}
//添加不了,会替换,因为学号相同了,比较规则里比的是学号
treeMap.put(new Student("wangwu",102),"hangzhou");
//删除
treeMap.remove(s3);
//能删除,比的是学号
treeMap.remove(new Student("wangwu",102),"hangzhou");
//遍历
for(Student key : treeMap.keySet()){
key;
treeMap.get(key);
}
//
for(Map.Entry<Student,String> entry:treeMap.entrySet()){
entry.getKey();
entry.getValue();
}
//Panduan
treeMap.containsKey();
Colletions 工具类
- 概念:集合工具类,定义了除存取以外的集合常用方法
List<Integer> list = new ArrayList<>();
list.add(12);
list.add(8);
list.add(20);
list.add(2);
list.add(18);
//sort 从小到大
Collections.sort(list);
//binarySearch 查找
int i = Collections.binarySeatch(12);
//负值说明没找到
//复制 报错了
List<Integer> dest=new ArrayList<>();
Collections.copy(dest,list);
//要先 把dest的长度扩展到和list的长度一致
for(int i=0;i<list.size();k++){
dest.add(0);
}
//reverse 反转
Collections.reverse(list);
//shuffle 打乱
Collections.shuffle(list);
//补充:
// list 转成 数组
Integer[] arr=list.toArray(new Integer[0]);
//数组转成集合
String[] names={"zhangsan","lisi","wangwu"};
//这个集合是受限集合,不能添加和删除
List<String> list2=Arrays.asList(names);
//不要用基本类型int..去转集合 会有问题
Integer[] nums={100,200,300,400};
List<Integer>list3 =Arrays.asList(nums);
集合总结
-
集合的概念
- 对象的容器,和数组类似,定义了多个对象进行操作的常用方法
-
List集合:
- 有序、有下标、元素可以重复(ArrayList,LinkedList,Vertor)
-
Set集合
- 无序、无下标、元素不可重复(HashSet,TreeSet)
-
Map集合
- 存储一对数据,无序、无下标,键不可重复,值可重复(HashMap,HashTable,TreeMap)
-
Collections:
- 集合工具类,定义了除存取以外的集合常用方法