Collection接口
API
Modifier and Type | Method and Description |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一、List
元素有序、可重复的集合;“动态数组”
添加元素所在的类要重写equals方法
一、ArrayList
简单源码分析:
源码方法 | 作用或实现 |
ArrayList list = new ArrayList(); | 在底层创建长度位10的Object数组elementData; |
list.add(“aaa”); | elementData[0] = “aaa”;当elementData的长度不够时,会扩容数组为原来的1.5倍,并将原来的数据copy到扩容后的数组 |
ArrayList list = new ArrayList(5); | 有参构造器;传入参数后会创建一个该大小的数组;在已知大小的情况下建议使用该构造器。 |
常用方法:(除去Collection接口中的方法)
返回值 | 方法 | 描述 |
void | add(int index, E element)` | 在此列表中的指定位置插入指定的元素。 |
void | addAll(int index, Collection<? extends E> c) | 将指定集合中的所有元素插入到此列表中,从指定的位置开始。 |
E | get(int index) | 返回此列表中指定位置的元素。 |
int | indexOf(Object o) | 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 |
int | lastIndexOf(Object o) | 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。 |
ListIterator | listIterator(int index) | 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。 |
E | remove(int index) | 删除该列表中指定位置的元素。 |
E | set(int index, E element) | 用指定的元素替换此列表中指定位置的元素。 |
List | subList(int fromIndex, int toIndex) | 返回此列表中指定的 |
排序:
List list = Arrays.asList(2,5,94,3,5,4,7,5,4,321,5);
list.sort(Comparator.naturalOrder()); //从小到大
list.sort(Comparator.reverseOrder()); //从大到小
List遍历:**
List<Integer> list = Arrays.asList(2,5,94,3,5,4,7,5,4,321,5);
//方式一:普通循环
for (int i=0; i<list.size(); i++){
System.out.println(list.get(i));
}
System.out.println("---------------------");
//方式二:增强for循环
for (int i : list) {
System.out.println(i);
}
System.out.println("---------------------");
//方式三:迭代器
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
二、LinkedList
简单源码分析:
源码方法 | 作用或实现 |
transient int size = 0; transient Node first; transient Node last; | 创建一个LinkedList时,会指明链表的长度、第一个节点(临时)和最后一个节点(临时) |
private static class Node {…} | 节点的内部类,用于声明一个节点;包括由上一个节点、数据、下一个节点 |
添加元素(add()会方法调用该方法)
void linkLast(E e) {
final Node<E> l = last; //获取最后一个节点
final Node<E> newNode = new Node<>(l, e, null); //构建一个新的节点,l为prev,next为空
last = newNode; //将新的节点作为最后一个节点
if (l == null) //如果最后一个节点是null,则将新的节点作为第一个节点
first = newNode;
else //否则,最后一个节点的next指向新的节点
l.next = newNode;
size++;
modCount++;
}
常用方法:(LinkedList特有的方法)
返回值 | 方法 | 描述 |
void | addLast(E e) | 将指定的元素追加到此列表的末尾。 |
void | addFirst(E e)` | 在该列表开头插入指定的元素。 |
E | getFirst() | 返回此列表中的第一个元素。 |
E | getLast() | 返回此列表中的最后一个元素。 |
LinkedList可以充当对或栈,所以具有一些符合栈和队列特性的方法
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
三、Vector
较少使用。创建时会直接创建长度为10的数组(jdk7、8都是),扩容会变为原来的两倍
四、ArrayList、LinkedList、Vector的异同
- 同:三者都是实现了List接口;存储结构都是有序的、可重复的
- 不同:
- Vector效率低(线程安全);其他的效率高(线程不安全)
- LinkedList适用于增加和删除(底层由双向链表实现);ArrayList由Object[ ]实现,适合数据的添加和查找;Vector底层由Object[] elementData实现
二、Set:
元素无序、不可重复的集合;set接口中没有新定义方法
在使用SET时,要重写所添加对象所在类的equals和hashCode方法;尽可能保证两个方法的一致,即如果equals的结果为false,则二者的hashcode也应该不一样
一、HashSet
*无序:不等于随机;底层使用数组实现,但是不根据数组的索引添加,而是根据数据的hashcode方法获得的值来添加
*不可重复性:保证添加的元素按照equals比较时,不能返回true;即equals比较结果必须为不相同
添加元素过程理解:1.首先调用待添加对象所在类的hashcode方法计算hash值;2.根据hash值使用算法计算出该值在hashset底层数组中的具体位置;3.如果在数组中的该位置没有元素,则直接将该值添加至数组中,即完成添加;4.如果数组的该位置已有元素,则比较其hash值,如果不同,在该位置使用链表存储这些元素;5.如果hash值也行同,则调用待添加对象所在类中的equals方法,如果返回true,则该值重复,不在添加,如果返回false,则在该位置的链表中添加该值
API:同Collection接口中的方法
Set遍历:
Set set = new HashSet();
set.add(1);
set.add("aaa");
set.add(false);
set.add(55);
//方法一
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("--------------------");
//方法二
for (Object o: set) {
System.out.println(o);
}
二、LinkedHashSet
LinkedHashSet存储的方式与HashSet一样;但是遍历结果与添加的顺序相通,原因为:在添加数据的同时,其维护了添加数据的先后顺序,具体实现为每个元素都具有头和尾,分别指向前一个元素和后一个元素
优点:频繁的遍历效率高于HashSet
三、TreeSet
TreeSet中的存储结构为红黑树
Set中添加的数据必须是同一个类的数据
可以按照的对象的指定属性排序
注:TreeSet中的比较对象是否相同不适用equals,而使用compareTo( )/Compare()的返回值是否为0,0表示相同;
使用Comparable接口规定排序的规则(自然排序):
//对象类persion,其他方法已省略,只关注compareTo方法的重写
public class persion implements Comparable{
private String name;
private int age;
public persion(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Object o) {
if(o instanceof persion){
persion p = (persion)o;
if(this.age != p.age){
return Integer.compare(this.age,p.age);
}else{
return this.name.compareTo(p.name);
}
}else{
throw new RuntimeException("传入参数错误");
}
}
}
//实现
public static void main(String[] args) {
Set set = new TreeSet();
set.add(new persion("zhangsan",15));
set.add(new persion("lisi",20));
set.add(new persion("wangwu",65));
set.add(new persion("liuiz",53));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
/*输出:
persion{name='zhangsan', age=15}
persion{name='lisi', age=20}
persion{name='liuiz', age=53}
persion{name='wangwu', age=65}
*/
使用Comparator实现定制排序:
public static void main(String[] args) {
Comparator com = new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof persion && o2 instanceof persion){
persion p1 = (persion)o1;
persion p2 = (persion)o2;
return Integer.compare(p1.getAge(),p2.getAge());
}else{
throw new RuntimeException("出入参数错误");
}
}
};
Set set = new TreeSet(com);
set.add(new persion("zhangsan",15));
set.add(new persion("lisi",20));
set.add(new persion("wangwu",65));
set.add(new persion("liuiz",53));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
四、HashSet、LinkedHashSet、TreeSet异同
- HashSet:为set的主要实现类;线程不安全;可存放null值
- LinkedHashSet:为HashSet的子类;遍历时可以按照添加数据时的顺序来遍历;频繁的遍历效率高于HashSet
- TreeSet:可以按照的对象的指定属性排序
Map接口
key–value
一、HashMap
hashMap结构理解:
- key:无序的、不可重复的;可以理解为set存储 >>>key所在的类要重写equals()和hashCode()方法
- value:无序的、可重复的;可以理解为Collection存储 >>>value所在的类要重写equals方法
- enrty:key-value构成entry对象;entry无序的、不可重复的;可以理解为使用set存储
底层实现:
(jdk7=数组+链表;jdk8=数组+链表+红黑树)
jdk7:
源码 | 描述 |
Map map = new HashMap(); | 底层创建长度为16的数组;类型为Entry [ ] table |
map.put(k1,v1); | 1.根据key所在类的hashCode方法,计算hash值,通过计算获得其在数组中的存放位置;2.如果该位置为空,则将该k-v放入该位置;3.如果该位置已有数据,则比较他们的hash值,如果不同,则添加该k-v;如果相同,则调用待添加k所在类的equals方法:如果返回false,则添加成功;如果返回true,使用v替换该位置的原来的value(覆盖)。(如果原位置已有元素,则以链表的形式添加新的元素;涉及扩容时:扩容为原来的两倍【超出临界值且该位置已有元素才会扩容】,并复制原来的数据) |
jdk8:
- new HashMap();底层没有创建长度为16的数组
- 底层使用的数组为Node[ ];
- 首次调用put()方法时会创建长度为16的数组;
- 当数组的某一个索引位置的元素数量>8 ,且当数组长度超过64时,此索引位置上的元素改用红黑树存储
常用API:
返回值 | 方法 | 描述 |
void | clear() | 从这张地图中删除所有的映射。 |
boolean | containsKey(Object key) | 如果此映射包含指定键的映射,则返回true。 |
boolean | containsValue(Object value) | 如果此地图将一个或多个键映射到指定值,则返回 true 。 |
V | get(Object key) | 返回到指定键所映射的值,或 null如果此映射包含该键的映射。 |
boolean | isEmpty() | 如果此地图不包含键值映射,则返回 true。 |
V | put(K key, V value) | 将指定的值与此映射中的指定键相关联。 |
void | putAll(Map<? extends K,? extends V> m) | 将指定地图的所有映射复制到此地图。 |
V | remove(Object key) | 从该地图中删除指定键的映射(如果存在)。 |
boolean | remove(Object key, Object value) | 仅当指定的密钥当前映射到指定的值时删除该条目。 |
V | replace(K key, V value) | 只有当目标映射到某个值时,才能替换指定键的条目。 |
boolean | replace(K key, V oldValue, V newValue) | 仅当当前映射到指定的值时,才能替换指定键的条目 |
int | size() | 返回此地图中键值映射的数量。 |
Collection | values() | 返回此地图中包含的值的Collection视图。 |
Set<Map.Entry<K,V>> | entrySet() | 返回此地图中包含的映射的Set视图。 |
Set | keySet() | 返回此地图中包含的键的Set视图。 |
hashMap的遍历:
public static void main(String[] args) {
Map<String,Integer> map = new LinkedHashMap();
map.put("a",1);
map.put("b",3);
map.put("c",3);
//遍历map中的key
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-----------------");
//遍历map中的value
Collection<Integer> values = map.values();
Iterator<Integer> iterator1 = values.iterator();
while(iterator1.hasNext()){
System.out.println(iterator1.next());
}
System.out.println("-----------------");
//遍历map:方法一
for (Map.Entry<String,Integer> e: map.entrySet()) {
System.out.print(e.getKey());
System.out.print(" ");
System.out.print(e.getValue());
System.out.println();
}
System.out.println("-----------------");
//遍历map:方法二
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator2 = entries.iterator();
while(iterator2.hasNext()){
Map.Entry e = (Map.Entry)iterator2.next();
System.out.print(e.getKey());
System.out.print(" ");
System.out.print(e.getValue());
System.out.println();
}
}
/*输出:
a
b
c
-----------------
1
3
3
-----------------
a 1
b 3
c 3
-----------------
a 1
b 3
c 3
*/
二、LinkedHashMap
是HashMap的子类,方法都一样,知识多了两个before、after指针,当频繁使用遍历时效率更高
三、TreeMap
*添加的数据类型必须都是同一类型的
自然排序实现(类实现Comparable接口):
//传入的参数类,关注接口的实现与方法的重写
public class student implements Comparable{ //实现Comparable接口
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
student student = (student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public student() {
}
public student(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;
}
@Override
public int compareTo(Object o) { //重写compareTo方法,将根据重写的逻辑来排序
if(o instanceof student){
student s = (student)o;
return this.name.compareTo(s.name);
}else{
throw new RuntimeException("参数错误");
}
}
}
//遍历TreeMap查看排序
public static void main(String[] args) {
TreeMap<student,Integer> map = new TreeMap();
student s1 = new student("shangsan", 10);
student s2 = new student("lisi", 15);
student s3 = new student("wangwu", 11);
student s4 = new student("liu", 120);
map.put(s1,1);
map.put(s2,2);
map.put(s3,3);
map.put(s4,4);
for (Map.Entry<student,Integer> e :map.entrySet()) {
System.out.print(e.getKey().getName());
System.out.print(" ");
System.out.print(e.getValue());
System.out.println();
}
}
/*输出:
lisi 2
liu 4
shangsan 1
wangwu 3
*/
定制排序(new TreeSet()时传入Comparator):
public static void main(String[] args) {
Comparator<student2> com = new Comparator(){ //创建Comparator对象,并重写compare方法
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof student2){
student2 s1 = (student2)o1;
student2 s2 = (student2)o2;
return Integer.compare(s1.getAge(),s2.getAge());
}else{
throw new RuntimeException("参数错误");
}
}
};
TreeMap<student2,Integer> map = new TreeMap(com); //将创建的Comparator对象传入TreeMap构造器,将根据此规则排序
student2 s1 = new student2("shangsan", 10);
student2 s2 = new student2("lisi", 15);
student2 s3 = new student2("wangwu", 11);
student2 s4 = new student2("liu", 120);
map.put(s1,1);
map.put(s2,2);
map.put(s3,3);
map.put(s4,4);
for (Map.Entry<student2,Integer> e :map.entrySet()) {
System.out.print(e.getKey().getName());
System.out.print(" ");
System.out.print(e.getValue());
System.out.println();
}
}
/*输出:
shangsan 1
wangwu 3
lisi 2
liu 4
*/
五、Hashtable:
Properties:作为Hashtable的子类(是一种map)
多用于配置文件
###配置文件jdbc.properties信息
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mytest?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=root
//加载配置文件
public static void main(String[] args) {
Properties properties = new Properties();
try {
FileInputStream fis = new FileInputStream("jdbc.properties");
properties.load(fis);
String driver = properties.getProperty("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String password = properties.getProperty("jdbc.password");
System.out.println(driver + " " + url + " "+ username +" "+ password);
} catch (Exception e) {
e.printStackTrace();
}
}
/*输出:
com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/mytest?serverTimezone=UTC&useSSL=false root root
*/
区别:
- HashMap:Map接口的主要实现类;线程不安全,效率高;可以存储null的key或value
- LinkedHashMap:作为HashMap的子类;保证在遍历map元素时实现按照添加时的顺序(添加有两个指针指向前一个和后一个元素);频繁遍历效率高
- TreeMap:添加的key-value可以按照key来实现自然排序或定制排序
- Hashtable:线程安全,效率低;不可以存储null的key或value
- Properties:作为Hashtable的子类;常用来作为配置文件。key和value都是String
Collections工具类
Collections用于操作set、list、map的工具类
常用方法:
- reverse(List<?> list) 反转指定列表中元素的顺序。
List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
Collections.reverse(list1);
for (String s:list1) {
System.out.println(s);
}
/*输出:
eee
ddd
ccc
bbb
aaa
*/
- shuffle(List<?> list)
List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
Collections.shuffle(list1);
for (String s: list1) {
System.out.println(s);
}
/*输出: 随机序列
bbb
ddd
ccc
eee
aaa
*/
- sort(List list) 根据其元素的natural ordering对指定的列表进行排序(简易理解为:从小到大)
- sort(List list, Comparator<? super T> c) 根据指定的比较器引起的顺序对指定的列表进行排序。
List<String> list1 = Arrays.asList("aaa", "ccc", "ddd", "bbb","eee");
Collections.sort(list1, Comparator.reverseOrder()); //倒叙
for (String s: list1) {
System.out.println(s);
}
System.out.println("--------------");
Collections.sort(list1, Comparator.naturalOrder()); //自然排序
for (String s: list1) {
System.out.println(s);
}
- swap(List<?> list, int i, int j) 交换指定列表中指定位置的元素。
List<String> list1 = Arrays.asList("aaa", "ccc", "ddd", "bbb","eee");
Collections.swap(list1,0,4); //交换索引为0和4的元素的位置
for (String s: list1) {
System.out.println(s);
}
/*输出:
eee
ccc
ddd
bbb
aaa
*/
- max(Collection<? extends T> coll) 根据其元素的 自然顺序返回给定集合的最大元素。
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb","eee","aaa");
String max = Collections.max(list1);
System.out.println(max); //eee
HashSet<Integer> set = new HashSet<>();
set.add(5);
set.add(8);
set.add(4);
Integer max1 = Collections.max(set);
System.out.println(max1); //8
- max(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定的比较器引发的顺序返回给定集合的最大元素。
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb","eee","aaa");
String max = Collections.max(list1,new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String)o1;
String s2 = (String)o2;
return - s1.compareTo(s2);
}else{
throw new RuntimeException("参数错误");
}
}
});
System.out.println(max); //eee
HashSet<Integer> set = new HashSet<>();
set.add(5);
set.add(8);
set.add(4);
Integer max1 = Collections.max(set,Comparator.reverseOrder());
System.out.println(max1); //8
- min(Collection<? extends T> coll) 根据其元素的 自然顺序返回给定集合的最小元素。
- min(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定的比较器引发的顺序返回给定集合的最小元素。
- frequency(Collection<?> c, Object o) 返回指定集合中与指定对象相等的元素数。
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
int ddd = Collections.frequency(list1, "ddd");
System.out.println(ddd); //3
- replaceAll(List list, T oldVal, T newVal) 将列表中一个指定值的所有出现替换为另一个。
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
Collections.replaceAll(list1,"ddd","replace");
for (String s: list1) {
System.out.println(s);
}
/*输出:
ccc
replace
bbb
replace
eee
aaa
*/
- synchronizedXXX(XXX c) 返回由指定集合支持的同步(线程安全)集合
例如List:
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
List<List<String>> lists = Collections.singletonList(list1);
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
int ddd = Collections.frequency(list1, "ddd");
System.out.println(ddd); //3
- replaceAll(List list, T oldVal, T newVal) 将列表中一个指定值的所有出现替换为另一个。
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
Collections.replaceAll(list1,"ddd","replace");
for (String s: list1) {
System.out.println(s);
}
/*输出:
ccc
replace
bbb
replace
eee
aaa
*/
- synchronizedXXX(XXX c) 返回由指定集合支持的同步(线程安全)集合
例如List:
List<String> list1 = Arrays.asList("ccc", "ddd", "bbb", "ddd","eee","aaa", "ddd");
List<List<String>> lists = Collections.singletonList(list1);