数组在使用时:
1.要定义容器的大小,超了直接报异常
2.数组操作的方法很少,没有专门的封装方法
3.数据类型也比较单一
期望有一个java方式,把之前讲的操作数组的方法封装到一起,供程序员使用。
Collection集合【它是一个接口】完成了一系列增删改查的操作
Collection java中所有集合的总接口
–|List 是Collection下面的子接口【特征:无序的,不可重复的】
–|--|ArrayList【重点】是可变长的数组容器,它是一个类,它的爷爷是List 它爷爷的爸爸是Collection。
–|--|LinkedList 链表数组
–|--|Vector安全版本的ArrayList
–|Set 也是Collection下面子接口【特征:无序的,不可重复的】
–|--|HashSet 底层是个hash表
–|--|TreeSet底层是二叉树
增: boolean add(E e)添加指定元素到Collection集合中,采用尾插法 boolean addAll(Collection<? extends E> c)添加一个集合到另一个集合中 删: remove(Object o)删除集合中指定的元素 removeAll(Collection <?> c)删除两个集合中交集 retainAll(Collection<?> c)保留两个集合的交集 clear()清空集合 查: int size()获取集合中元素的个数 Object[] toArray() 返回整个集合中所有元素的Object类型的数组 boolean contains(Object o)判断指定元素是否在当前集合中 boolean containsAll(Collection<?> c)判断指定集合是否是当前集合子集合 boolean isEmpty()
【特别注意】Collection是一个接口,没有实例化对象,应采用多态的思想进行实例化
获取迭代器对象:
通过集合对象获取迭代器
Iterator iterator();
常用方法:
boolean hasNext()判断是否可继续遍历
Object next()获取当前迭代器指向的元素,并且指向下一个元素
void remove()删除
List是Collection的子接口,意味着Collection下面的所有方法,List都是可以使用的,并且还可以有自己的方法
【List特点:有序的可重复的】
增: add(int index,E e)指定下标添加元素 addAll(int index,Collection<? extends E> c)在指定下标位置添加另一个集合 删: remove(int index)删除指定下标的元素 改: E set(int index,E e)依据指定下标,替换指定下标元素 查: E get(int index)获取指定下标元素 int indexOf(Object obj)查找指定元素的下标位置 int lastIndexOf(Object obj)查找指定元素最后一次出现的位置 List<E> SubList(int startIndex,int endIndex)获取子List集合
ListIterator
获取方式:ListIterator listIterator();
常用方法:
boolean hasNext();
E next();
void remove();
void add(E e);在迭代器中添加数据。【注意】是根据迭代器的指针指向进行添加的
void set(E e);修改当前迭代器指向位置的那个元素
public class Demo2 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("红旗渠"); list.add("散花"); list.add("荷花"); list.add("利群"); list.add("华子"); ListIterator<String> it = list.listIterator(); System.out.println(it.hasNext());//true System.out.println(it.next());//红旗渠 System.out.println(it.nextIndex());//1s下一个的元素的索引 it.add("牡丹"); System.out.println(list); System.out.println(it.next());//牡丹 System.out.println(it.next());//散花 System.out.println(it.next());//h荷花 it.set("芙蓉王"); System.out.println(list); /*增强for循环*/ for (String s : list) { System.out.println(s); } } }
调用ArrayList无参构造方法,是没有传容量的。底层是一个数组
底层是数组
初始化值是10,因为在ArrayList中私有化的静态的使用final修饰成员变量
private static final int DEFAULT_CAPACITY = 10;
默认的是10,如果添加数据超过了10,进行扩容。让其容量自增1,
ArrayList特征:增删慢,查找快
增加慢:
1、添加数据的时候,可能涉及到数组的扩容,这里涉及使用数组copy问题
2、想要在指定位置添加数据,会导致添加位置及以后的数组元素后移
删除慢:
删除元素后,会有删除位置及以后的元素向前移动
查找快:
int [ ] arr = new int[10];
arr是数组的名字,同时也是一个引用数据类型的变量,该变量保存的数据时当前数组在内存中的首地址。cpu通过内存首地址进行查询这个效率是十分高的,ArrayList就是把数组名+索引方式进行访问的,就是变相通过内存首地址进行查询,所以效率高
ArrayList应用场景:
对于数据查询需求比较大,但对数据的增删需求少的,比较适合使用
如:图书馆,人力管理系统…
也是实现了接口List,兄弟是ArrayList,以链表的形式进行数据存储
boolean addFirst(E e)在第一个位置添加一个元素 boolean addLast(E e)在最后一个位置添加一个元素 E getFirst()获取第一个元素 E getLast()获取最后一个元素 removeLast()删除最后一个元素 removeFirst()移除第一个元素
Object类是所有类的基类
boolean equals(Object obj);比较两个对象是否相等的方法
根本的比较方式:比较两个内存首地址是否相等,如果相等就返回true,如果不相等就返回false和String里的比较方法是完全不一样的。
toString();返回的是类的字符串表示形式
int hashCode(); 返回对象的hash码值
Object类的hashCode方法返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样 ,所以哈希码也不一样。
【规定】java中规定,如果equals方法比较两个对象的话,如果两个对象相等,就意味着内存地址相等,如果内存地址相等,hash码必须相等
【面试题】重写equals方法,比较两个对象是否相等(主观意愿上的相等,就是内容相等即可,没必要内存地址也相等)
【面试题】
String类下==和equals的区别:==是比较内存地址,equals比较的是内容
Object类下equals比较的是内存地址(hash码值)
java中有如下规定
两个对象相等,hashCode一定相等
两个对象不等,hashCode不一定不等
hashCode相等,两个对象不一定相等
hashCode不等,两个对象一定不等
package com.qfedu.a_Object; public class Person { private int id; private String name; @Override public boolean equals(Object obj) { /** * this是当前的类对象 obj是传入过来的对象 * 调用当前equals方法,如果传入的对象和当前对象的地址一样,就证明是同一个对象 * 这是比较严格的比较 */ if (this==obj){ return true; } /** * 如果不是同一个对象,就需要比较对象的数据内容 * 按照目前的情况,若名字相同,id也相同是一个对象 * 必须强制类型转换 */ Person p = (Person)obj; /** * id相等 用==比较 * name是一个字符串,需要用equals进行比较 */ return p.id == this.id && p.name.equals(this.name); } /** * 重写hashCode方法,把id当成hash值 * @return */ @Override public int hashCode() { return id; } /** * 重写toString() Object下面的方法 */ public Person() { } public Person(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + '}'; } } package com.qfedu.a_Object; public class Demo { public static void main(String[] args) { Person p1 = new Person(1, "红孩儿"); Person p2 = new Person(1, "红孩儿"); System.out.println(p1.equals(p2)); /** * 1:这两个对象不是同一个对象。因为是通过new关键字new出来的,所以内存地址不一样 * 2:这两个对象保存的数据时一样的,从主观意愿上来说是同一个对象 */ System.out.println(p1.hashCode()); System.out.println(p2.hashCode()); } }
Collection下面有两个子接口:
List:ArrayList LinkedList Vector 可重复的,有序的
Set:不可重复的,无序的
Set接口下面没有独特的方法,可以完全使用Collection下面的方法
–|HashSet底层是一个hash表,存储效率十分高
–|TreeSet底层是一个树状结构,要求保存的数据必须是有顺序的,自然顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CW0UgQYR-1627902881225)(C:\Users\22564\AppData\Roaming\Typora\typora-user-images\image-20210405104650206.png)]
【由图像可知】这是不符合规范的,因为Set集合中存的对象确实是两个内存地址不同的对象,但内容确实一致的。
解决方案:1.重写hashCode方法 2.必须重写equals方法 【缺一不可】
1.如果没有重写hashCode和equals方法。只比较hash值是否相等,两个对象两个内存地址,两个hash值,就直接判定是不同的,就可以写进set集合中了
2.如果重写了hashCode方法没有重写equals方法。如果hash值一样,当时物理地址不一样。还是可以存到set集合中的。
3.如果重写了equals方法没有重写hashCode方法,hash值还是不一样的,直接判断hashCode方法,不调用equals方法
4.如果写了hashCode方法和equals方法,不看物理地址,直接比较hash值和内容,如果相等就存一个。
Map和Collection没有关系,Map是双边队列(成双成对)Map(K,V)
(key,value)键是唯一的,一个键只能对应一个数据。值可以是相等的,对应多个键。
a====>1
b====>2
–|HashMap<K,V>底层是一个hash表,存储的就是当前键值对的key(意味着你的键值不能重复)
–|TreeMap<K,V>底层是一个二叉树,比较存储数据的时候,参考也是key值
增: put(K key,V value) putAll(Map<? extends K,? extends v>)参数是一个对应好的map集合,k和v泛型一定和被存入map集合保持一致 删: remove(Object key)通过对应的键值删除value值 改: put(K key,V value)若key存在,修改对应的value,如果不存在就添加 查: int size()有效键值对的个数 boolean isEmpty() boolean containsKey(Object key)在map集合中是否包含key boolean containsValue(Object value)在map集合中是否包含value Set<K> keySet()获取当前map集合所有的key存储在set集合中 Collection<V> values()获取集合中的value值 V get(Object key)通过键值获取value值
package com.qfedu.a_map; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author wangbo * @version 1.0 * @date 2021/3/17 10:01 */ public class Demo1 { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); //map.put("烤羊排", "168"); map.put("烤羊排", "167"); map.put("烤鲶鱼", "58"); map.put("烤乳猪", "589"); map.put("烤骆驼", "18888"); System.out.println(map); Map<String, String> map1 = new HashMap<>(); //map.put("烤羊排", "168"); map1.put("麻辣小龙虾", "167"); map1.put("佛跳墙", "58"); System.out.println(map1); map.putAll(map1); System.out.println(map); map.remove("佛跳墙"); System.out.println(map); //修改 map.put("烤乳猪", "689"); System.out.println(map); //查 System.out.println(map.size());//5 System.out.println(map.isEmpty());//false System.out.println(map.containsKey("烤羊排"));//true System.out.println(map.containsValue("58"));//true Set<String> strings = map.keySet(); //遍历出来键 for (String string : strings) { System.out.println(string); } Collection<String> values = map.values(); for (String value : values) { System.out.println(value); } System.out.println(map.get("麻辣小龙虾")); } }