Java学习笔记(六)
List集合
java.util.List
接口继承自Collection
接口,是单列集合的一个重要分支,习惯性的会将实现了List
接口的对象称为List集合,在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
List接口的特点:
- 元素存取有序的集合
- 带有索引的集合
- 集合中可以有重复元素
常用方法(特有)
public void add(int index,E element)
:将指定的元素,添加到集合中的指定位置上public E get(int index)
:返回集合中指定位置的元素public E remove(int index)
:移除列表中指定位置的元素,返回的是被移除的元素public E set(int index,E element)
:用指定的元素替换集合中指定位置的元素,返回值为被替换的元素
注意:操作索引的时候,一定要防止索引越界异常
IndexOutOfBoundException
:集合索引越界异常ArrayIndexOutOfBoundException
:数组索引越界异常StringIndexOutOfBoundException
:字符串索引越界异常
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);//[a, b, c]
String s = list.get(1);
System.out.println(s);//b
String removeE = list.remove(2);
System.out.println(removeE);//c
list.add(1,"thomas");
System.out.println(list);//[a, thomas, b]
String result = list.set(2, "hello");//b
System.out.println(list);//[a, thomas, hello]
//集合的遍历
for (String s1 : list) {
System.out.println(s1);
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
List集合的子类
ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构,元素增删慢,查找快
LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构,方便元素添加、删除的集合,LinkedList是一个双向链表- 特点:
- 底层是一个链表结构:查询慢,增删快
- 里面包含了大量操作首尾元素的方法
注意:使用LinkedList集合特有的方法不能使用多态
public void addFirst(E e)
:将指定元素插入此列表的开头public void addLast(E e)
:将指定元素添加到此列表的结尾public E getFirst()
:返回此列表的第一个元素public E getLast()
:返回此列表的最后一个元素public E removeFirst()
:移除并返回此列表的第一个元素public E removeLast()
:移除并返回此列表的最后一个元素public E pop()
:从此列表所表示的堆栈处弹出一个元素public void push(E e)
:将元素推入此列表所表示的堆栈public boolean isEmpty()
:如果列表不包含元素,则返回true
public class Test {
public static void main(String[] args) {
LinkedList<String> linked = new LinkedList<>();
linked.add("a");
linked.add("b");
linked.add("c");
System.out.println(linked);//[a, b, c]
linked.addFirst("thomas");//[thomas, a, b, c]
linked.push("thomas");//[thomas, a, b, c]
System.out.println(linked);
linked.addLast("hello");
System.out.println(linked);//[thomas, a, b, c, hello]
System.out.println(linked.getFirst());//thomas
System.out.println(linked.getLast());//hello
System.out.println(linked.removeFirst());//thomas
System.out.println(linked);//[a, b, c,hello]
System.out.println(linked.removeLast());//hello
System.out.println(linked);//[a, b, c]
String pop = linked.pop();
System.out.println(pop);//thomas
System.out.println(linked);//[a, b, c]
boolean empty = linked.isEmpty();
System.out.println(empty);//false
}
}
Vector集合
-
Vector
类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是,Vector
的大小可以根据需要增长或缩小,以适应在创建Vector
之后添加和删除项目。 -
从Java 2平台v1.2,这个类被改造为实现
List
接口,使其成为成员Java Collections Framework
。 与新集合实现不同,Vector
是同步的。 如果不需要线程安全的实现,建议使用ArrayList
代替Vector
。
Set集合
-
java.util.Set
接口和java.util.List
接口一样,同样继承于Collection
接口,它与Collection
接口中的方法基本一致,并没有对Collection
接口进行功能上的扩充,只是比Collection
更加严格了。与List
接口不同的是,Set
接口中的元素无序,并都会以某种规则保证纯如的元素不出现重复 -
Set
集合有多个子类,以下介绍其中java.util.HashSet
、java.util.LinkedHashSet
这两个集合 -
特点:
1、不允许存储重复元素
2、没有索引没有带索引的方法也不能使用普通的for循环遍历
Set集合取出元素的方式可以采用:迭代器、增强for循环
HashSet集合
-
java.util.HashSet
集合是Set
集合的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的。java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持 -
HashSet
是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode
和equals
方法 -
特点:
1、不允许存储重复元素
2、没有索引没有带索引的方法也不能使用普通的for循环遍历
3、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4、底层是一个哈希表结构(查询速度非常快)
public class Test {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(3);
set.add(2);
set.add(1);
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());//1 2 3
}
System.out.println("----------------");
for (Integer i : set) {
System.out.println(i);//1 2 3
}
}
}
哈希值
- 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
在Object类中有一个方法,可以获取对象的哈希值
-
int hashCode()
:返回对象的哈希码值hashCode方法的源码:
public native int hashCode();//native:代表该方法调用的是本地操作系统的方法
public class Test { public static void main(String[] args) { //Person类继承了Object类,所以可以使用Object类的hashCode方法 Person p = new Person(); int i = p.hashCode(); System.out.println(i);//824909230 Person p1 = new Person(); System.out.println(p1.hashCode());//122883338 /* * toString()源码: * public String toString() { * return getClass().getName() + "@" + Integer.toHexString(hashCode()); * } * */ System.out.println(p);//com.thomas.test.Person@312b1dae System.out.println(p1);//com.thomas.test.Person@7530d0a /* * String类的哈希值 * String类重写了Object类的hashCode方法 * */ String s = new String("abc"); String s1 = new String("abc"); System.out.println(s.hashCode());//96354 System.out.println(s1.hashCode());//96354 System.out.println("重地".hashCode());//1179395 System.out.println("通话".hashCode());//1179395 } }
HashSet集合存储数据的结构(哈希表)
- 在JDK 1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一个hash值的链表都存储在一个链表中,但是当位于一个同种的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低,而在JDK 1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值**(8)**的时候,将链表转换为红黑树,这样大大减少了查找时间
Set集合存储元素不重复的原理
HashSet存储自定义类型元素
- 给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
public class Person {
private String name;
private int age;
public Person() {
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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 age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
/*
* HashSet集合存储自定义的元素
* Set集合存储元素唯一,存储的元素(String,Integer,....Student,Person),必须重写hashCode和equals方法
*要求:
* 同名同年龄的人,视为一个人,只能存放一次
* */
public class Test {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("tom",18);
Person p2 = new Person("tom",18);
Person p3 = new Person("tom",20);
System.out.println(p1.hashCode());//3566785
System.out.println(p2.hashCode());//3566785
System.out.println(p1.equals(p2));//true
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);//[Person{name='tom', age=20}, Person{name='tom', age=18}]
}
}
LinkedHashSet
-
HashSet保证元素唯一,可是元素存放进去是没有顺序的,在HashSet下面有一个子类
java.util.LinkedHashSet
,它是一个链表和哈希表组合的一个数据存储结构 -
特点:
底层是一个哈希表(数组+链表/红黑树)+链表;多了一条链表 (记录元素的存储顺序),保证元素有序
public class Test {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("ccc");
set.add("bbb");
set.add("aaa");
set.add("bbb");
System.out.println(set);//[aaa, ccc, bbb] 无序的,不允许重复
LinkedHashSet<String> linked = new LinkedHashSet<>();
linked.add("bbb");
linked.add("ccc");
linked.add("bbb");
linked.add("aaa");
System.out.println(linked);//[bbb, ccc, aaa] 有序的,不允许重复
}
}
可变参数
-
可变参数:是JDK 1.5之后出现的新特性
-
使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定时就可以使用可变参数
-
使用格式:
修饰符 返回值类型 方法名(数据类型...变量名){ }
-
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递的参数个数可以时0个,1个也可以是多个
-
注意事项:
一个方法的参数列表,只能有一个可变参数
如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
-
可变参数的特殊(终结)写法
修饰符 返回值类型 方法名(Object...obj){ }
public class Test {
public static void main(String[] args) {
int result = add(10, 20, 30, 50);//110
System.out.println(result);
int result1 = add(10, 20);//30
System.out.println(result1);
}
/*
* 定义计算(0-n)个整数和的方法
* 已知:计算整数的和,数据类型已经确定int
* 但是参数个数不确定,使用可变参数处理
* add();创建一个长度为0的数组 new int[0];
* add(10);创建一个长度为1的数组 new int[]{10};
* add(10,20);创建一个长度为2的数组 new int[]{10,20};
* ........
* */
private static int add(int...arr) {
// System.out.println(arr);//[I@27973e9b 底层是一个数组
// System.out.println(arr.length);//0
int sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
}
}
Collections
java.util.Collections
集合工具类,用来对集合进行操作
常用功能
public static <T> boolean addAll(Collection<T> c,T... elements)
:往集合中添加一些元素public static void shuffle(List<?> list)
:打乱集合顺序public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序public static <T> void sort(List<T> list,Comparator<? super T>)
:将集合中元素按照指定规则排序
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
System.out.println(list);//[a, b, c, d, e]
Collections.shuffle(list);
System.out.println(list);//[d, a, e, c, b]
}
}
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
//(this,参数)
return this.getAge() - o.getAge();//根据年龄升序
// return o.getAge() - this.getAge();//根据年龄降序
}
}
/*
* `public static <T> void sort(List<T> list)`:将集合中元素按照默认规则排序
* 注意:
* sort(List<T> list)使用前提:
* 被排序的集合中存储的元素,必须实现Comparable接口,重写接口中的compareTo方法定义排序规则
* Integer,String都实现了Comparable接口,
* 自定义的类对象的集合使用sort排序,类对象必须实现Comparable接口,重写接口的compareTo方法定义排序规则
* */
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
Collections.sort(list01);
System.out.println(list01);//[1, 2, 3]
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("c");
list02.add("b");
System.out.println(list02);//[a, c, b]
Collections.sort(list02);
System.out.println(list02);//[a, c, b]
ArrayList<Person> list03 = new ArrayList<>();
list03.add(new Person("张三",20));
list03.add(new Person("李四",18));
list03.add(new Person("王五",22));
System.out.println(list03);//[Person{name='张三', age=20}, Person{name='李四', age=18}, Person{name='王五', age=22}]
Collections.sort(list03);
System.out.println(list03);//[Person{name='李四', age=18}, Person{name='张三', age=20}, Person{name='王五', age=22}]
}
}
/*
* `public static <T> void sort(List<T> list,Comparator<? super T>)`:将集合中元素按照指定规则排序
* Comparator和Comparable的区别:
* Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口重写比较规则的compareTo方法
* Comparator:相当于找一个第三方裁判进行比较
* */
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(3);
list01.add(1);
list01.add(2);
System.out.println(list01);//[3, 1, 2]
Collections.sort(list01, new Comparator<Integer>() {
//定义排序规则
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;//升序
//return o2 - o1;//降序
}
});
System.out.println(list01);//[1, 2, 3]
ArrayList<Person> list02 = new ArrayList<>();
list02.add(new Person("a张三",18));
list02.add(new Person("李四",23));
list02.add(new Person("王五",20));
list02.add(new Person("b张三",18));
System.out.println(list02);//[Person{name='a张三', age=18}, Person{name='李四', age=23}, Person{name='王五', age=20}, Person{name='b张三', age=18}]
Collections.sort(list02, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
//按照年龄升序
int result = o1.getAge() - o2.getAge();
//如果两个人年龄相同,使用姓名的第一个字母比较
if (result == 0){
result = o1.getName().charAt(0) - o2.getName().charAt(0);
}
return result;
}
});
System.out.println(list02);//[Person{name='a张三', age=18}, Person{name='b张三', age=18}, Person{name='王五', age=20}, Person{name='李四', age=23}]
}
}
Map集合
Collection
中的集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储Map
中的集合,元素是成对存在的,每个元素有键与值两部分组成,通过键可以找到对应的值Collection
中的集合被称为单列集合,Map
中的集合被称为双列集合- 需要注意的是,
Map
中的集合不能包含重复的键,值可以重复,每个键只能对应一个值
java.util.Map<K,V>
集合
特点:
- Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
- Map集合中的元素,key和value的数据类型可以相同,也可以不同
- Map集合中的元素,key是不允许重复的,value是可以重复的
- Map集合中的元素,key和value是一一对应的
Map集合的常用子类
-
HashMap<K,V>
:存储数据采用哈希表结构,元素的存取顺序不能保证一致,由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法java.util.HashMap<K,V>
集合implements Map<K,V>
接口特点:
1、HashMap集合底层是哈希表:查询速度特别快
JDK 1.8之前使用的是数组+单向链表
JDK 1.8之后使用的是数组+单向链表/红黑树(链表长度超过8),提高查询速度
2、HashMap集合是一个无序的集合,存储元素和取出全速的顺序可能不一致
-
LinkedHashMap<K,V>
:HashMap下有一个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构,通过链表结构可以保证元素的存取顺序一致,通过哈希表结构可以保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法java.util.LinkdeHashMap<K,V>
集合extends HashMap<K,V>
集合特点:
1、LinkdeHashMap集合的底层是哈希表+链表(保证迭代的顺序)
2、LinkdeHashMap集合是一个有序的集合,存储和取出元素的顺序是一致的
Map接口中的集合都有两个泛型<K,V>在使用时,要为两个泛型变量赋予数据类型,两个泛型变量<K,V>的数据类型可以相同,也可以不同
Map接口中的常用方法
public V put(K key,V value)
:把指定的键与指定的值添加到Map集合中public V remove(Object key)
:把指定的键所对应的键值对元素在Map中删除,返回被删除的元素boolean containsKey(Object key)
:判断集合中是否包含指定的键public V get(Object key)
:根据指定的键,在Map集合中获取对应的值public Set<K> keySet()
:获取Map集合中的所有键,存储到Set集合中public Set<Map.Entry<K,V>> entrySet()
:获取到Map集合中所有的键值对对象的集合
public class Test {
public static void main(String[] args) {
//show01();
//show02();
//show03();
}
/*
* `public V get(Object key)`:根据指定的键,在Map集合中获取对应的值
* 返回值 V:key存在,返回对应的value,key存在返回null
* `boolean containsKey(Object key)`:判断集合中是否包含指定的键
* 存在返回true不存在返回false
* */
private static void show03() {
Map<String,Integer> map = new HashMap<>();
map.put("1",555);
map.put("2",666);
map.put("3",777);
Integer i = map.get("3");
System.out.println(i);//777
System.out.println(map.get("5"));//null
System.out.println(map.containsKey("3"));//true
System.out.println(map.containsKey("5"));//false
}
/*
* `public V remove(Object key)`:把指定的键所对应的键值对元素在Map中删除,返回被删除的元素
* 返回值 V:key存在,v是被删除的值,key不存在,v的值为null
* */
private static void show02() {
Map<String, Integer> map = new HashMap<>();
map.put("1",111);
map.put("2",222);
map.put("3",333);
System.out.println(map);//{1=111, 2=222, 3=333}
Integer i = map.remove("1");
System.out.println(i);//111
System.out.println(map);//{2=222, 3=333}
Integer i1 = map.remove("4");
System.out.println(i1);//null
}
/*
*`public V put(K key,V value)`:把指定的键与指定的值添加到Map集合中
* 返回值 V:存储键值对的时候,key不重复,返回值为null
* 存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
* */
private static void show01() {
Map<String, String> map = new HashMap<>();
// String v1 = map.put("第一个", "abc");
// System.out.println(v1);//null
// String v2 = map.put("第一个", "cde");
// System.out.println(v2);//abc
// System.out.println(map);//{第一个=cde}
map.put("1","001");
map.put("2","002");
map.put("3","003");
System.out.println(map);//{1=001, 2=002, 3=003}
}
}
Map集合遍历键找值方法
-
键找值方法:通过元素中的键,获取键所对应的值
-
步骤:
1、获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键(
keySet()
)2、遍历键的Set集合,得到每一个键
3、根据键,获取所对应的值(
get(K key)
)
/*
`public Set<K> keySet()`:获取Map集合中的所有键,存储到Set集合中
*/
Map<String,Integer> map = new HashMap<>();
map.put("1",555);
map.put("2",666);
map.put("3",777);
Set<String> keys = map.keySet();
for (String key : keys) {
Integer value = map.get(key);
System.out.println("key: " + key + " = value:" + value);
//key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
}
System.out.println("-----------------");
Iterator<String> it = keys.iterator();
while (it.hasNext()){
String key = it.next();
Integer value = map.get(key);
System.out.println("key: " + key + " = value:" + value);
//key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
}
Entry键值对对象
Map
中存放的是两个对象,一个是key(键)
,一个是value(值)
,它们在Map
中是一一对应的关系,这一对对象又称Map
中的一个Entry(项)
,Entry
将键值对的对应关系封装成了对象,即键值对对象,这样我们在遍历Map
集合的时候,就可以从每一个键值对对象(Entry)
中获取对应的键与对应的值public K getKey()
:获取Entry对象中的键public V getValue()
:获取Entry对象中的值- 在Map集合中也提供了获取所有Entry对象的方法:
public Set<Map.Entry<K,V>> entrySet()
:获取到Map集合中所有的键值对对象的集合
/*
Map集合遍历的第二种方式:使用Entry对象遍历
*/
public class Test {
public static void main(String[] args) {
show01();
}
/*
* `public Set<Map.Entry<K,V>> entrySet()`:获取到Map集合中所有的键值对对象的集合
* Map.Entry<K,V>:在Map接口中有一个内部接口Entry
* 作用:当Map集合一创建,那么会在Map集合中创建一个Entry对象,用来记录键与值
* * */
private static void show01() {
Map<String,Integer> map = new HashMap<>();
map.put("1",555);
map.put("2",666);
map.put("3",777);
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
for (Map.Entry<String, Integer> entry : entrySet) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("key: " + key + " = value:" + value);
//key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
//System.out.println(entry);//1=555,2=666,3=777
}
System.out.println("---------------------");
Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("key: " + key + " = value:" + value);
//key: 1 = value:555 key: 2 = value:666 key: 3 = value:777
}
}
}
HashMap存储自定义类型键值对
- Map集合保证key是唯一的:作为key元素,必须重写
hashCode
方法和equals
方法,以保证key唯一
public class Person {
private String name;
private int age;
public Person() {
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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 age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Test {
public static void main(String[] args) {
//show01();
show02();
}
/*
* key:Person类型
* Person类型必须重写hashCode和equals方法以保证key唯一
* value:String类型
* 可以重复
* */
private static void show02() {
HashMap<Person,String> map = new HashMap<>();
map.put(new Person("女王",18),"英国");
map.put(new Person("普京",30),"俄罗斯");
map.put(new Person("奥巴马",31),"美国");
map.put(new Person("女王",18),"毛里求斯");
Set<Map.Entry<Person, String>> entrySet = map.entrySet();
for (Map.Entry<Person, String> entry : entrySet) {
System.out.println(entry.getKey()+"---->"+entry.getValue());
//Person{name='奥巴马', age=31}---->美国
// Person{name='女王', age=18}---->毛里求斯
// Person{name='普京', age=30}---->俄罗斯
}
}
/*
* key:String类型
* String类型重写了hashCode和equals方法,保证key唯一
* value:Person
* value可以重复(同名同年龄的视为一个人)
* */
private static void show01() {
HashMap<String,Person> map = new HashMap<>();
map.put("北京",new Person("张三",18));
map.put("上海",new Person("李四",20));
map.put("西安",new Person("王五",19));
map.put("北京",new Person("赵六",18));
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key+"--->"+map.get(key));
}
}
}
LinkedHashMap
HashMap
保证元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,我们可以通过LinkedHashMap
去解决- 在
HashMap
下面有一个子类LinkedHashMap
,它是链表和哈希表组合的一个数据存储结构,记录元素的顺序
public class Test {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1","aaa");
map.put("3","ccc");
map.put("2","bbb");
map.put("1","aaa");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + "--->" + entry.getValue());
//1--->aaa
//2--->bbb key不允许重复,无序
//3--->ccc
}
System.out.println("---------------------");
LinkedHashMap<String, String> linked = new LinkedHashMap<>();
linked.put("1","aaa");
linked.put("3","ccc");
linked.put("2","bbb");
linked.put("1","aaa");
Set<Map.Entry<String, String>> entrySet1 = linked.entrySet();
for (Map.Entry<String, String> entry1 : entrySet1) {
System.out.println(entry1.getKey() + "--->" + entry1.getValue());
//1--->aaa
//3--->ccc key不允许重复,有序
//2--->bbb
}
}
}
Hashtable集合
-
java.util.Hashtable<K,V>
结合实现了Map<K,V>
接口 -
Hashtable:
1、底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
2、Hashtable不能存储null值和null键
-
HashMap:
1、底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
2、HashMap可以存储null值和null键
-
Hashtable
和Vector
集合一样,在JDK 1.2版本之后被更先进的集合(HashMap,ArrayList
)取代了 -
Hashtable
的子类Properties
依然在使用,Properties
集合是唯一一个和IO流结合的集合
public class Test {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put(null,"a");
map.put("a",null);
map.put(null,null);
System.out.println(map);//{null=null, a=null}
System.out.println("----------------------");
Hashtable<String, String> table = new Hashtable<>();
table.put(null,"a");//NullPointerException
table.put("a",null);//NullPointerException
table.put(null,null);//NullPointerException
System.out.println(table);
}
}
JDK9对集合添加的优化
-
JDK 9的新特性:
1、List接口、Set接口、Map接口,里面添加了一个静态方法of,可以给集合一次性添加多个元素
2、
static <E> List<E> of (E... elements)
3、使用前提:当即和中存储的元素的个数已经确定了,不再改变时
-
注意:
1、of方法只适用于List接口、Set接口、Map接口,不适用于接口的实现类
2、of方法的返回值是一个不能改变的集合,集合不能再使用add、put方法添加元素,会抛出异常
3、Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
public class Test {
public static void main(String[] args) {
List<String> list = List.of("a", "b", "a", "c", "d");
System.out.println(list);//[a, b, a, c, d]
//list.add("x");//UnsupportedOperationException不支持操作异常
//IllegalArgumentException: duplicate element: a
//非法参数异常,有重复元素a
//Set<String> set = Set.of("a", "b", "a", "c", "d");
Set<String> set = Set.of("a", "b", "c", "d");
System.out.println(set);//[a, d, c, b]
//set.add("x");//UnsupportedOperationException不支持操作异常
//IllegalArgumentException: duplicate key: 张三
//非法参数异常,有重复的键张三
//Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20, "张三", 19);
Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
System.out.println(map);//{王五=20, 李四=19, 张三=18}
//map.put("赵六",25);//UnsupportedOperationException不支持操作异常
}
}