集合:用于存储、获取、操作对象的容器 数组的不好处:数组的长度不可变
集合的特点: 1、集合的长度是可变的 2、集合中可以存储是任意类型的对象且只能存储对象
Collection接口:java.util.Collection ? ? ? ? ?Collection 接口是 List、Set 和 Queue 接口的父接口 Collection接口中的方法:
boolean add(E e) ;//向集合中添加元素
int size() ?;//获取集合中有效元素个数
void clear() ?;//清空集合
isEmpty();//判断集合是否为空
addAll(Collection coll);//将coll所有元素们一个一个加进去
contains();//判断集合中是否某个元素是否存在,依据是equals
containsAll();?跟顺序有关吗,无关//
remove();//要删除先判断有没有,contains
removeAll();//删除的是俩个集合的交集
retainAll();//取得是俩个集合的交集
toArray();将集合转数组
@Test
public void testA() {
//将数组转集合
Collection c1 = Arrays.asList(1, 2, 3, 4, 5, 6);
Collection c2 = Arrays.asList(6, 3, 1);
//如果此 c1 包含指定 c2 中的所有元素,则返回 true。
System.out.println(c1.containsAll(c2));
}
List接口: 有序[因为list集合具有索引值]? ?/? ?且可重复的。有序的意思是存进去的顺序和取出来的顺序是一样的。 List接口在Collection接口上增加了一些根据元素索引来操作集合的特有方法
Arrays.asList(…) 方法返回的 List 集合既不是 ArrayList 实例,也不是 Vector 实例而是Arrays的内部类ArrayList
void add(int index, Object ele)
boolean addAll(int index, Collection eles)
Object get(int index);获取指定
int indexOf(Object obj)//从前往后找指定元素的索引值,找不到返回-1
int lastIndexOf(Object obj);//从后往前找
Object remove(int index);//按照指定索引删除。和Collection接口的按照元素删构成重载,删除指定位置元素 返回被删除元素
Object set(int index, Object ele);//替换指定索引元素,返回替换前的元素
List subList(int fromIndex, int toIndex)//截取子集合,左闭右开
List接口的实现类ArrayList: ArrayList:底层就是很好的封装了数组,采用数组结构存储,适用于查询多的 1.利用ArrayList()默认数组长度
- jdk1.7,数组长度10;
- jdk1.8,数组长度0【默认{}】,做任何小操作则数组长度变为10。
ArrayList(int initialCapacity) 也可以通过有参构造器指定数组长度。 2.扩容 以原来容量的1.5倍来扩容。
List接口的实现类LinkedList??:
LinkedList是一个双向链表。前向索引first和后向索引 last。适用于增删操作 LinkedList提供了大量首尾操作的方法
LinkedList特有的方法:
void addFirst(Object obj)
void addLast(Object obj)
Object getFirst()
Object getLast()
Object removeFirst();//移除并返回集合中第一个元素,如果集合为空报异常
Object removeLast();//移除并返回集合中最后一个元素,如果集合为空报异常
在开发时,LinkedList集合也可以作为堆栈,队列的结构使用
public class SylQueue {
//底层使用LinkedList封装Queue
LinkedList ll=new LinkedList();
public SylQueue() {
}
//添加
public void add(Object obj){
ll.addFirst(obj);
}
//获取
public Object get(){
// return ll.removeFirst();//达成后进先出的堆栈效果
return ll.removeLast();//达成后进后出的队列效果
}
//判断
public boolean isNull(){
return ll.isEmpty();
}
public String getAll(){
return ll.toString();
}
}
public class ExceptionTest {
@Test
public void testA() {
SylQueue sylQueue = new SylQueue();
sylQueue.add("a");
sylQueue.add("b");
sylQueue.add("c");
sylQueue.add("d");
sylQueue.add("e");
String all = sylQueue.getAll();
System.out.println(all);
System.out.println("=================");
Object o = sylQueue.get();
String all2 = sylQueue.getAll();
System.out.println(all2);
System.out.println("=================");
}
}
问题3: LinkedList中get(index i)和数组有啥区别【源码】 index i <.size(),从前往后找,反之从后往前找。
java.util.Set:无序不可重复的。
set集合里的元素是无序不可重复的,且set集合没有下标这个说法。
Set接口实现类: HashSet:是一个set接口的典型实现类【jdk1.7 底层:数组+链表】
? ?LinkedHashSet
TreeSet
HashSet 具有以下特点:
- 不能保证元素的排列顺序
- HashSet 不是线程安全的
- 集合元素可以是 null
一个有意思关于set集合元素不可以重复的Demo
生成一个Person类,嗯。。完全生成的,没有技术含量
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(age, person.age);
}
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ExceptionTest {
@Test
public void testA() {
Set set = new HashSet();
set.add(new String("苹果"));
set.add(new String("苹果"));
set.add(new Person("zhangsan",18));
set.add(new Person("zhangsan",18));
System.out.println(set);
}
}
当Person类没有重写hashCode方法的时候,上面代码输出
?Person类重写了hashCode()之后,输出结果如下:
总结: 1、HashSet为什么不用equals? ? ? ?要是用了则会每次给set集合添加值都会和每一个元素都比较一次,都累死了。
2、调用Object类的hashCode()任何对象都产生一个唯一的哈希码值
3、哈希算法:会将哈希码值变为数组的索引值,hash算法是一种可以从任何数据中提取出其“指纹”的数据摘要算法,它将任意大小的数据映射到一个固定大小的序列上,这个序列被称为hash code。
总的原则:在给set集合存储的时候,俩个对象哈希值是一样的,那他俩一定是一样的
1、那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。 如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式
2.重写的目的:让内容一样的对象不能存到set集合里。 3.重写的规则:当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等。 3.重写hashCode方法是都调这个工具类吗?? ?Objects.hash(name, price);
HashSet集合存储过程:
1.先调用存储对象的hashcode()方法,补重写的话会调用Object中hashcode(),让每一个对象都对应唯一的,此时连equals机会都没。
//Person类不重写HashCode方法的话,调用Object类中的,则下面俩个 Person对象
//即使内容一样,我们不想让它重复存储到set集合,是做不到的。因为不重写会生成俩个哈希码值
set.add(new Person("zhangsan",18));
set.add(new Person("zhangsan",18));
2.重写哈希方法的目的:属性相同,生成的哈希值也相同,同时equals返回true。 3.从哈希码值经过哈希运算到数组之后比较equals()方法,不再使用哈希码值比较了
了解一下!!在调用Object类的toString()时,
打印的字符串:getClass().getName() + '@' + Integer.toHexString(hashCode())//对象哈希码的无符号十六进制
-------------------------------
4、HashSet底层是一个数组,默认长度16。 加载因子:0.75,
扩容原则:【以原来的2倍】
jdk1.8? HashSet又多了一个:数组+链表+红黑树。
红黑树是解决二叉树的平衡问题的。
当链表的长度达到了>=8-1;i并且集合中总元素的个数超过了64,这个链表就会转为红黑树。要不然链表上每一个元素都要和新加的元素equals。有了红黑树就可以顺着hashcode值比较,往下溜。
LinkedHashSet 继承 HashSet 是链表和哈希表组合的一个数据存储结构,相比于HashSet 多了一个链表维护集合中的元素,效率变低了。 LinkedHashSet遍历的时候直接一根列表,可以按添加顺序遍历,且遍历时不用过滤null值。
public class Demo {
public static void main(String[] args) {
LinkedHashSet set = new LinkedHashSet();
set.add(10);
set.add(8);
set.add(1);
set.add(11);
//LinkedHashSet会按照添加顺序遍历
System.out.println(set);
}
}
java.util.TreeSet 底层采用红黑树,有自己指定的排序方式。 2.compareTo,返回正数,0,负数 3.要是不是Person类怎么返回呢,应该是抛出异常吧。在TreeSet中应用的时候返回0可以。 如果返回0,在TreeSet中会视为重复,是对的。 4。为啥compareTo方法形参不不直接写Person 【方法重写】
Collection接口集合实现类的遍历 1.使用增强for循环 【java5提供】
for(元素数据类型 变量名:被遍历的集合){ } 注意:增强for循环不擅长改变数组中的值。
代码案例如下:
?增强for循环 也可以遍历数组【但是要改变数组中某一个值,改不了】
@Test
public void test6() {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(1);
System.out.println(arrayList);//[1,2,1]
for (Integer i : arrayList) {
System.out.println("i="+i);
if(i==2){
i=1;
}
}
System.out.println(arrayList);//[1,2,1]
}
}
结果:
那正确的操作方式呢?
发现,set方法是根据索引去修改值得,在增强for循环里没有索引值,自然也就不能改值了
@Test
public void test6() {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(1);
System.out.println(arrayList);//[1,2,1]
for (int i = 0; i < arrayList.size(); i++) {
if(arrayList.get(i)==2){
//public E set(int index, E element)
arrayList.set(i,1);
}
}
System.out.println(arrayList);//[1,2,1]
}
Collection集合遍历的第二种方式:迭代器
迭代器Iterator
Collection中有一个方法:Iterator ?iterator() ;//返回Iterator的实例,交给迭代器遍历
首先看看迭代器对象的3个方法,真老六啊
- hasNext() ?如果仍有元素可以迭代,返回true
- next() ?返回迭代的下一个元素
- remove() 移除元素
使用迭代器遍历集合是固定写法,如下遍历一个TreeSet
@Test
public void testIter(){
TreeSet set = new TreeSet();
set.add(10);
set.add(8);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
// System.out.println(iterator.next()); 当next()没有值时,NoSuchElementException
}
?
迭代器Iterator进行list集合元素的删除?
在集合结构发生变化时,迭代器必须重新获取,不然当你下一次调next()方法时,会报异常。
俩个remove方法
下图最重要的就是,你在while循环里调用集合自带的remove方法删除元素是不可取的,想在迭代时删除,可以,但你必须用我迭代器自己的remove方法。
ListIterator【列表迭代器】
是List集合特有的迭代器,会多一些方法
1.previous()?//获取前一个元素
2.hasPrevious()//获取前一个元素
map集合的所有操作,可以去看同样的那一篇
2021/11/07 北京 List集合,map集合,Collection集合,set集合_£小羽毛的博客-CSDN博客
|