集合
1. Collection接口
Collection接口是集合的父接口。
1.1 List接口
List接口中存储一组有序的,可以重复的元素。
1.1.1 ArrayList
常用方法
package com.qfedu.test1;import java.util.ArrayList;import java.util.InputMismatchException;/*** Collection* List* ArrayList类常用方法* @author WHD**/public class Test1 {public static void main(String[] args) {ArrayList list = new ArrayList();list.add(10);list.add(3.5);list.add('a');list.add("hello");list.add(false);ArrayList<Integer> list1 = new ArrayList<Integer>();list1.add(20);list1.add(35);list1.add(30);list1.add(55);list1.add(60);System.out.println(list1.size());System.out.println(list1.remove(0));System.out.println(list1.size());list1.set(0, 666);System.out.println(list1.get(0));System.out.println(list1.isEmpty());list1.clear();System.out.println(list1.isEmpty());ArrayList<Student> list2 = new ArrayList<Student>();Student stu1 = new Student("赵四", 20);list2.add(stu1);list2.add(new Student("赵四", 20));list2.add(new Student("赵四", 20));list2.add(new Student("赵四", 20));list2.add(new Student("赵四", 20));list2.add(new Student("赵四", 20));list2.remove(stu1);System.out.println(list2.size());}}
遍历
package com.qfedu.test2;import java.util.ArrayList;import java.util.Iterator;/*** ArrayList集合遍历方式* 1.普通for循环* 2.迭代器遍历* 3.增强for循环* @author WHD**/public class Test1 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<Integer>();for (int i = 0; i < 200000; i++) {list.add(i);}// 方式1 普通for循环long beginTime = System.currentTimeMillis();for(int i = 0; i < list.size();i++) {System.out.println(list.get(i));}long endTime = System.currentTimeMillis();System.out.println("普通for循环耗时" + (endTime - beginTime));// 方式2 迭代器遍历beginTime = System.currentTimeMillis();Iterator<Integer> it = list.iterator();while(it.hasNext()) {System.out.println(it.next());}endTime = System.currentTimeMillis();System.out.println("迭代器耗时" + (endTime - beginTime));// 方式3 增强for循环 底层实现依然还是迭代器 是JDK1.5新增的写法beginTime = System.currentTimeMillis();for(Integer i :list) {System.out.println(i);}endTime = System.currentTimeMillis();System.out.println("增强for循环耗时" + (endTime - beginTime));}}
数据结构 ArrayList集合特点和数据结构 底层实现是一个Object数组,有下标,有序,可以为null,可以重复,线程不安全 查询修改快,因为有下标 增删慢,因为需要移动元素
ArrayList集合源代码解读: 1.当我们调用无参构造 初始化一个初始为空的数组 2.当我们第一次添加元素的时候 将数组容量改为10 3.如果长度不够 将扩容为原来的1.5倍
1.1.2 LinkedList
常用方法
package com.qfedu.test4;import java.util.LinkedList;/*** LinkedList 集合常用方法* @author WHD*/public class Test1 {public static void main(String[] args) {LinkedList<String> list = new LinkedList<String>();list.add("a");list.addFirst("hello");list.addLast("world");System.out.println(list.remove(0));System.out.println(list.size());System.out.println(list.removeFirst());System.out.println(list.removeLast());System.out.println(list.size());list.add("ABC");list.add("DEF");list.set(0, "abc");System.out.println(list.get(0));System.out.println(list.getLast());System.out.println(list.isEmpty());list.clear();System.out.println(list.isEmpty());}}
遍历方式
package com.qfedu.test5;import java.util.Iterator;import java.util.LinkedList;/*** LinkedList 三种遍历方式* 1.普通for循环* 2.迭代器* 3.增强for循环** LinkedList数据结构* 双向链表,没有初始大小,不需要扩容,没有个数上限,有序(插入顺序),可以为null,可以重复,线程不安全* 查询,修改慢,因为没有下标,我们根据某个序号查找元素必须先找到与之相邻的元素,以此类推* 删除,添加块,因为不需要移动元素,只需要改变新的指针即可* @author WHD**/public class Test1 {public static void main(String[] args) {LinkedList<Integer> list = new LinkedList<Integer>();for (int i = 0; i < 200000; i++) {list.add(i);}// 方式1 普通for循环// long begin = System.currentTimeMillis();// for(int i= 0;i < list.size();i++) {// System.out.println(list.get(i));// }//// long end = System.currentTimeMillis();// System.out.println("普通for循环耗时" + (end - begin));// 方式2 迭代器遍历long begin = System.currentTimeMillis();Iterator<Integer> iterator = list.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}long end = System.currentTimeMillis();System.out.println("迭代器耗时" + (end - begin));// 方式3 增强for循环begin = System.currentTimeMillis();for(Integer i : list) {System.out.println(i);}end = System.currentTimeMillis();System.out.println("增强for循环耗时" + (end - begin));}}
数据结构 LinkedList数据结构 双向链表,没有初始大小,不需要扩容,没有个数上限,有序(插入顺序),可以为null,可以重复,线程不安全 查询,修改慢,因为没有下标,我们根据某个序号查找元素必须先找到与之相邻的元素,以此类推 删除,添加块,因为不需要移动元素,只需要改变新的指针即可
1.1.3 Vector
ArrayList与Vector的区别? ArrayList线程不安全 Vector线程安全 ArrayList初始为0 Vector初始为10 扩容1.5倍 扩容2倍
package com.qfedu.test5;import java.util.Vector;/*** ArrayList与Vector的区别?* ArrayList线程不安全 Vector线程安全* ArrayList初始为0 Vector初始为10* 扩容1.5倍 扩容2倍* @author WHD**/public class TestVector {public static void main(String[] args) {Vector<String> v = new Vector<String>();v.add("a");v.add("b");v.add("c");v.add("d");v.remove(1);v.set(0, "hello");System.out.println(v.get(0));System.out.println(v.size());v.clear();System.out.println(v.isEmpty());// 遍历的方式三种 普通for 迭代器 增强for}}
1.2 Set接口
Set接口存储一组唯一,无序的对象,不允许两个对象equals方法比较为true,并且hashCode相同
1.2.1 HashSet
HashSet 特点 :无序 不能重复 去除重复的原理 两个对象equals比较为true 并且hashCode相同 底层是由一个HashMap维护的
package com.qfedu.test4;import java.util.HashSet;import java.util.Iterator;/*** Set接口* HashSet 特点 :无序 不能重复 去除重复的原理 两个对象equals比较为true 并且hashCode相同* 底层是有一个HashMap维护的** @author WHD**/public class TestHashSet {public static void main(String[] args) {HashSet<String> set = new HashSet<String>();set.add("a");set.add("a");set.add("A");set.remove("a");for (String v : set) {System.out.println(v);}Iterator<String> iterator = set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}set.clear();System.out.println(set.isEmpty());System.out.println(set.size());HashSet<Student> stuSet = new HashSet<Student>();Student stu1 = new Student("赵四", 25);Student stu2 = new Student("赵四", 25);Student stu3 = new Student("赵四", 25);stuSet.add(stu1);stuSet.add(stu2);stuSet.add(stu3);System.out.println(stuSet.size());}}
package com.qfedu.test4;public class Student implements Comparable<Student>{private String name;private int 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;}public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student [name=" + name + ", age=" + age + "]";}@Overridepublic int compareTo(Student stu) {if(this.getAge() > stu.getAge()) {return 1;}else if(this.getAge() < stu.getAge() ) {return -1;}return 0;}@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 (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}}
1.2.2 TreeSet
TreeSet底层维护的是一个TreeMap 有序的Set集合 比较的顺序 元素必须实现Comparable接口,重写compareTo方法
package com.qfedu.test5;import java.util.Iterator;import java.util.TreeSet;import com.qfedu.test4.Student;/*** TreeSet底层维护的是一个TreeMap* 有序的Set集合 比较的顺序* @author WHD**/public class TestTreeSet {public static void main(String[] args) {TreeSet<String> set = new TreeSet<String>();set.add("a");set.add("d");set.add("f");set.add("c");for (String v : set) {System.out.println(v);}Iterator<String> iterator = set.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}TreeSet<Student> stuSet = new TreeSet<Student>();Student stu1 = new Student("赵四1", 26);Student stu2 = new Student("赵四2", 23);Student stu3 = new Student("赵四3", 25);stuSet.add(stu1);stuSet.add(stu2);stuSet.add(stu3);for (Student stu : stuSet) {System.out.println(stu);}}}
1.2.3 LinkedHashSet
一个基于双向链表的Set集合 有序的 插入顺序
package com.qfedu.test5;import java.util.Iterator;import java.util.LinkedHashSet;/*** 一个基于双向链表的Set集合 有序的 插入顺序* @author WHD**/public class TestLinkedHashSet {public static void main(String[] args) {LinkedHashSet<Integer> set = new LinkedHashSet<Integer>();set.add(110);set.add(11);set.add(12);set.add(3);set.remove(11);System.out.println(set.size());// set.clear();System.out.println(set.isEmpty());for (Integer i : set) {System.out.println(i);}Iterator<Integer> it = set.iterator();while(it.hasNext()) {System.out.println(it.next());}}}
2.Map接口
Map接口存储键值映射的数据
2.1 HashMap
HashMap:无序,键和值可以为null,键不能重复,线程不安全
常用方法
package com.qfedu.test6;import java.util.HashMap;/*** Map接口* HashMap常用方法* @author WHD**/public class Test1 {public static void main(String[] args) {HashMap<String,String> map = new HashMap<String,String>();map.put("CN", "中国");map.put("US", "美国");map.put("JP", "小日本");map.put("KR", "棒子");map.put("ID","阿三");System.out.println(map.size());System.out.println(map.remove("JP")); // 删除System.out.println(map.size()); // 长度map.put("CN", "中华人民共和国"); // 存放System.out.println(map.get("CN")); // 获取map.replace("US", "美国佬");System.out.println(map.get("US"));map.clear();System.out.println( map.isEmpty());}}
遍历方式
package com.qfedu.test7;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map.Entry;import java.util.Set;/*** HashMap 遍历方式* 1.获取所有的键* 2.获取所有的值* 3.获取所有的键的迭代器* 4.获取所有的值的迭代器* 5.获取所有的元素Entry数组* 6.获取所有的元素的迭代器* @author WHD**/public class Test1 {public static void main(String[] args) {HashMap<String,String> map = new HashMap<String,String>();map.put("CN", "中国");map.put("US", "美国");map.put("JP", "小日本");map.put("KR", "棒子");map.put("ID","阿三");// 1.获取所有的键Set<String> keySet = map.keySet();for(String key : keySet) {System.out.println(key + "\t" + map.get(key) );}System.out.println("=====================================");// 2. 获取所有的值Collection<String> values = map.values();for(String v : values) {System.out.println(v);}System.out.println("=====================================");// 3.获取键的迭代器Iterator<String> iterator = map.keySet().iterator();while(iterator.hasNext()) {String key = iterator.next();System.out.println(key + "\t" + map.get(key));}System.out.println("=====================================");// 4.获取所有的值的迭代器Iterator<String> iterator2 = map.values().iterator();while(iterator2.hasNext()) {System.out.println(iterator2.next());}System.out.println("=====================================");// 5.获取所有的键值对组合Set<Entry<String, String>> entrySet = map.entrySet();for(Entry<String,String> entry : entrySet) {System.out.println(entry.getKey() + entry.getValue());}System.out.println("=====================================");// 6.所有键值对组合的迭代器Iterator<Entry<String, String>> iterator3 = map.entrySet().iterator();while(iterator3.hasNext()) {Entry<String, String> next = iterator3.next();System.out.println(next.getKey() + next.getValue());}}}
数据结构 HashMap数据结构
回顾我们之前学过的两种数据结构: ArrayList基于数组的,因为有下标,所以查询、修改快,增删慢 LinkedList基于链表的,因为没有下标,所以查询、修改慢,增删快 以上两个数据结构是刚好互补的,如果能将两个数据结构结合在一起,完美~ 这只是理想状态,实际情况不会这么完美,另外结合在一起比较浪费空间 HashMap就是将两种数据结构结合在了一起 JDK7 数组 + 单向链表 JDK8 数组 + 单向链表 + 红黑树
HashMap数据的存放过程: HashMap中一个元素是一个Node(节点),一个节点包含四个部分:Key值,value值,根据key计算出来的hash值,下一个元素的引用next 当我们调用put方法往HashMap中存储数据,会先根据key的hash值找到当前元素应该存放在数组中的位置, 如果此位置没有元素,则直接存放, 如果此位置有元素,那么向下延伸为单向链表 如果链表的长度大于8并且元素的总个数超过64 那么单向链表转换为红黑树 在我们使用过程中,我们会删除元素,如果链表的长度小于6,将红黑树再次转换为链表
HashMap中两个重要的数值: 16 表示数组的长度为初始长度16 0.75 表示数组的使用率达到75% 就扩容 扩容两倍 resize() 方法
2.2 Hashtable
Hashtable JDK1.0 提供与HashMap相同的API 并且不允许null作为键或者值 线程安全 初始长度为11 负载因子0.75 扩容 rehash() 两倍+1
HashMap与Hashtable的区别? HashMap线程不安全 Hashtable线程安全 HashMap允许null键和值 Hashtable不允许 HashMapJDK1.2 Hashtable JDK1.0
package com.qfedu.test2;import java.util.Collection;import java.util.Hashtable;import java.util.Map.Entry;import java.util.Set;/*** Hashtable JDK1.0 提供与HashMap相同的API 并且不允许null作为键或者值 线程安全* 初始长度为11 负载因子0.75 扩容 rehash() 两倍+1* @author WHD**/public class TestHashtable {public static void main(String[] args) {Hashtable<Integer,String> table = new Hashtable<Integer,String>();table.put(1, "a");table.put(2, "b");table.put(3, "c");table.put(4, "d");// table.put(null, null);System.out.println(table.remove(1));System.out.println(table.size());table.replace(2, "hello");System.out.println(table.get(2));//table.clear();System.out.println(table.isEmpty());// 遍历方式与HashMap一致Set<Integer> keySet = table.keySet();for (Integer key : keySet) {System.out.println(table.get(key) + "\t" + key);}Collection<String> values = table.values();for (String v : values) {System.out.println(v);}Set<Entry<Integer, String>> entrySet = table.entrySet();for (Entry<Integer, String> entry : entrySet) {System.out.println(entry.getKey() + entry.getValue());}}}
2.3 LinkedHashMap
LinkedHashMap是基于双向链表的有序的Map集合 顺序为插入顺序
package com.qfedu.test3;import java.util.Collection;import java.util.LinkedHashMap;import java.util.Map.Entry;import java.util.Set;/*** LinkedHashMap是有序的Map集合 顺序为插入顺序* @author WHD**/public class TestLinkedHashMap {public static void main(String[] args) {LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();map.put("a", "A");map.put("b", "B");map.put("c", "C");map.put("d", "D");System.out.println(map.remove("a"));map.replace("b", "hello");System.out.println(map.get("b"));System.out.println(map.size());// map.clear();System.out.println(map.isEmpty());// 遍历方式与之前Map集合一致Set<String> keySet = map.keySet();for (String key : keySet) {System.out.println(key + "---" + map.get(key));}Collection<String> values = map.values();for (String v : values) {System.out.println(v);}Set<Entry<String, String>> entrySet = map.entrySet();for (Entry<String, String> entry : entrySet) {System.out.println(entry.getKey() + "===" + entry.getValue());}}}
2.3 TreeMap
基于树的Map集合 有序是按照键的比较顺序 使用自定义的类型作为TreeMap键 必须实现Comparable接口 重写compareTo方法 指定比较规则 否则运行报错 不能添加数据
package com.qfedu.test3;import java.util.Map.Entry;import java.util.Set;import java.util.TreeMap;/*** 基于树的Map集合 有序是按照键的比较顺序* 使用自定义的类型作为TreeMap键 必须实现Comparable接口 重写compareTo方法* 指定比较规则 否则运行报错 不能添加数据* @author WHD**/public class TestTreeMap {public static void main(String[] args) {TreeMap<Integer,String> map = new TreeMap<Integer,String>();map.put(1, "abc");map.put(20, "hello");map.put(17, "hhh");map.put(5, "666");// 其他方法 增删改查 是否为空 与之前map集合一致// 遍历方式与之前也一致Set<Integer> keySet = map.keySet();for (Integer key : keySet) {System.out.println(map.get(key) + "===" + key);}System.out.println("============================================");TreeMap<Student,String> map1 = new TreeMap<Student,String>();Student stu1 = new Student("赵四", 25);Student stu2 = new Student("广坤", 21);Student stu3 = new Student("大拿", 22);map1.put(stu1, "abc");map1.put(stu2, "abc");map1.put(stu3, "abc");Set<Entry<Student, String>> entrySet = map1.entrySet();for (Entry<Student, String> entry : entrySet) {System.out.println(entry.getKey());System.out.println(entry.getValue());}}}
package com.qfedu.test3;
public class Student implements Comparable<Student>{
private String name;
private int 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;
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student stu) {
if(this.getAge() > stu.getAge()) {
return 1;
}else if(this.getAge() < stu.getAge() ) {
return -1;
}
return 0;
}
}
2.4 Properties
Properties类用于存放成对的字符串数据 实际开发中用于读取配置文件(jdbc.properties)(log4j.properties) 所以此类不要使用从父类Hashtable继承来的put或者putAll方法 而应该使用setProperty()
package com.qfedu.test6;
import java.util.Properties;
/**
* Properties类用于存放成对的字符串数据 实际开发中用于读取配置文件
* 所以此类不要使用从父类Hashtable继承来的put或者putAll方法
* 而应该使用setProperty()
* @author WHD
*
*/
public class TestProperties {
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
System.getProperties().list(System.out);
Properties p = new Properties();
// p.put(1, "abc");
p.setProperty("a", "A");
p.setProperty("b", "B");
System.out.println(p.get("a"));
p.list(System.out);
}
}
3.Collections
Collections和Collection的区别? 前者是工具类 后者是集合父接口 工具类提供的有操作集合一些方法 比如查找集合最大、最小元素,集合排序等
package com.qfedu.test7;
import java.util.ArrayList;
import java.util.Collections;
/**
* Collections和Collection的区别?
* 前者是工具类 后者是集合父接口
* 工具类提供的有操作集合一些方法 比如查找集合最大、最小元素,集合排序等
* @author WHD
*
*/
public class TestCollections {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(101);
list.add(202);
list.add(30);
list.add(55);
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
Collections.sort(list);
System.out.println("============================");
for (Integer i : list) {
System.out.println(i);
}
// 二分查找的前提必须先排序
System.out.println(Collections.binarySearch(list, 101));
}
}
4. 泛型
泛型 用于统一数据类型 并且扩展代码 相当于是一个占位符 表示未知的类型
- 泛型不能类型转换 不能多态
- List<类型A> 表示此list只能存放A类型的数据
- 泛型应用场景:
- 类、方法、形参、接口
- 泛型字母表示的含义 通常是单词首字母
- T type 类型
- E Element 元素
- P Parameter 参数
- R Return 返回值
- K Key 键
- V Value 值
- 以上字母是业界公认有特定含义的简写 可以任意写字母 也可以小写 但是不要太随意
package com.qfedu.test7;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 泛型 用于统一数据类型 并且扩展代码 相当于是一个占位符 表示未知的类型
* 泛型不能类型转换 不能多态
* List<类型A> 表示此list只能存放A类型的数据
*
* 泛型应用场景:
* 类、方法、形参、接口
*
* 泛型字母表示的含义 通常是单词首字母
* T type 类型
* E Element 元素
* P Parameter 参数
* R Return 返回值
* K Key 键
* V Value 值
* 以上字母是业界公认有特定含义的简写 可以任意写字母 也可以小写 但是不要太随意
* @author WHD
*
*/
public class Test {
public static void main(String[] args) {
A<String> a = new A<String>();
a.m1("a");
a.m2();
A<Integer> a1 = new A<Integer>();
a1.m1(20);
a1.m2();
}
}
class A<T>{
void m1(T t) {
}
T m2() {
return null;
}
public static <P> List<P> m3() {
List<P> list = new ArrayList<P>();
return list;
}
}
interface B<P,R>{
R m1(P p);
}
class C implements B<String,Integer>{
@Override
public Integer m1(String p) {
return null;
}
}
class D implements B<Float,Character>{
@Override
public Character m1(Float p) {
return null;
}
}
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
class E{
void m1(Set<Animal> set) { }
// <? extends Animal> 表示Animal或者Animal的子类
void m2(List<? extends Animal> list) {}
// <? super Dog> 泛型为 可以是Dog类 或者Dog类的父类
void m3(Map<Set<? super Dog>,String> map) {}
}
