Java的collection集合/set容器/list容器/map容器
一、collection集合【父类】
collection是父类 父类的方法子类全都可以使用
集合和数组的区别
1、数组 长度固定
集合 长度不固定
2、数组中存储的数据是同一类型的
集合存储的一定是对象 不过对象是任意类型的
list.add(“abc”)
什么时候用集合?
当对象很多的时候(对象很多?不存在的…
collection集合的方法
①、如何知道添加完到底有没有?直接输出对象
Collection c=new ArrayList();
以前直接输出对象 然后输出结果是类名@内存地址
这里是打印集合 把集合中的元素以数组形式打印出来
②、一般方法(不带All的方法)
add() 添加 可以添加任意类型的对象
remove() 删除
contains() 判断集合中是否包含某个对象 返回boolean
size() 返回此列表的元素数
③、全部方法(带All的方法)
addAll() 添加全部 将collection2的所有元素添加到collection1的尾部 并且内容允许重复
containsAll() A.containsAll(B)判断集合A里是否包含集合B中的所有元素 返回boolean
removeAll() A.removeAll(B)移除A中包含在B中的所有元素 即 移除集合A和集合B共同的元素
retainAll() A.retainAll(B)保留A中包含在B中的所有元素 即 保留集合A和集合B共同的元素
二、list【子类,继承自collection】
List容器的特点
1、元素存储和取出顺序是有序的
2、有角标 可以进行精确地定位
3、允许重复的元素
这是List集合的特有方法★因为能精确定位
list.size() 获取该list集合的总长度
for (int i=0;i<list.size();i++)
{
System.out.println(list.get(i));
}
List接口支持对元素进行curd(create update read delete)操作
注:只有List集合可以增删改查 因为它有角标
经典for循环用迭代器遍历集合元素示例:
for (Iterator<MyStudent> it = list.iterator(); it.hasNext();)
{
MyStudent s=it.next();
System.out.println(s);
}
1、ArrayList
ArrayList特点★
1、定位一个元素很快 因为有索引
2、增加和删除一个元素很慢 因为底层是数组实现 效率较低
它采用的是数组结构
方法:
获取元素 get(int index) :
只是获取 不进行修改
MyStudent a=list.get(0);
修改元素 set(int index,E element) :
(获取为get 修改为set)
list.set(0,new MyStudent("学生M",17));
2、LinkedList
LinkedList特点★ LinkedList:链接链表 简称链表
数据域→指针域
1、查找操作费时
2、添加和删除操作 简单
它采用的是链表结构
方法:
addFirst(E e) 将指定元素插入此列表的开头:
link.addFirst("aaa");
addFirst(E e) 将指定元素插入此列表的末尾:
link.addLast("zzz");
获取第一个数据:
link.getFirst();
获取最后一个数据:
link.getLast();
获取元素 get(int index) 只是获取 不进行修改:
MyStudent a=list.get(0);
修改元素 set(int index,E element) :
(获取为get 修改为set)
list.set(0,new MyStudent("学生M",17));
三、set【子类,继承自collection】
Set容器的特点
1、元素存储和取出顺序是无序的
2、没有角标 不能进行精确地定位
3、不允许重复的元素 内容相同的只保留一个 它是通过复写equals()方法来判断是否的重复元素
Set容器和List容器一样 同样支持迭代和增强for循环
1、HashSet
返回哈希值
int hashCode=stu1.hashCode();
小案例
需求:同姓名同年龄视为同一个人
前置:
set.add(new Student("treeset",16));
set.add(new Student("B",21));
set.add(new Student("C",24));
set.add(new Student("treeset",16));
首先调用hashCode() 判断两个对象的哈希值是否一样(算法可以凭自己喜好写)
重写hashCode()方法★
重写hashCode()方法的目的就是要让同姓名同年龄的hashCode相同
因为原装的hashCode的算法结果 同姓名同年龄的hashCode不同 无法达到需求
public int hashCode()
{
return name.hashCode()+age;
}
若两个对象的hashCode()不相同 则:存这个对象
若两个对象的hashCode()相同 则:调用equals()方法 判断内容也是否一样
若不一样 采用拉链法 存储
若一样 视为重复 不存储
重写equals()方法★
public boolean equals(Object obj) {
if (this==obj)//若传进来的和当前引用对象为同一个对象(即:自己和自己比较)
{
return true;
}
if (obj==null)//若传空值
{
return false;
}
if (obj instanceof Student)//若传进来的不为Student类或其子类
{
Student s=(Student)obj;//强制类型转换
return name.equals(s.name) && this.age==s.age;//判断姓名和年龄是否相等
}
return super.equals(obj);
}
以上如此 即可实现需求
2、TreeSet
排序有两种方式:
1、实现Compareable接口 并且复写CompareTo()方法
2、TreeSet(Comparator<? super E> comparator)
构造一个新的空TreeSet 它根据指定比较器进行排序
①、compareTo()方法
用此方法时 传入的自定义的类必须实现Comparable接口 并且复写compareTo方法 二者缺一不可★
比较方法一:根据姓名排序★
@Override
public int compareTo(StudentX s)
{
//在此比较时 必须明确主次 主要条件相等 再进行次要条件比较
int temp=this.name.compareTo(s.name);
return temp==0?/*若姓名相同*/ this.age-s.age:temp/*若姓名相同 返回年龄,若姓名不相同 返回0*/ /*再按照姓名排序*/;
}
比较方法二:根据年龄排序★
@Override
public int compareTo(StudentX s)
{
//在此比较时 必须明确主次 主要条件相等 再进行次要条件比较
int temp=this.age-s.age;
return temp==0?/*若年龄相同*/ this.name.compareTo(s.name):temp/*再按照姓名排序*/;
}
②、compare()方法★★★
用此方法时 传入的自定义的类无须实现Comparable接口 无须复写compareTo方法★
但要在比较器里实现Comparator接口 复写compare方法★
语法:TreeSet(Comparator<? super E> comparator)
构造一个新的空TreeSet 它根据指定比较器进行排序
例:Set<StudentXX> set=new TreeSet<StudentXX>(new TreeSetCompareByName())
用于中文比较的类
Collator collator=Collator.getInstance(Locale.CHINA);
小案例:
要求:姓名和年龄相同 视为同一个对象
按照姓名排序:当姓名相同 再根据年龄排序
自己创建个比较器 用于执行固定的功能
public class TreeSetCompareByName implements Comparator<StudentXX>
{
@Override
public int compare(StudentXX o1, StudentXX o2) {
//如果是汉字,字符串比较不包含中文
Collator collator=Collator.getInstance(Locale.CHINA);//用于中文比较的类★★★
int temp=collator.compare(o1.name,o2.name);
return temp==0? o1.age-o2.age:temp;//若o1.age大于o2.age 返回一个正数 则代表o1的age比o2的age大 且它们两个不相等
}
要求:姓名和年龄相同 视为同一个对象
按照年龄排序:当年龄相同 再根据姓名排序
自己创建个比较器 用于执行固定的功能
public class TreeSetCompareByAge implements Comparator<StudentXX>
{
@Override
public int compare(StudentXX o1, StudentXX o2) {
//如果是汉字,字符串比较不包含中文
Collator collator=Collator.getInstance(Locale.CHINA);//用于中文比较的类★★★
int temp=o1.age-o2.age;//若o1.age大于o2.age 返回一个正数 则代表o1的age比o2的age大 且它们两个不相等
return temp==0? collator.compare(o1.name,o2.name):temp;
}
}
总结:
Set两个实现类:
一、hashset
底层结构:哈希表(数组+链表)
如果自定义一个类
自定义:对象是否是同一个对象 就要重写HashCode()方法和equals()方法
二、TreeSet
底层结构:二叉树结构
1、让自定义的类去实现comparable接口 重写compareTo()方法
自定义排序需求(根据年龄、姓名…)
2、写一个比较器 实现comparator 重写compare()方法
自定义排序需求(根据年龄、姓名…)
TreeSet比HashSet多了排序功能
四、map【子类,继承自collection】
不关心实现类到底是谁 只关心顶层方法
存储特点:
存储重复键 对应的值会被覆盖
方法:
put(K key, V value) 往map里添加键值对
get(Object key) 返回指定键所映射的值,如果此映射不包含该键的映射关系 则返回null
remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除
Integer a=map.remove("bbb");//移除一个key键 并返回这个键对应的value值
keySet() 返回此映射中所有的键
K→getKey() 返回与此项对应的键
V→getValue() 返回与此项对应的值
Set<Map,Entry<K,V>>→entrySet() 返回此映射中包含的映射关系的Set视图
返回map中键值对的映射关系 这个键值对的映射关系由Set保存
拆箱:将Integer类型自动转化成int类型
例:
Map<String,Integer> map=new HashMap<String,Integer>();
map.put("aaa",1);
int i=map.get("aaa");
Map集合的遍历方式:
方法一、通过键找值 ★
步骤:
1、调用集合的keySet()方法 获得集合所有的键
2、遍历所有的键 调用集合的get(Object obj) 通过指定的键找到对应的值
方法:keySet()
返回此映射中所有的键
例:
Map<String,Integer> map=new HashMap<String,Integer>();
map.put("aaa",1);
map.put("bbb",2);
map.put("ccc",99999);
map.put("ccc",3);
Set<String> mySet=map.keySet();//通过map集合的keySet()方法获得集合中的全部的键key
or (Iterator<String> it=mySet.iterator();it.hasNext();)
{
String myKey=it.next();
Integer myValue=map.get(myKey);//通过key找到对应的value值
System.out.println("Key="+myKey+" Value="+myValue);
}
方法二、通过map.entrySet()方法 ★
思考方式:
public interface Map
{
class Entry
{
}
}
Map.Entry<K,V>这里面存的是键值对的映射关系 把键值对的映射关系封装成一个类
Entry反映的是键值关系 里面保存的是键值对 所以里面要注明K和V的类型Set<Map.Entry<K,V>>
→ 这里的Map.Entry<K,V>相当于Student 也是一个类而已
方法:K→getKey()
返回与此项对应的键V→getValue()
返回与此项对应的值Set<Map,Entry<K,V>>
→entrySet() 返回此映射中包含的映射关系的Set视图
返回map中键值对的映射关系 这个键值对的映射关系由Set保存
步骤:
1、调用map集合方法中的entrySet() 将集合中的映射关系对象存储到set集合中
2、迭代set集合
3、获取set集合中的映射关系对象元素
4、通过映射对象方法getKey()和getValue()来获取键值对
例:
Map<String,Integer> map=new HashMap<String,Integer>();
map.put("aaa",1);
map.put("bbb",2);
map.put("ccc",99999);
map.put("ccc",3);
Set<Map.Entry<String,Integer>> mySet=map.entrySet();//调用entrySet()方法获得集合中的全部的键和值
遍历方法一、用迭代器遍历★
Iterator<Map.Entry<String,Integer>> it=mySet.iterator();//创建迭代器
while (it.hasNext())
{
Map.Entry<String,Integer> myEntry=it.next();
System.out.println("Key="+myEntry.getKey()+" Value="+myEntry.getValue());//这里的每个myEntry都是一组key键和value值
}
//遍历方法二、用增强for循环遍历★
for (Map.Entry<String,Integer> myEntry:mySet)
{
System.out.println("Key="+myEntry.getKey()+" Value="+myEntry.getValue());//这里的每个myEntry都是一组key键和value值
}
推荐阅读
-
Java中的容器(集合)之ArrayList源码解析
-
set容器与map容器的简单应用
-
Java中的容器(集合)之HashMap源码解析
-
[ Java学习基础 ] Java的对象容器 -- 集合
-
荐 JAVA13——容器(Map接口、Equals和hashcode、Set接口、容器存储数据练习、Iterator接口)
-
荐 Java语言基础之Collection接口、List集合、Set集合的基本使用
-
Java多线程并发编程中并发容器第二篇之List的并发类讲解
-
java容器类分析:Collection,List,ArrayList
-
【java读书笔记】——Collection集合之六大接口(Collection、Set、List、Map、Iterator和Comparable)
-
Java通过工厂、Map容器创建对象的方法