Java集合框架
除了数组之外存储的方式 。容器,可以动态的吧多个对象引用放入容器中集合出现目的就是为了替代数组,能用集合就用集合
Collection接口
单列集合 存储一个一个对象
collection.addAll(coll); //将coll集合元素添加到collection中 collection.add("12");//将12添加到集合中 System.out.println(collection.size());//获取元素个数 System.out.println(collection.toString());//打印集合中的元素 System.out.println(collection.isEmpty())//判断集合受否为空 collection.clear//清空集合元素 boolean contains = coll.contains(465);//判断集合是否包含这个元素 调用的方法是equals Collection coll1 = Arrays.asList(456,446);//创建集合时直接填入数据 coll.remove(456);//删除数据 coll.removeALL(coll1)//从coll移除coll1中的元素 是数学中的差集 coll.retaainALL(coll1)//获取coll1和coll交集 返回coll equals coll.equals(coll1) //比较两个集合 hashCode//调用哈希值 toAraay 集合---->数组 iterator();返回 iterator接口的实例,用于遍历集合元素
public class test {
public void test(){
Collection collection = new ArrayList();
collection.add("12");
collection.add("adsa");
collection.add("bb");
collection.add(new Date());
System.out.println(collection.size());
Collection coll = new ArrayList();
coll.add("456");
coll.add("456");
collection.addAll(coll);
System.out.println(collection.size());
System.out.println(collection.toString());
}
}
Collection coll = new ArrayList();
coll.add("456");
coll.add("446");
coll.add(false);
coll.add(new Person(50,"王鹏翔"));
coll.add(new String("王鹏翔"));
boolean contains = coll.contains(465);
System.out.println(contains);
System.out.println(coll.contains(new String("王鹏翔")));
System.out.println(coll.contains(new Person(50 ,"王鹏翔")));
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
//person类中重写equals方法 否则无法比较对象
person类中重写equals方法 否则无法比较对象
输出元素会用到toString方法 如果没重写toString方法则只会输出引用对象的哈希值,不会输出对象的内容
Iterator迭代器接口
集合元素遍历
指针都在第一个元素之前
每次调用 .iterator()方法指针都会返回第一个元素之前
调用两次remove方法会出IllegalStateException
.iterator()不能遍历Map接口
Iterator iterator = coll.iterator();
System.out.println(iterator.next());//写一个输出一个 如果写的超过元素则会报错NoSuchElementException
输出多个元素肯定不能一直写System.out.println(iterator.next());
用循环结构输出 while if都行,一般用while
while (iterator.hasNext()){
System.out.println(iterator.next());
}
iterator原理
一个队列,hasNest()方法看下一个有没有元素,nest()方法 指针下移然后输出元素。它不是容器只是用来遍历的工具
常见错误方式1 因为.next()操作会改变指针 所以下面这个方法会跳着输出,改变两个指针,只输出了第二个元素。也会空指针异常NoSuchElementException
while (iterator.next() !=null){
System.out.println(iterator.next());
}
常见错误方式2 图省事不写 Iterator iterator = coll.iterator();
coll.iterator()等于每次重新初始化调用这个方法,即每次输出的总是第一个元素
while (coll.iterator().hasNext()){
System.out.println(coll.iterator().next());
}
remove方法
// 删除集合中王鹏翔Person类的数据
while (iterator.hasNext()) {
Object obj = iterator.next();
if (new Person("王鹏翔").equals(obj)) {
iterator.remove();
}
}
iterator = coll.iterator();//把指针移到最上边
while (iterator.hasNext()){
System.out.println(iterator.next());
}
foreach 或者增强for循环用于遍历集合
public void test(){
Collection coll = new ArrayList();
coll.add(456);
coll.add(446);
coll.add("466");
coll.add(false);
coll.add(new Person("王鹏翔"));
coll.add(new String("王鹏翔1"));
Iterator iterator = coll.iterator();
// for( 集合元素的类型 局部变量:集合对象)因为coll是个对象 所以用Object 而obj是自己随便起的名字 只是形式参数
for (Object obj:coll) {
System.out.println(obj);
}
foreach其实代码也是调用迭代器iterator,形式上不一样
foreach不会改变原有数组中的元素
Collection 的Set接口
元素无序、不可重复 —》高中集合
无序性不等于随机性,存储的数据在数组中不是按照索引顺序添加,而是根据数据哈希值决定
不可重读性,保证添加的元素按照equals()判断是不能返回ture,即形同元素只能添加一个
实现不可重复性必须重写equals和HashCode方法
,HashCode方法是根据内容计算哈希值的方法
HashCode在add时创建一个数组 key=16 模相同,哈希值不同 存入链表(相同的地方延伸)
模相同,哈希值一样,调用equals比较 一样则插入链表
Set set= new HashSet();
void test1(){
set.add(456);
set.add(123);
set.add(new Person(22,"王鹏翔"));
set.add("王鹏翔");
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
王鹏翔
456
123
Person{age=22, name='王鹏翔'}
LinkedHashSet
extends HashSet<E>是hashset子类
在添加数据的同时,还维护了两个引用,记录了数据的前一个数据和后一个数据
有利于频繁遍历操作
Set set= new LinkedHashSet();
TreeSet
二叉排序树
TreeSet 添加的数据 要求由同一个类提供 错误实例
public class TreeSetTest {
Set set= new TreeSet();
void test1(){
set.add(456);
set.add(123);
set.add(123);
set.add(new User(20,"wpx"));
set.add(new User(20,"wpx"));
set.add("王鹏翔");
}
}
void test1(){
set.add(456);
set.add(123);
set.add(123);
set.add(15);
set.add(-1);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
-1
15
123
456
遍历后,从小到大排序
如果传递的值为对象
自然排序 Comparable
TreeSet 的iterator排序不用equals 而用compareTo方法
必须在类里implements Comparable接口 然后重写compareTo方法 按照自已的要求重写
@Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// User user = (User) o;
// return age == user.age && Objects.equals(name, user.name);
// }
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public int compareTo(Object o) {
if (o instanceof User){
User user = (User) o;
int compare = this.name.compareTo(user.name);
if (compare != 0){
return compare;
}else {//二级排序
return Integer.compare(this.age,user.age);
}
}else {
throw new RuntimeException("输入不匹配");
}
}
定制排序 常用类部分
implements Comparable
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User ){
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(), u2.getAge());
}else {
throw new RuntimeException("不匹配");
}//只要一个年龄相同的
}
};
TreeSet set= new TreeSet(com);
set.add(new User(21,"张三"));
set.add(new User(19,"李四"));
set.add(new User(26,"张武"));
set.add(new User(26,"王6"));
set.add(new User(27,"王6"));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Collection 的List接口
元素有序、可重复 —》动态数组
/**
* ArrayList LinkList Vector 异同
* 相同点:都是想List接口,存储数据特点相同:存储有序的可重复的数据
* 不同:ArrayLis主要实现类
* Vector 出现比较古老 1.0 比List接口和其他两个类还老 1.2
* ArrayList线程不安全 效率高 Vector 安全 效率低 底层都使用Object[]数组
*Vector 安全 效率低 底层都使用Object[]数组
* LinkList底层使用双向链表 但对于频繁使用插入删除操作效率比较高
*
* */
三个实现类
ArrayList 第一次使用add()时,底层创建了一个长度为10的数组, 当超过十个时 新造一个1.5倍的数组 。然后复制过去在加上这个新加的数字 不够一直扩容。如果知道大概放多少,建议开发中使用带参构造器
List接口常用方法
Arraylist 增删改查 长度 遍历
list.add(1,"bb");索引为1的位置插入,其余往后移
list.addAll(list1);//list1所有元素加入到list
add只添加一个元素 list.add(list1);会吧list1作为一个元素加入到list
System.out.println(list.get(0));//获取下标为0的元素
list.indexOf(new Person(50, "王鹏翔"));获得元素下标
list.lastindexOf() 最后一个符合条件的元素
list.remove(index:0);//按照下表删除元素
list.set(1,789);//把下标1元素修改为789
List subList = list.subList(2, 4);//取(2,4]区间元素
public static void main(String[] args) {
/* ListTest test = new ListTest();
test.set(test.list);
System.out.println(test.list);*/
ListTest test = new ListTest();
test.test1();
System.out.println(test.list);
}
class ListTest {
ArrayList list = new ArrayList();
void test1(){
list.add(123);
list.add(456);
list.add("aa");
list.add(new Person(50,"王鹏翔"));//顺序插入
list.add(1,"bb");//索引插入
}
}
List list1 = Arrays.asList(1,2,3); //新建一个list1
list.addAll(list1);//list1所有元素加入到list add只添加一个元素
System.out.println(list);
int index = list.indexOf(new Person(50, "王鹏翔"));
System.out.println(index);//输出符合第一个元素的下表
list.remove(0);移除下标为0的元素
System.out.println(list.remove(0));输出这个元素
list.set(1,789);//把下标为1的元素修改为789
删除两种方法
ArrayList list = new ArrayList();
void test3(){
list.add(123);
list.add(456);
list.add("aa");
list.add(new Person(50,"王鹏翔"));
list.remove(index:0);//按照索引删除
list.remove(new Integer(123));//或者new String等等 按照数据删除
System.out.println(list);
}
遍历 三种方法
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("******************");
for (Object o:
list) {
System.out.println(o);
}
System.out.println("******************");
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
Map接口
具有映射关系的 key-value对集合,类似于函数y=f(x)(x1,y1)能多对一,不能一对多
Map和set有关联
// HashMap的主要实现类 线程不安全 先率高,可以存储null的key value
// LinkedHashMap 遍历时有序,在原有的HashMap添加了一对指针,适合频繁遍历操作
// TreeMap 存储有序的kv才用,按照key-value进行排序,一般按照key来排序,自然排序或定制排序。
// 使用二叉排序树的红黑树
// HashTable为古老实现类 线程安全效率低 不怎么用,不可以存储null的key value
key-value 理解
key不能重复,无序 用set存储。values可重复无序,看成用Collection存
Map中的kv 原理是用Entry封装成一个数据,Entry 无序不可重复,类似set
所以set和map有关联
key的类需要重写equals和hashcode方法
value类需要重写equals方法
treeMap 例外,使用compare或comparable进行自然排序或定制排序
jdk8中HashMap底层实现原理,
底层数组Node类型数组,不是Entry【】数组,
首次调用put方法时底层创建长度为16的数组。
HashCode在add时创建一个数组 key=16 模相同,哈希值不同 存入链表(相同的地方延伸)
模相同,哈希值一样,调用equals比较 一样则插入当前元素下的链表
当一个索引位置上的元素以链表形式存在的数据个数>8并且数组长度>64时,用红黑树存储。
Map中常用方法
Map map = new HashMap();
map = new LinkedHashMap();
添加删除修改
Object put(Object key,Object value);将指定key-value添加或修改到当前map对象中
put
public void test1(){
Map map = new HashMap();
map.put("aa",123);//添加
map.put("bb",123);
map.put("cc",123);
map.put("aa",456);//修改
System.out.println(map);
}
putAll
Map map = new HashMap();
map.put("aa",123);
map.put("bb",123);
map.put("cc",123);
map.put("aa",456);
System.out.println(map);
Map map1 = new HashMap();
map1.put("dd",123);
map1.put("ee",123);
map1.put("ff",123);
map.putAll(map1);
System.out.println(map);
{aa=456, bb=123, cc=123}
{aa=456, bb=123, cc=123, dd=123, ee=123, ff=123}
remove
Map map = new HashMap();
map.put("aa",123);
map.put("bb",123);
map.put("cc",123);
map.put("aa",456);
System.out.println(map);
Object cc = map.remove("cc");
System.out.println(cc);
System.out.println(map);
输出
{aa=456, bb=123, cc=123}
123
{aa=456, bb=123}
clear
map.clear();
System.out.println(map.size());
System.out.println(map);
//不等于map等于null 更像是整成一个空集合
0
{}
get
元素查询 根据key查询value
System.out.println(map.get(456));
boolean b = map.containsKey(456);//判断这个key是否存在
boolean b1 = map.containsValue(456);//判断这个value是否存在
System.out.println(b);
System.out.println(b1);
false
true
size
获取对的个数
isEmpty
判断是否为空
equals
判断两个map是否相等
Map遍历操作
遍历key 我们知道key使用set存储的,keySet()方法可以提取key
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
遍历values
Collection values = map.values();
for (Object o: values) {
System.out.println(o);
}
虽然key 和values都是无序,但是查找的顺序是一样的,无序不是随机
遍历key-value
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
aa=456
bb=123
cc=123
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
Map.Entry entry = (Map.Entry) o;
System.out.println(entry.getKey()+"-------"+entry.getValue());
}
aa-------456
bb-------123
cc-------123
TreeMap
要求key必须是同一个类创建的对象
因为是按照key进行排序,所以要在key对象的类里重写CompareTo方法自然排序
或者在当前类里实现comparable接口,重写定制排序
不能按照value排序
public void test2(){
TreeMap map = new TreeMap();
User u1 =new User(10,"wpx");
User u2 =new User(15,"tom");
User u3 =new User(12,"anndy");
map.put(u1,50);
map.put(u2,50);
map.put(u3,50);
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
Map.Entry entry = (Map.Entry) o;
System.out.println(entry.getKey()+"成绩"+entry.getValue());
}
}
Collections 工具类
sort(list)根据其元素的自然排序对指定的列表进行排序
sort( list, Comparator)`根据指定的比较器引起的顺序对指定的列表进行排序。
swap(List, int i, int j)` 交换指定列表中指定位置的元素
frequency(Collection, Object o)返回指定集合中与指定对象相等的元素数
copy易错点
错误写法,list1没有空间 ,会报错
List list1 = new ArrayList();
Collections.copy(list1,list);
正确写法 new Object 数组 ,数组里填入 要复制的size();
使用Arrays.asList方法返回这个数组并保存新数组中
List dest = Arrays.asList(new Object[list.size()]);
Collections.copy(dest,list);
System.out.println(dest);
replaceAll(List<T> list, oldVal, newVal)
将列表中一个指定值的所有出现替换为另一个。
List list2 = Collections.synchronizedList(list);返回一个线程安全的list
Map Set 同理 但是线程不安全的list等必须在方法体里声明,作用域不同