科技期刊网站建设,甘肃兰州海拔多少米,淮安哪里有做网站的,承德建设银行网站集合、数组都是对多个数据进行存储操作的结构#xff0c;简称java容器 #xff08;此时的存储#xff0c;主要指的是内存层面的存储#xff0c;不涉及持久化的存储#xff09;
数组存储的特点#xff1a;
一旦初始化#xff0c;其长度就确定了。数组一旦定义好#x…集合、数组都是对多个数据进行存储操作的结构简称java容器 此时的存储主要指的是内存层面的存储不涉及持久化的存储
数组存储的特点
一旦初始化其长度就确定了。数组一旦定义好其元素的类型也就确定了。我们也就只能操作指定类型的数据了。 比如
String []arr; int[] arr1 ; Object[] arr2;数组存储的弊端
一旦初始化以后其长度就不可修改数组中提供的方法非常有限对于添加删除插入等操作非常不便同时效率不高获取数组中实际元素的个数的需求数组没有现成的属性或方法可以用数组存储数据的特点有序、可重复。对于无序、不可重复的需求不能满足。
集合存储的优点解决数组存储数据方面的弊端。 java集合可以分为Collection和Map两种体系
Collection接口单列集合用来存储一个一个的对象
List元素有序、可重复的集合 --“动态”数组Set元素无序、不可重复的集合 --高中的“集合”
Map接口双列集合保存具有映射关系的“Key-value”的集合即存储一对的数据
List内包含很多实现类比如ArrayList、LinkedList、Vector
Set的实现类比如HashSet、LinkedHashSet、TreeSet
Map的实现类比如HashMap、LinkedHashMap、TreeMap、Hashtable、Properties Collection接口中的方法使用
✨向Collection接口的实现类的对象中添加数据obj时要求obj所在类要重写equals()
add()添加size()求集合元素addAll(当前集合)把当前集合所有元素加到另一个集合去clear()清空集合数据isEmpty()判断是否有元素有返回false
Test
public void test1() {Collection coll new ArrayList();// add(Object e) 将元素e添加到集合coll中coll.add(AA);coll.add(BB);coll.add(123); //自动装箱coll.add(new Date());//size(): 获取添加的元素的个数System.out.println(coll.size()); // 4//addAll():Collection coll1 new ArrayList();coll1.add(456);coll1.add(CC);coll.addAll(coll1); //把coll1集合中的所有元素加到coll中System.out.println(coll.size()); // 6System.out.println(coll);//clear(): 清空集合数据而不是赋值为空coll.clear();//isEmpty():判断当前集合是否有元素,没有则返回trueSystem.out.println(coll.isEmpty());
}contains(Object obj):判断当前集合中是否包含obj,判断的是内容而不是地址!//containsAll(Collection coll1):判断形参coll1所有元素是否都存在于当前集合中
Test
public void test2() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new String(Tom));coll.add(false);coll.add(new Person(Jerry,20));//contains(Object obj):判断当前集合中是否包含obj,判断的是内容而不是地址!//我们在判断时会调用obj对象所在类的equals()boolean contains coll.contains(123);System.out.println(contains); //trueSystem.out.println(coll.contains(new String(Tom))); // trueSystem.out.println(coll.contains(new Person(Jerry,20)));//containsAll(Collection coll1):判断形参coll1所有元素是否都存在与当前集合中Collection coll1 Arrays.asList(123,456);System.out.println(coll.containsAll(coll1)); //coll中是否包含coll1中所有数据
}remove(Object obj):从当前集合中删除一个指定数据并可以返回一个布尔值表示是否删除成功removeAll(Collection coll1):从当前集合中移除coll1中的所有元素
Test
public void test3() {//remove(Object obj):从当前集合中删除一个指定数据并可以返回一个布尔值表示是否删除成功Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new Person(Jerry,20));coll.add(new String(Tom));coll.add(false);System.out.println(coll);coll.remove(123);System.out.println(coll);//removeAll(Collection coll1):从当前集合中移除coll1中的所有元素即删除的是当前集合中和coll1中都有的元素但coll1不删Collection coll1 Arrays.asList(456,4657); //coll1中有456,4567coll.removeAll(coll1); //找coll中是否有456和4567,有的话删掉System.out.println(coll1); //打印之后发现456没了
}retainAll():求两个集合的交集,本例中是获取coll和coll1中的交集并返回给当前集合
Test
public void test4() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new Person(Jerry,20));coll.add(new String(Tom));coll.add(false);//retainAll():求两个集合的交集,本例中是获取coll和coll1中的交集并返回给当前集合Collection coll1 Arrays.asList(123,456,789); coll.retainAll(coll1);System.out.println(coll);
}equals(Object obj):要想返回true需要当前集合和形参集合的元素都相同。
Test
public void test5() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new Person(Jerry,20));coll.add(new String(Tom));coll.add(false);//equals(Object obj):要想返回true需要当前集合和形参集合的元素都相同。Collection coll1 new ArrayList();coll1.add(123);coll1.add(456);coll1.add(new Person(Jerry,20));coll1.add(new String(Tom));coll1.add(false);System.out.println(coll.equals(coll1));
}hashCode():返回当前对象的哈希值 集合—数组toArray(); 数组 — 集合:调用Arrays类的静态方法asList(),基本数据类型要写成包装类 iterator():返回Iterator接口的实例用于遍历集合元素。
Test
public void test6() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new Person(Jerry,20));coll.add(new String(Tom));coll.add(false);//hashCode():返回当前对象的哈希值System.out.println(coll.hashCode());//集合---数组toArray()Object[] arr coll.toArray();for(int i 0;i arr.length ;i) {System.out.println(arr[i]);}//拓展数组 --- 集合:调用Arrays类的静态方法asList(),基本数据类型要写成包装类ListString list Arrays.asList(new String[] {AA,BB,CC});System.out.println(list);//基本数据类型数组的两种方式List arr1 Arrays.asList(123,456);System.out.println(arr1);List arr2 Arrays.asList(new Integer[] {123,456});System.out.println(arr2);
}下面是自定义Person类的源码上面代码演示时用到了一个Person类 public class Person {private String name;private int age;public Person() {super();}public Person(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 Person [name name , age age ];}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;return age other.age Objects.equals(name, other.name);}}迭代器Iterator的使用
内部的方法hasNext()和next()
Test
//集合元素的遍历操作使用迭代器Iterator接口
public void test() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new String(Tom));coll.add(false);Iterator iterator coll.iterator();//方式1一次取一个数据System.out.println(iterator.next());//方式2for遍历不推荐for(int i 0;i coll.size() ; i) {System.out.println(iterator.next());}//方式3hasNext()判断是否还有元素可以取 --推荐while(iterator.hasNext()) {System.out.println(iterator.next());}
}hasNext()判断是否还有下一个元素next()①指针下移②将下移以后集合位置上的元素返回 remove()的使用
迭代器中remove()的使用遍历时删除指定元素,此方法不同于集合直接调用remove()
Test
public void test1() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new Person(Jerry,20));coll.add(new String(Tom));coll.add(false);//删除集合中Tom这个数据Iterator iterator coll.iterator();while(iterator.hasNext()) {Object obj iterator.next();;if(Tom.equals(obj)) {iterator.remove();}}//删除后重头遍历集合让指针重新指向这个集合的头部iterator coll.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}
}foreach循环遍历集合元素
Java5.0提供了foreach循环迭代访问Collection和数组这种循环又叫增强for循环
✨格式for(集合/数组元素类型 局部变量 : 集合/数组对象){}
例1foreach循环迭代访问Collection
Test
public void test() {Collection coll new ArrayList();coll.add(123);coll.add(456);coll.add(new String(Tom));coll.add(false);for(Object obj : coll) {System.out.println(obj);}
}例2foreach循环迭代访问数组
Test
public void test1() {int [] arr new int[] {1,2,3,4,5};for(int x : arr) {System.out.println(x);}
}List接口框架
List元素有序、可重复的集合
List不用关注长度够不够的问题它动态帮我们把长度做了变化。所以可以看作一个“动态”数组替换原有的数组
List接口的实现类主要有ArrayList、LinkedList、Vector
面试题ArrayList、LinkedList、Vector的异同 同三个类都实现了List接口存储数据的特点相同存储有序的可重复的数据 异 ArrayList作为List接口的主要实现类线程不安全的效率高底层使用Object[] elementData存储扩容1.5倍LinkedList:对于频繁的插入、删除操作使用此类效率比ArrayList高底层使用双向链表存储Vector作为List接口的古老实现类线程安全的效率低底层使用Object[] elementData存储扩容2倍 ArrayList
每次创建ArrayList的对象表示底层创建长度是10的Object[] 数组elementData
可以向数组内添加数据如果有一次的添加导致底层数组elementData容量不够则扩容默认情况下扩容为原来的1.5倍同时需要将原有数组中的数据复制到新的数组中
结论建议开发中使用带参的构造器ArrayList list new ArrayList(int capacity) 指定创建初始数组的容量。
Test
public void test() {ArrayList list new ArrayList(); //底层创建了长度是10的Object[] 数组elementDatalist.add(123); // elementData[0] nwe Interger(123);list.add(11);
}jdk 8中ArrayList的变化
ArrayList list new ArrayList(); //底层Object[] elementData初始化为{}并没有创建长度为10的数组
list.add(123); //第一次调用add()时底层才创建了长度为10的数组并把123这个数据添加到elementData
后续的添加和扩容操作与jdk 7无异
小结jdk 7中的ArrayList的对象创建类似于单例的饿汉式而jdk 8中的ArrayList对象的创建类似于单例的懒汉式延迟了数组创建节省内存。 LinkedList
LinkedList list new LinkedList();
内部声明了Node类型的first和last属性默认值为null
list.add(213);//将123封装到Node中创建了Node对象其中Node定义为(源码)体现了双向链表的说法
private 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;}
}List接口常用方法测试
void add(int index, Object ele):在index位置插入ele元素boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来Object get(int index):获取指定index位置的元素
Test
public void test() {ArrayList list new ArrayList(); //底层创建了长度是10的Object[] 数组elementDatalist.add(123);list.add(456);list.add(AA);list.add(BB);list.add(Tom);list.add(456);System.out.println(list);//1.void add(int index, Object ele):在index位置插入ele元素list.add(1,BB);System.out.println(list);//2.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来List list1 Arrays.asList(1,2,3);//list.add(list1); //把list1当作一个整体插入到list里,size为7而不是9list.addAll(1,list1); //不写位置默认插入到最后System.out.println(list);//3.Object get(int index):获取指定index位置的元素System.out.println(list.get(0));
}int indexOf(Object obj):返回obj在集合中首次出现的位置int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置Object remove(int index):移除指定index位置的元素并返回此元素Object set(int index, Object ele):设置指定index位置的元素为eleList subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合左闭右开
Test
public void test1() {ArrayList list new ArrayList(); list.add(123);list.add(456);list.add(AA);list.add(BB);list.add(Tom);list.add(456);//4.int indexOf(Object obj):返回obj在集合中首次出现的位置,找不到返回-1int index list.indexOf(456);System.out.println(index); //System.out.println(list.indexOf(123)); //可以直接输出//5.int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置,找不到返回-1System.out.println(list.lastIndexOf(456));//6.Object remove(int index):移除指定index位置的元素并返回此元素 注意这里是按照索引删除Object obj list.remove(0); //返回指定位置被删除的元素System.out.println(obj);System.out.println(list);//7.Object set(int index, Object ele):设置index位置的元素为elelist.set(1, CC);System.out.println(list);//8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合List list1 list.subList(2, 4);System.out.println(list1);
}总结常用方法
增add(Object obj)删remove(int index) / remove(Object obj)改set(int index, Object ele)查get(int index)插add(int index, Object ele)长度size()遍历① Iterator迭代器方式 ② 增强for循环 ③ 普通的循环
Test
public void test2() {ArrayList list new ArrayList(); list.add(123);list.add(456);list.add(AA);//Iterator迭代器方式Iterator iterator list.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}// 增强for循环for(Object obj : list) {System.out.println(obj);}// 普通for循环for(int i 0;i list.size() ;i) {System.out.println(list.get(i));}
}删除指定元素要自己手动装箱比如remove(new Integer(2)); Set接口框架
元素无序、不可重复的集合
Set的实现类比如HashSet、LinkedHashSet、TreeSet
HashSet作为Set接口的主要实现类线程不安全可以存储null值LinkedHashSet是HashSet的子类遍历其内部数据时可以按照添加的顺序遍历TreeSet底层用红黑树存数据可以确保集合元素处于排序状态可以按照添加对象的指定属性进行排序。
注Set接口中没有额外定义新的方法使用的都是Collection中声明过的方法。
✨下面解释Set集合两种特征
无序性并不是随机性遍历这样集合的时候也会有一个固定顺序只不过和你添加的顺序不一样。而是根据数据的哈希值决定的
Test
public void test() {Set set new HashSet();set.add(123);set.add(456);set.add(AA);set.add(BB);set.add(CC);Iterator iterator set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}
}不可重复性保证添加的元素按照equals()判断时不能返回true。即相同元素只能添加一个。 HashSet添加元素过程
HashSet底层是数组链表的结构初始容量为16
我们向HashSet添加元素a首先调用元素a所在类的hashCode()方法计算元素a的哈希值此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置即为索引位置判断数组再次位置上是否已经有元素
如果此位置上没有其他元素则元素a添加成功。 如果此位置上有其他元素b(或以链表形式存在的多个元素)则比较a与元素b的hash值 如果hash值不相同则元素a添加成功 如果hash值相同进而需要调用元素a所在类的equals()方法 euqals()返回true元素a添加失败 euqals()返回false元素a添加成功 总结添加时先看这个位置上有没有元素有的话就比较hash值hash值一样就用equals()方法
要求①向Set中添加的数据其所在类一定要重写hashCode()和equals() ②重写的hashCode()和equals()方法尽量保持一致性
对于要插入位置上已经有元素的情况而言元素a 与 已经存在指定索引位置上数据以链表的方式存储。 存储方式即指针谁指向谁看下面。 Jdk 7:元素a放到数组中指向原来的元素。 Jdk 8:原来的元素在数组中指向元素a。 七上八下 LinkedHashSet的使用
LinkedHashSet作为HashSet的子类在添加数据的同时每个数据还维护了两个引用记录此数据前一个数据和后一个数据。
优点对于频繁的遍历操作LinkedHashSet效率要高于HashSet TreeSet*
可以按照对象的指定属性进行排序
排序有自然排序实现Comparable接口和定制排序Comparator
自然排序中比较两个对象是否相同的标准为compareTo()返回0不再是equals()定制排序中比较两个对象是否相同的标准为compare()返回0不再是equals()
注意
向TreeSet中添加的数据要求是相同类的对象对于基本数据类型还有String类型可进行从小到大排序
Test
public void test() {TreeSet set new TreeSet();set.add(123);set.add(456);
// set.add(AA); //不能添加不同类的对象set.add(36);set.add(-11);Iterator iterator set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}}对于自定义类型我们在自定义类重写compareTo()方法 比如下面的Person类就是一个自定义类 public class Person implements Comparable{//按照姓名从小到大进行排列Overridepublic int compareTo(Object o) {if(o instanceof Person) {Person p (Person)o;
// return this.name.compareTo(p.name); //相同值会只返回一个,如果从大到小就-thisint compare this.name.compareTo(p.name);if(compare ! 0) {return compare;} else {return Integer.compare(this.age, p.age);}} else {throw new RuntimeException(输入的类型不匹配);}}private String name;private int age;public Person() {super();}public Person(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 Person [name name , age age ];}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Person other (Person) obj;return age other.age Objects.equals(name, other.name);}
}测试类如下
Test
public void test1() {TreeSet set new TreeSet();set.add(new Person(Jerry,32));set.add(new Person(Jim,22));set.add(new Person(Mike,26));set.add(new Person(Adobe,66));Iterator iterator set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}
}定制排序利用TreeSet带参构造器(Comparator comparator)下面例子中。如果不在TreeSet()里加com就是自然排序加上就是定制排序
Test
public void test2() {Comparator com new Comparator() {//按照年龄从小到大排序Overridepublic int compare(Object o1,Object o2) {if(o1 instanceof Person o2 instanceof Person) {Person p1 (Person)o1;Person p2 (Person)o2;return Integer.compare(p1.getAge(), p2.getAge());} else {throw new RuntimeException(输入的数据类型不匹配);}}};TreeSet set new TreeSet(com);
}Map接口
Map接口双列集合保存具有映射关系的“Key-value”的集合即存储一对的数据类似于高中的函数
Map的实现类
HashMap:作为Map的主要实现类线程不安全的效率高可存储null的Key-value 在JDK7之前底层时数组链表JDK8之后是数组链表红黑树 LinkedHashMapHashMap的子类保证在遍历map元素时可以按照添加的顺序实现遍历。原因在原有的HashMap底层结构基础上添加了一对指针指向前一个和后一个元素对于频繁的遍历操作此类执行效率高于HashMap TreeMap保证按照添加的key-value键值对进行排序实现排序遍历按照key来自然或定制排序底层使用红黑树。Hashtable作为古老的实现类线程安全的效率低不能存储null的Key-value PropertiesHashtable的子类常用来处理配置文件key-value都是String类型 Map中键值对的注意事项 Map中的Key无序的、不可重复的使用Set存储所有的key --key所在类要重写equals()和hashCode()方法 Map中的value无序的、可重复的使用Collection存储所有的vaule --key所在类要重写equals() 一个键值对key-vaule构成了一个Entry对象。 Map中的Entry无序的、不可重复的使用Set存储所有的Entry Map中常用方法
添加、删除、修改操作
Object put(Object key,Object value)将指定key-value添加到(或修改)当前map对象中void putAll(Map m):将m中的所有key-value对存放到当前map中Object remove(Object key)移除指定key的key-value对并返回value找不到key返回nullvoid clear()清空当前map中的所有数据
Test
public void test() {//1.put(Object key,Object value)将指定key-value添加到(或修改)当前map对象中Map map new HashMap();//添加map.put(AA, 123);map.put(66, 123);map.put(BB, 13);//修改上面有过一个AA了32会覆盖掉123map.put(AA, 32);System.out.println(map);//2.putAll(Map m):将m中的所有key-value对存放到当前map中Map map1 new HashMap();map1.put(CC, 56);map1.put(DD, 99);map.putAll(map1);System.out.println(map);//3.remove(Object key)移除指定key的key-value对并返回valueObject value map.remove(CC);System.out.println(value);System.out.println(map);//4.clear()清空当前map中的所有数据map.clear();System.out.println(map.size());System.out.println(map);
}元素查询的操作
Object get(Object key)获取指定key对应的value找不到key返回nullboolean containsKey(Object key)是否包含指定的keyboolean containsValue(Object value)是否包含指定的valueint size()返回map中key-value对的个数boolean isEmpty()判断当前map是否为空boolean equals(Object obj)判断当前map和参数对象obj是否相等
Test
public void test3() {Map map new HashMap();map.put(AA, 123);map.put(66, 123);map.put(BB, 13);//1.get(Object key)获取指定key对应的valueSystem.out.println(map.get(66));//2.boolean containsKey(Object key)是否包含指定的keyboolean isExist map.containsKey(BB);System.out.println(isExist);//3.boolean containsValue(Object value)是否包含指定的valueboolean b map.containsValue(123);System.out.println(b);//4.int size()返回map中key-value对的个数System.out.println(map.size());//5.boolean isEmpty()判断当前map是否为空System.out.println(map.isEmpty());map.clear(); //清空mapSystem.out.println(map.isEmpty());
}元视图操作的方法涉及如何遍历map中的key-value、key、value
Set keySet()返回所有key构成的Set集合Collection values()返回所有value构成的Collection集合Set entrySet()返回所有key-value对构成的Set集合
Test
public void test() {Map map new HashMap();map.put(AA, 123);map.put(66, 1234);map.put(BB, 13);//1.Set keySet()返回所有key构成的Set集合Set set map.keySet();Iterator iterator set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}//2.Collection values()返回所有value构成的Collection集合Collection values map.values();for(Object obj : values) {System.out.println(obj);}//3.Set entrySet()返回所有key-value对构成的Set集合Set entrySet map.entrySet();Iterator iterator1 entrySet.iterator();while(iterator1.hasNext()) {Object obj iterator1.next();Map.Entry entry (Map.Entry)obj;System.out.println(entry.getKey() --- entry.getValue());//或者直接输出System.out.println(iterator1.next());}
}总结常用方法
添加put(Object key,Object value)删除remove(Object key)修改put(Object key,Object value)查询get(Object key)长度size()遍历keySet() / values() / entrySet() HashMap底层实现原理
以JDK7为例HashMap map new HashMap();
在经过实例化之后底层会创建一个长度为16的一维数组Entry[] table。如果涉及到扩容则每一次扩容2倍并将原来的数据拷贝过来给新数组。
然后以进行增加数据为例
map.put(key1,value1);首先调用key1所在类的hashCode()方法计算key1的哈希值此哈希值经过某种算法计算以后得到Entry数组中的存放位置。 如果此位置上的数据为空此时的key1-value1添加成功。 如果此位置上的数据不为空意味着此位置上存在一个或多个数据以链表形式存在比较当前key1和已经存在的一个或多个数据的哈希值。如果key1的哈希值于已经存在的数据都不一样那么key1-value1添加成功。 如果key1和已经存在的某一个数据key2-value2的哈希值相同继续比较调用key1所在类的equals(key2)方法比较如果equals()返回falsekey1-value1添加成功 返回true使用value1替换value2。 对于后两中添加成功的方式key1-value1和原来的数据以链表的形式存储。 JDK8相比较于JDK7在底层实现方面的不同
new HashMap():底层没有创建一个长度为16的数组jdk8底层的数组是Node[]而非Entry[]数组首次调用put()方法时底层创建长度为16的数组jdk8中当数组的某一个位置上的元素以链表的形式存在的数据个数 8 且数组长度 64时此位置上的所有数据改为使用红黑树存储 DEFAULT_INITIAL_CAPACITY : HashMap的默认容量16DEFAULT_LOAD_FACTORHashMap的默认加载因子0.75threshold扩容的临界值容量*填充因子16 * 0.75 12TREEIFY_THRESHOLDBucket中链表长度大于该默认值转化为红黑树:8MIN_TREEIFY_CAPACITY桶中的Node被树化时最小的hash表容量:64