网店交易平台网站建设青海网站建设公司
web/
2025/10/5 11:25:23/
文章来源:
网店交易平台网站建设,青海网站建设公司,wordpress 显示文章固定链接,国际跨境电商平台排名集合简介
概念#xff1a;对象的容器#xff0c;定义了对多个对象进项操作的的常用方法。可实现数组的功能。和数组的区别#xff1a;
数组长度固定#xff0c;集合长度不固定。数组可以存储基本类型和引用类型#xff0c;集合只能存储引用类型。
位置#xff1a; jav…集合简介
概念对象的容器定义了对多个对象进项操作的的常用方法。可实现数组的功能。和数组的区别
数组长度固定集合长度不固定。数组可以存储基本类型和引用类型集合只能存储引用类型。
位置 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() //姜此集合转换成数组。 COPY/*** Collection接口的使用一* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断*/
public class Demo1{pubic static void main(String[] args){//创建集合Collection collectionnew ArrayList();
// * 1.添加元素Collection.add(苹果);Collection.add(西瓜);Collection.add(榴莲);System.out.println(元素个数collection.size());System.out.println(collection);
// * 2.删除元素collection.remove(榴莲);System.out.println(删除之后collection.size());
// * 3.遍历元素//3.1 使用增强for for(Object object : collection){System.out.println(object);}//3.2 使用迭代器迭代器专门用来遍历集合的一种方式//hasnext();判断是否有下一个元素//next();获取下一个元素//remove();删除当前元素Iterator iteratorcollection.Itertor();while(iterator.hasnext()){String object(String)iterator.next();System.out.println(s);//删除操作//collection.remove(s);引发错误并发修改异常//iterator.remove();应使用迭代器的方法
// * 4.判断System.out.println(collection.contains(西瓜));//trueSystem.out.println(collection.isEmpty());//false}}
}COPY/*** Collection接口的使用二* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断*/
public class Demo2 {public static void main(String[] args) {Collection collectionnew ArrayList();Student s1new Student(张三,18);Student s2new Student(李四, 20);Student s3new Student(王五, 19);//1.添加数据collection.add(s1);collection.add(s2);collection.add(s3);//collection.add(s3);可重复添加相同对象System.out.println(元素个数collection.size());System.out.println(collection.toString());//2.删除数据collection.remove(s1);System.out.println(删除之后collection.size());//3.遍历数据//3.1 增强forfor(Object object:collection) {Student student(Student) object;System.out.println(student.toString());}//3.2迭代器//迭代过程中不能使用collection的删除方法Iterator iteratorcollection.iterator();while (iterator.hasNext()) {Student student(Student) iterator.next();System.out.println(student.toString());}//4.判断和上一块代码类似。}
}COPY/*** 学生类*/
public class Student {private String name;private int age;public Student(String name, int age) {super();this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}Overridepublic String toString() {return Student [name name , age age ];}
}Collection子接口 List集合 特点有序、有下标、元素可以重复。 方法 void add(int index,Object o) //在index位置插入对象o。boolean addAll(index,Collection c) //将一个集合中的元素添加到此集合中的index位置。Object get(int index) //返回集合中指定位置的元素。List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素。 COPY/*** List子接口的使用一* 特点1.有序有下标 2.可以重复* * 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo3 {public static void main(String[] args) {List listnew ArrayList();//1.添加元素list.add(tang);list.add(he);list.add(0,yu);//插入操作System.out.println(元素个数list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove(yu);结果同上System.out.println(删除之后list.size());System.out.println(list.toString());//3.遍历元素//3.1 使用for遍历for(int i0;ilist.size();i) {System.out.println(list.get(i));}//3.2 使用增强forfor(Object object:list) {System.out.println(object);}//3.3 使用迭代器Iterator iteratorlist.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//3.4使用列表迭代器listIterator可以双向遍历添加、删除及修改元素。ListIterator listIteratorlist.listIterator();//从前往后while (listIterator.hasNext()) {System.out.println(listIterator.next()); }//从后往前此时“遍历指针”已经指向末尾while(listIterator.hasPrevious()) {System.out.println(listIterator.previous());}//4.判断System.out.println(list.isEmpty());System.out.println(list.contains(tang));//5.获取位置System.out.println(list.indexOf(tang));}
}COPY/*** List子接口的使用二* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo4 {public static void main(String[] args) {List listnew ArrayList();//1.添加数字数据自动装箱list.add(20);list.add(30);list.add(40);list.add(50);System.out.println(元素个数list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove(20);很明显数组越界错误改成如下//list.remove(Object(20));//list.remove(new Integer(20));System.out.println(元素个数list.size());System.out.println(list.toString());//3-5不再演示与之前类似//6.补充方法subList返回子集合含头不含尾List list2list.subList(1, 3);System.out.println(list2.toString()); }
}List实现类
ArrayList[重点]
数组结构实现查询块、增删慢JDK1.2版本运行效率快、线程不安全。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqGEjbf9-1614751593954)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210228215642063.png)]
COPY/*** ArrayList的使用* 存储结构数组* 特点查找遍历速度快增删慢。* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.查找*/
public class Demo5 {public static void main(String[] args) {ArrayList arrayListnew ArrayList();//1.添加元素Student s1new Student(唐, 21);Student s2new Student(何, 22);Student s3new Student(余, 21);arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);System.out.println(元素个数arrayList.size());System.out.println(arrayList.toString());//2.删除元素arrayList.remove(s1);//arrayList.remove(new Student(唐, 21));//注这样可以删除吗不可以显然这是两个不同的对象。//假如两个对象属性相同便认为其是同一对象那么如何修改代码//3.遍历元素//3.1使用迭代器Iterator iteratorarrayList.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}//3.2使用列表迭代器ListIterator listIteratorarrayList.listIterator();//从前往后遍历while(listIterator.hasNext()) {System.out.println(listIterator.next());}//从后往前遍历while(listIterator.hasPrevious()) {System.out.println(listIterator.previous());}//4.判断System.out.println(arrayList.isEmpty());//System.out.println(arrayList.contains(new Student(何, 22)));//注与上文相同的问题。//5.查找System.out.println(arrayList.indexOf(s1));}
}注Object里的equals(thisobj)用地址和当前对象比较如果想实现代码中的问题可以在学生类中重写equals方法
COPYOverride
public boolean equals(Object obj) {//1.是否为同一对象if (thisobj) {return true;}//2.判断是否为空if (objnull) {return false;}//3.判断是否是Student类型if (obj instanceof Student) {Student student(Student) obj;//4.比较属性if(this.name.equals(student.getName())this.agestudent.age) {return true;}}//不满足返回falsereturn false;
}ArrayList源码分析 默认容量大小private static final int DEFAULT_CAPACITY 10; 存放元素的数组transient Object[] elementData; 实际元素个数private int size; 创建对象时调用的无参构造函数 COPY//这是一个空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA {};
public ArrayList() {this.elementData DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}这段源码说明当你没有向集合中添加任何元素时集合容量为0。那么默认的10个容量怎么来的呢 这就得看看add方法的源码了 COPYpublic boolean add(E e) {ensureCapacityInternal(size 1); // Increments modCount!!elementData[size] e;return true;
}假设你new了一个数组当前容量为0size当然也为0。这时调用add方法进入到ensureCapacityInternal(size 1);该方法源码如下 COPYprivate void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}该方法中的参数minCapacity传入的值为size1也就是 1接着我们再进入到calculateCapacity(elementData, minCapacity)里面 COPYprivate static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}上文说过elementData就是存放元素的数组当前容量为0if条件成立返回默认容量DEFAULT_CAPACITY也就是10。这个值作为参数又传入ensureExplicitCapacity()方法中进入该方法查看源码 COPYprivate void ensureExplicitCapacity(int minCapacity) {modCount;// overflow-conscious codeif (minCapacity - elementData.length 0)grow(minCapacity);
}我们先不要管modCount这个变量。 因为elementData数组长度为0所以if条件成立调用grow方法重要的部分来了我们再次进入到grow方法的源码中 COPYprivate void grow(int minCapacity) {// overflow-conscious codeint oldCapacity elementData.length;int newCapacity oldCapacity (oldCapacity 1);if (newCapacity - minCapacity 0)newCapacity minCapacity;if (newCapacity - MAX_ARRAY_SIZE 0)newCapacity hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData Arrays.copyOf(elementData, newCapacity);
}这个方法先声明了一个oldCapacity变量将数组长度赋给它其值为0又声明了一个newCapacity变量其值为oldCapacity一个增量可以发现这个增量是和原数组长度有关的量当然在这里也为0。第一个if条件满足newCapacity的值为10这就是默认的容量不理解的话再看看前面。第二个if条件不成立也可以不用注意因为MAX_ARRAY_SIZE的定义如下 COPYprivate static final int MAX_ARRAY_SIZE Integer.MAX_VALUE - 8;这个值太大了以至于第二个if条件没有了解的必要。 最后一句话就是为elementData数组赋予了新的长度Arrays.copyOf()方法返回的数组是新的数组对象原数组对象不会改变该拷贝不会影响原来的数组。copyOf()的第二个自变量指定要建立的新数组长度如果新数组的长度超过原数组的长度则保留数组默认值。 这时候再回到add的方法中接着就向下执行elementData[size] e;到这里为止关于ArrayList就讲解得差不多了当数组长度为10的时候你们可以试着过一下源码查一下每次的增量是多少答案是每次扩容为原来的1.5倍。
Vector 数组结构实现查询快、增删慢 JDK1.0版本运行效率慢、线程安全。 COPY/*** Vector的演示使用* *1.添加数据*2.删除数据*3.遍历*4.判断*/
public class Demo1 {public static void main(String[] args) {Vector vectornew Vector();//1.添加数据vector.add(tang);vector.add(he);vector.add(yu);System.out.println(元素个数vector.size());//2.删除数据/** vector.remove(0); vector.remove(tang);*///3.遍历//使用枚举器Enumeration enumerationvector.elements();while (enumeration.hasMoreElements()) {String s (String) enumeration.nextElement();System.out.println(s);}//4.判断System.out.println(vector.isEmpty());System.out.println(vector.contains(he));//5. Vector其他方法//firstElement() lastElement() ElementAt();}
}LinkedList
链表结构实现增删快查询慢。
COPY/*** LinkedList的用法* 存储结构双向链表* 1.添加元素* 2.删除元素* 3.遍历* 4.判断*/
public class Demo2 {public static void main(String[] args) {LinkedList linkedListnew LinkedList();Student s1new Student(唐, 21);Student s2new Student(何, 22);Student s3new Student(余, 21);//1.添加元素linkedList.add(s1);linkedList.add(s2);linkedList.add(s3);linkedList.add(s3);System.out.println(元素个数linkedList.size());System.out.println(linkedList.toString());//2.删除元素/** linkedList.remove(new Student(唐, 21));* System.out.println(linkedList.toString());*///3.遍历//3.1 使用forfor(int i0;ilinkedList.size();i) {System.out.println(linkedList.get(i));}//3.2 使用增强forfor(Object object:linkedList) {Student student(Student) object;System.out.println(student.toString());}//3.3 使用迭代器Iterator iterator linkedList.iterator();while (iterator.hasNext()) {Student student (Student) iterator.next();System.out.println(student.toString());}//3.4 使用列表迭代器略//4. 判断System.out.println(linkedList.contains(s1));System.out.println(linkedList.isEmpty());System.out.println(linkedList.indexOf(s3));}
}LinkedList源码分析
LinkedList首先有三个属性
链表大小transient int size 0;指向第一个结点/头结点transient NodeE first;指向最后一个结点/尾结点transient NodeE last;
关于Node类型我们再进入到类里看看
COPYprivate static class NodeE {E item;NodeE next;NodeE prev;Node(NodeE prev, E element, NodeE next) {this.item element;this.next next;this.prev prev;}
}首先item存放的是实际数据next指向下一个结点而prev指向上一个结点。
Node带参构造方法的三个参数分别是前一个结点、存储的数据、后一个结点调用这个构造方法时将它们赋值给当前对象。
LinkedList是如何添加元素的呢先看看add方法
COPYpublic boolean add(E e) {linkLast(e);return true;
}进入到linkLast方法
COPYvoid linkLast(E e) {final NodeE l last;final NodeE newNode new Node(l, e, null);last newNode;if (l null)first newNode;elsel.next newNode;size;modCount;
}假设刚开始new了一个LinkedList对象first和last属性都为空调用add进入到linkLast方法。
首先创建一个Node变量 l 将last此时为空赋给它然后new一个newNode变量存储数据并且它的前驱指向l后继指向null再把last指向newNode。如下图所示 如果满足if条件说明这是添加的第一个结点将first指向newNode 至此LinkedList对象的第一个数据添加完毕。假设需要再添加一个数据我们可以再来走一遍过程同上不再赘述图示如下 ArrayList和LinkedList区别
ArrayList必须开辟连续空间查询快增删慢。LinkedList无需开辟连续空间查询慢增删快。 泛型概述
Java泛型是JDK1.5中引入的一个新特性其本质是参数化类型把类型作为参数传递。常见形式有泛型类、泛型接口、泛型方法。语法 T,… T称为类型占位符表示一种引用类型。 好处 提高代码的重用性。防止类型转换异常提高代码的安全性。
泛型类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JNlbroFK-1614751593971)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210301155839838.png)]
COPY/*** 泛型类* 语法类名T* T是类型占位符表示一种引用类型编写多个使用逗号隔开* */
public class myGenericT{//1.创建泛型变量//不能使用new来创建因为泛型是不确定的类型也可能拥有私密的构造方法。T t;//2.泛型作为方法的参数public void show(T t) {System.out.println(t);}//泛型作为方法的返回值public T getT() {return t;}
}
COPY/*** 注意* 1.泛型只能使用引用类型* 2.不同泛型类型的对象不能相互赋值*/
public class testGeneric {public static void main(String[] args) {//使用泛型类创建对象myGenericString myGeneric1new myGenericString();myGeneric1.ttang;myGeneric1.show(he);myGenericInteger myGeneric2new myGenericInteger();myGeneric2.t10;myGeneric2.show(20);Integer integermyGeneric2.getT();}
}泛型接口
COPY/*** 泛型接口* 语法接口名T* 注意不能创建泛型静态常量*/
public interface MyInterfaceT {//创建常量String nameStringtang;T server(T t);
}
COPY/*** 实现接口时确定泛型类*/
public class MyInterfaceImpl implements MyInterfaceString{Overridepublic String server(String t) {System.out.println(t);return t; }
}
COPY//测试
MyInterfaceImpl myInterfaceImplnew MyInterfaceImpl();
myInterfaceImpl.server(xxx);
//xxx
COPY/*** 实现接口时不确定泛型类*/
public class MyInterfaceImpl2T implements MyInterfaceT{Overridepublic T server(T t) {System.out.println(t);return t;}
}
COPY//测试
MyInterfaceImpl2Integer myInterfaceImpl2new MyInterfaceImpl2Integer();
myInterfaceImpl2.server(2000);
//2000泛型方法
COPY/*** 泛型方法* 语法T 返回类型*/
public class MyGenericMethod {public T void show(T t) {System.out.println(泛型方法t);}
}
COPY//测试
MyGenericMethod myGenericMethodnew MyGenericMethod();
myGenericMethod.show(tang);
myGenericMethod.show(200);
myGenericMethod.show(3.14);泛型集合 概念参数化类型、类型安全的集合强制集合元素的类型必须一致。 特点 编译时即可检查而非运行时抛出异常。访问时不必类型转换拆箱。不同泛型指尖引用不能相互赋值泛型不存在多态。
之前我们在创建LinkedList类型对象的时候并没有使用泛型但是进到它的源码中会发现
COPYpublic class LinkedListEextends AbstractSequentialListEimplements ListE, DequeE, Cloneable, java.io.Serializable{//略}它是一个泛型类而我之前使用的时候并没有传递说明java语法是允许的这个时候传递的类型是Object类虽然它是所有类的父类可以存储任意的类型但是在遍历、获取元素时需要原来的类型就要进行强制转换。这个时候就会出现一些问题假如往链表里存储了许多不同类型的数据在强转的时候就要判断每一个原来的类型这样就很容易出现错误。 Set集合概述
Set子接口
特点无序、无下标、元素不可重复。方法全部继承自Collection中的方法。
COPY/*** 测试Set接口的使用* 特点1.无序没有下标2.重复* 1.添加数据* 2.删除数据* 3.遍历【重点】* 4.判断*/
public class Demo1 {public static void main(String[] args) {SetString setnew HashSetString();//1.添加数据set.add(tang);set.add(he);set.add(yu);System.out.println(数据个数set.size());System.out.println(set.toString());//无序输出//2.删除数据/** set.remove(tang); System.out.println(set.toString());*///3.遍历【重点】//3.1 使用增强forfor (String string : set) {System.out.println(string);}//3.2 使用迭代器IteratorString iteratorset.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//4.判断System.out.println(set.contains(tang));System.out.println(set.isEmpty());}
}Set实现类
HashSet【重点】
基于HashCode计算元素存放位置。当存入元素的哈希码相同时会调用equals进行确认如结果为true则拒绝后者存入。
COPY/*** 人类*/
public class Person {private String name;private int age;public Person(String name,int age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}Overridepublic String toString() {return Peerson [name name , age age ];}
}
COPY/*** HashSet集合的使用* 存储结构哈希表数组链表红黑树* 1.添加元素* 2.删除元素* 3.遍历* 4.判断
*/
public class Demo3 {public static void main(String[] args) {HashSetPerson hashSetnew HashSet();Person p1new Person(tang,21);Person p2new Person(he, 22);Person p3new Person(yu, 21);//1.添加元素hashSet.add(p1);hashSet.add(p2);hashSet.add(p3);//重复添加失败hashSet.add(p3);//直接new一个相同属性的对象依然会被添加不难理解。//假如相同属性便认为是同一个对象怎么修改hashSet.add(new Person(yu, 21));System.out.println(hashSet.toString());//2.删除元素hashSet.remove(p2);//3.遍历//3.1 增强forfor (Person person : hashSet) {System.out.println(person);}//3.2 迭代器IteratorPerson iteratorhashSet.iterator();while (iterator.hasNext()) {System.out.println(iterator.next()); }//4.判断System.out.println(hashSet.isEmpty());//直接new一个相同属性的对象结果输出是false不难理解。//注假如相同属性便认为是同一个对象该怎么做System.out.println(hashSet.contains(new Person(tang, 21)));}
}注hashSet存储过程
根据hashCode计算保存的位置如果位置为空则直接保存否则执行第二步。执行equals方法如果方法返回true则认为是重复拒绝存储否则形成链表。
存储过程实际上就是重复依据要实现“注”里的问题可以重写hashCode和equals代码
COPYOverride
public int hashCode() {final int prime 31;int result 1;result prime * result age;result prime * result ((name null) ? 0 : name.hashCode());return result;
}
Override
public boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Person other (Person) obj;if (age ! other.age)return false;if (name null) {if (other.name ! null)return false;} else if (!name.equals(other.name))return false;return true;
}hashCode方法里为什么要使用31这个数字大概有两个原因
31是一个质数这样的数字在计算时可以尽量减少散列冲突。可以提高执行效率因为31*i(i5)-i31乘以一个数可以转换成移位操作这样能快一点但是也有网上一些人对这两点提出质疑。 TreeSet
基于排序顺序实现不重复。实现了SortedSet接口对集合元素自动排序。元素对象的类型必须实现Comparable接口指定排序规则。通过CompareTo方法确定是否为重复元素。
COPY/*** 使用TreeSet保存数据* 存储结构红黑树* 要求元素类必须实现Comparable接口compareTo方法返回0认为是重复元素 */
public class Demo4 {public static void main(String[] args) {TreeSetPerson personsnew TreeSetPerson();Person p1new Person(tang,21);Person p2new Person(he, 22);Person p3new Person(yu, 21);//1.添加元素persons.add(p1);persons.add(p2);persons.add(p3);//注直接添加会报类型转换错误需要实现Comparable接口System.out.println(persons.toString());//2.删除元素persons.remove(p1);persons.remove(new Person(he, 22));System.out.println(persons.toString());//3.遍历略//4.判断System.out.println(persons.contains(new Person(yu, 21)));}
}查看Comparable接口的源码发现只有一个compareTo抽象方法在人类中实现它
COPYpublic class Person implements ComparablePerson{Override//1.先按姓名比//2.再按年龄比public int compareTo(Person o) {int n1this.getName().compareTo(o.getName());int n2this.age-o.getAge();return n10?n2:n1;}
}除了实现Comparable接口里的比较方法TreeSet也提供了一个带比较器Comparator的构造方法使用匿名内部类来实现它
COPY/*** TreeSet的使用* Comparator实现定制比较比较器*/
public class Demo5 {public static void main(String[] args) {TreeSetPerson personsnew TreeSetPerson(new ComparatorPerson() {Overridepublic int compare(Person o1, Person o2) {// 先按年龄比较// 再按姓名比较int n1o1.getAge()-o2.getAge();int n2o1.getName().compareTo(o2.getName());return n10?n2:n1;} });Person p1new Person(tang,21);Person p2new Person(he, 22);Person p3new Person(yu, 21);persons.add(p1);persons.add(p2);persons.add(p3);System.out.println(persons.toString());}
}接下来我们来做一个小案例
COPY/*** 要求使用TreeSet集合实现字符串按照长度进行排序* helloworld tangrui hechengyang wangzixu yuguoming* Comparator接口实现定制比较*/
public class Demo6 {public static void main(String[] args) {TreeSetString treeSetnew TreeSetString(new ComparatorString() {Override//先比较字符串长度//再比较字符串public int compare(String o1, String o2) {int n1o1.length()-o2.length();int n2o1.compareTo(o2);return n10?n2:n1;} });treeSet.add(helloworld);treeSet.add(tangrui);treeSet.add(hechenyang);treeSet.add(yuguoming);treeSet.add(wangzixu);System.out.println(treeSet.toString());//输出[tangrui, wangzixu, yuguoming, hechenyang, helloworld]}
}Map集合概述
Map体系集合 Map接口的特点 用于存储任意键值对(Key-Value)。键无序、无下标、不允许重复唯一。值无序、无下标、允许重复。 特点存储一对数据Key-Value无序、无下标键不可重复。 方法 V put(K key,V value)//将对象存入到集合中关联键值。key重复则覆盖原值。 Object get(Object key)//根据键获取相应的值。 SetK//返回所有的key CollectionV values()//返回包含所有值的Collection集合。 SetMap.EntryK,V//键值匹配的set集合 COPY/*** Map接口的使用* 特点1.存储键值对 2.键不能重复值可以重复 3.无序*/
public class Demo1 {public static void main(String[] args) {MapString,Integer mapnew HashMapString, Integer();//1.添加元素map.put(tang, 21);map.put(he, 22);map.put(fan, 23);System.out.println(map.toString());//2.删除元素map.remove(he);System.out.println(map.toString());//3.遍历//3.1 使用keySet();for (String key : map.keySet()) {System.out.println(key map.get(key));}//3.2 使用entrySet();效率较高for (Map.EntryString, Integer entry : map.entrySet()) {System.out.println(entry.getKey() entry.getValue());}}
}Map集合的实现类
HashMap【重点】 JDK1.2版本线程不安全运行效率快允许用null作为key或是value。 COPY/*** 学生类*/public class Student {private String name;private int id; public Student(String name, int id) {super();this.name name;this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getId() {return id;}public void setId(int id) {this.id id;}Overridepublic String toString() {return Student [name name , age id ];}}COPY/*** HashMap的使用* 存储结构哈希表数组链表红黑树*/public class Demo2 {public static void main(String[] args) {HashMapStudent, String hashMapnew HashMapStudent, String();Student s1new Student(tang, 36);Student s2new Student(yu, 101);Student s3new Student(he, 10);//1.添加元素hashMap.put(s1, 成都);hashMap.put(s2, 杭州);hashMap.put(s3, 郑州);//添加失败但会更新值hashMap.put(s3,上海);//添加成功不过两个属性一模一样//注假如相同属性便认为是同一个对象怎么修改hashMap.put(new Student(he, 10),上海);System.out.println(hashMap.toString());//2.删除元素hashMap.remove(s3);System.out.println(hashMap.toString());//3.遍历//3.1 使用keySet()遍历for (Student key : hashMap.keySet()) {System.out.println(key hashMap.get(key));}//3.2 使用entrySet()遍历for (EntryStudent, String entry : hashMap.entrySet()) {System.out.println(entry.getKey() entry.getValue());}//4.判断//注同上System.out.println(hashMap.containsKey(new Student(he, 10)));System.out.println(hashMap.containsValue(成都));}}注和之前说过的HashSet类似重复依据是hashCode和equals方法重写即可 COPYOverridepublic int hashCode() {final int prime 31;int result 1;result prime * result id;result prime * result ((name null) ? 0 : name.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Student other (Student) obj;if (id ! other.id)return false;if (name null) {if (other.name ! null)return false;} else if (!name.equals(other.name))return false;return true;}HashMap源码分析 默认初始化容量static final int DEFAULT_INITIAL_CAPACITY 1 4; // aka 16 数组最大容量static final int MAXIMUM_CAPACITY 1 30; 默认加载因子static final float DEFAULT_LOAD_FACTOR 0.75f; 链表调整为红黑树的链表长度阈值JDK1.8static final int TREEIFY_THRESHOLD 8; 红黑树调整为链表的链表长度阈值JDK1.8static final int UNTREEIFY_THRESHOLD 6; 链表调整为红黑树的数组最小阈值JDK1.8static final int MIN_TREEIFY_CAPACITY 64; HashMap存储的数组transient NodeK,V[] table; HashMap存储的元素个数transient int size; 默认加载因子是什么 就是判断数组是否扩容的一个因子。假如数组容量为100如果HashMap的存储元素个数超过了100*0.7575那么就会进行扩容。 链表调整为红黑树的链表长度阈值是什么 假设在数组中下标为3的位置已经存储了数据当新增数据时通过哈希码得到的存储位置又是3那么就会在该位置形成一个链表当链表过长时就会转换成红黑树以提高执行效率这个阈值就是链表转换成红黑树的最短链表长度 红黑树调整为链表的链表长度阈值是什么 当红黑树的元素个数小于该阈值时就会转换成链表。 链表调整为红黑树的数组最小阈值是什么 并不是只要链表长度大于8就可以转换成红黑树在前者条件成立的情况下数组的容量必须大于等于64才会进行转换。 HashMap的数组table存储的就是一个个的NodeK,V类型很清晰地看到有一对键值还有一个指向next的指针以下只截取了部分源码 COPYstatic class NodeK,V implements Map.EntryK,V {final K key;V value;NodeK,V next;}之前的代码中在new对象时调用的是HashMap的无参构造方法进入到该构造方法的源码查看一下 COPYpublic HashMap() {this.loadFactor DEFAULT_LOAD_FACTOR; // all other fields defaulted}发现没什么内容只是赋值了一个默认加载因子而在上文我们观察到源码中table和size都没有赋予初始值说明刚创建的HashMap对象没有分配容量并不拥有默认的16个空间大小这样做的目的是为了节约空间此时table为nullsize为0。 当我们往对象里添加元素时调用put方法 COPYpublic V put(K key, V value) {return putVal(hash(key), key, value, false, true);}put方法把key和value传给了putVal同时还传入了一个hash(Key)所返回的值这是一个产生哈希值的方法再进入到putVal方法部分源码 COPYfinal V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {NodeK,V[] tab; NodeK,V p; int n, i;if ((tab table) null || (n tab.length) 0)n (tab resize()).length;if ((p tab[i (n - 1) hash]) null)tab[i] newNode(hash, key, value, null);else{//略}}这里面创建了一个tab数组和一个Node变量p第一个if实际是判断table是否为空而我们现在只关注刚创建HashMap对象时的状态此时tab和table都为空满足条件执行内部代码这条代码其实就是把resize()所返回的结果赋给tabn就是tab的长度resize顾名思义就是重新调整大小。查看resize()源码部分 COPYfinal NodeK,V[] resize() {NodeK,V[] oldTab table;int oldCap (oldTab null) ? 0 : oldTab.length;int oldThr threshold;if (oldCap 0);else if (oldThr 0);else { // zero initial threshold signifies using defaultsnewCap DEFAULT_INITIAL_CAPACITY;newThr (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);} SuppressWarnings({rawtypes,unchecked})NodeK,V[] newTab (NodeK,V[])new Node[newCap];table newTab;return newTab;}该方法首先把table及其长度赋值给oldTab和oldCapthreshold是阈值的意思此时为0所以前两个if先不管最后else里newCap的值为默认初始化容量16往下创建了一个newCap大小的数组并将其赋给了table刚创建的HashMap对象就在这里获得了初始容量。然后我们再回到putVal方法第二个if就是根据哈希码得到的tab中的一个位置是否为空为空便直接添加元素此时数组中无元素所以直接添加。至此HashMap对象就完成了第一个元素的添加。当添加的元素超过16*0.7512时就会进行扩容 COPYfinal V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){if (size threshold)resize();}扩容的代码如下部分 COPYfinal NodeK,V[] resize() {int oldCap (oldTab null) ? 0 : oldTab.length;int newCap;if (oldCap 0) {if (oldCap MAXIMUM_CAPACITY) {//略}else if ((newCap oldCap 1) MAXIMUM_CAPACITY oldCap DEFAULT_INITIAL_CAPACITY)}}核心部分是else if里的移位操作也就是说每次扩容都是原来大小的两倍。 注*额外说明的一点是在JDK1.8以前链表是头插入JDK1.8以后链表是尾插入。 HashSet源码分析
了解完HashMap之后再回过头来看之前的HashSet源码为什么放在后面写你们看一下源码就知道了部分
COPYpublic class HashSetEextends AbstractSetEimplements SetE, Cloneable, java.io.Serializable{private transient HashMapE,Object map;private static final Object PRESENT new Object();public HashSet() {map new HashMap();}}可以看见HashSet的存储结构就是HashMap那它的存储方式是怎样的呢可以看一下add方法
COPYpublic boolean add(E e) {return map.put(e, PRESENT)null;}很明了地发现它的add方法调用的就是map的put方法把元素作为map的key传进去的。。
Hashtable JDK1.0版本线程安全运行效率慢不允许null作为key或是value。 初始容量11加载因子0.75。 这个集合在开发过程中已经不用了稍微了解即可。
Properties
Hashtable的子类要求key和value都是String。通常用于配置文件的读取。
它继承了Hashtable的方法与流关系密切此处不详解。
TreeMap
实现了SortedMap接口是Map的子接口可以对key自动排序。
COPY/*** TreeMap的使用* 存储结构红黑树*/
public class Demo3 {public static void main(String[] args) {TreeMapStudent, Integer treeMapnew TreeMapStudent, Integer();Student s1new Student(tang, 36);Student s2new Student(yu, 101);Student s3new Student(he, 10);//1.添加元素treeMap.put(s1, 21);treeMap.put(s2, 22);treeMap.put(s3, 21);//不能直接打印需要实现Comparable接口因为红黑树需要比较大小System.out.println(treeMap.toString());//2.删除元素treeMap.remove(new Student(he, 10));System.out.println(treeMap.toString());//3.遍历//3.1 使用keySet()for (Student key : treeMap.keySet()) {System.out.println(key treeMap.get(key));}//3.2 使用entrySet()for (EntryStudent, Integer entry : treeMap.entrySet()) {System.out.println(entry.getKey() entry.getValue());}//4.判断System.out.println(treeMap.containsKey(s1));System.out.println(treeMap.isEmpty()); }
}在学生类中实现Comparable接口
COPYpublic class Student implements ComparableStudent{Overridepublic int compareTo(Student o) {int n1this.id-o.id;return n1;
}除此之外还可以使用比较器来定制比较
COPYTreeMapStudent, Integer treeMap2new TreeMapStudent, Integer(new ComparatorStudent() {Overridepublic int compare(Student o1, Student o2) {// 略return 0;}
});TreeSet源码
和HashSet类似放在TreeMap之后讲便一目了然部分
COPYpublic class TreeSetE extends AbstractSetEimplements NavigableSetE, Cloneable, java.io.Serializable
{private transient NavigableMapE,Object m;private static final Object PRESENT new Object();TreeSet(NavigableMapE,Object m) {this.m m;}public TreeSet() {this(new TreeMapE,Object());}
}TreeSet的存储结构实际上就是TreeMap再来看其存储方式
COPYpublic boolean add(E e) {return m.put(e, PRESENT)null;
}它的add方法调用的就是TreeMap的put方法将元素作为key传入到存储结构中。 Collections工具类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJZH8Shy-1614751593973)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210303135614014.png)] 概念集合工具类定义了除了存取以外的集合常用方法。 方法 public static void reverse(List? list)//反转集合中元素的顺序public static void shuffle(List? list)//随机重置集合元素的顺序public static void sort(ListT list)//升序排序元素类型必须实现Comparable接口 COPY/*** 演示Collections工具类的使用**/
public class Demo4 {public static void main(String[] args) {ListInteger listnew ArrayListInteger();list.add(20);list.add(10);list.add(30);list.add(90);list.add(70);//sort排序System.out.println(list.toString());Collections.sort(list);System.out.println(list.toString());System.out.println(---------);//binarySearch二分查找int iCollections.binarySearch(list, 10);System.out.println(i);//copy复制ListInteger list2new ArrayListInteger();for(int i10;i15;i1) {list2.add(0);}//该方法要求目标元素容量大于等于源目标Collections.copy(list2, list);System.out.println(list2.toString());//reserve反转Collections.reverse(list2);System.out.println(list2.toString());//shuffle 打乱Collections.shuffle(list2);System.out.println(list2.toString());//补充list转成数组Integer[] arrlist.toArray(new Integer[0]);System.out.println(arr.length);//补充数组转成集合 String[] nameStrings {tang,he,yu};//受限集合不能添加和删除ListString list3Arrays.asList(nameStrings);System.out.println(list3);//注基本类型转成集合时需要修改为包装类}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87337.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!