Java集合中List,Set以及Map等集合
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java集合中List,Set以及Map等集合,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含37323字,纯文字阅读大概需要54分钟。
内容图文
![Java集合中List,Set以及Map等集合](/upload/InfoBanner/zyjiaocheng/610/7e91e7c1ecfe418d85a07cf6d732fa2c.jpg)
目录
1.概述
- List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口
- Set下有HashSet,LinkedHashSet,TreeSet
- List下有ArrayList,Vector,LinkedList
- Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
- Collection接口下还有个Queue接口,有PriorityQueue类
- Queue接口与List、Set同一级别,都是继承了Collection接口。
- 看图你会发现,LinkedList既可以实现Queue接口,也可以实现List接口.只不过呢, LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。
- SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)中的元素一定是有序的
2.List集合
List 有序,可重复
- ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高- Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低- LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高
1.list中添加,获取,删除元素
添加方法是:.add(e); 获取方法是:.get(index); 删除方法是:.remove(index); 按照索引删除; .remove(Object o); 按照元素内容删除;
List<String> person=new ArrayList<>();
person.add("jackie"); //索引为0 //.add(e)
person.add("peter"); //索引为1
person.add("annie"); //索引为2
person.add("martin"); //索引为3
person.add("marry"); //索引为4
person.remove(3); //.remove(index)
person.remove("marry"); //.remove(Object o)
String per="";
per=person.get(1);
System.out.println(per); .get(index)
for (int i = 0; i < person.size(); i++) {
System.out.println(person.get(i)); //.get(index)
}
2.list中是否包含某个元素;
方法:.contains(Object o); 返回true或者false
List<String> fruits=new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("桃子");
//for循环遍历list
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i));
}
String appleString="苹果";
//true or false
System.out.println("fruits中是否包含苹果:"+fruits.contains(appleString));
if (fruits.contains(appleString)) {
System.out.println("我喜欢吃苹果");
}else {
System.out.println("我不开心");
}
3.list中根据索引将元素数值改变(替换);
注意 .set(index, element); 和 .add(index, element); 的不同;
String a="白龙马", b="沙和尚", c="八戒", d="唐僧", e="悟空";
List<String> people=new ArrayList<>();
people.add(a);
people.add(b);
people.add(c);
people.set(0, d); //.set(index, element); //将d唐僧放到list中索引为0的位置,替换a白龙马
people.add(1, e); //.add(index, element); //将e悟空放到list中索引为1的位置,原来位置的b沙和尚后移一位
//增强for循环遍历list
for(String str:people){
System.out.println(str);
}
4.list中查看(判断)元素的索引;
注意:.indexOf(); 和 lastIndexOf()的不同;
List<String> names=new ArrayList<>();
names.add("刘备"); //索引为0
names.add("关羽"); //索引为1
names.add("张飞"); //索引为2
names.add("刘备"); //索引为3
names.add("张飞"); //索引为4
System.out.println(names.indexOf("刘备"));
System.out.println(names.lastIndexOf("刘备"));
System.out.println(names.indexOf("张飞"));
System.out.println(names.lastIndexOf("张飞"));
5.根据元素索引位置进行的判断;
if (names.indexOf("刘备")==0) {
System.out.println("刘备在这里");
}else if (names.lastIndexOf("刘备")==3) {
System.out.println("刘备在那里");
}else {
System.out.println("刘备到底在哪里?");
}
6.利用list中索引位置重新生成一个新的list(截取集合);
方法: .subList(fromIndex, toIndex); .size() ; 该方法得到list中的元素数的和
List<String> phone=new ArrayList<>();
phone.add("三星"); //索引为0
phone.add("苹果"); //索引为1
phone.add("锤子"); //索引为2
phone.add("华为"); //索引为3
phone.add("小米"); //索引为4
//原list进行遍历
for(String pho:phone){
System.out.println(pho);
}
//生成新list
phone=phone.subList(1, 4); //.subList(fromIndex, toIndex) //利用索引1-4的对象重新生成一个list,但是不包含索引为4的元素,4-1=3
for (int i = 0; i < phone.size(); i++) { // phone.size() 该方法得到list中的元素数的和
System.out.println("新的list包含的元素是"+phone.get(i));
}
7.对比两个list中的所有元素;
两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象
//1.<br>if (person.equals(fruits)) {
System.out.println("两个list中的所有元素相同");
}else {
System.out.println("两个list中的所有元素不一样");
}
//2.
if (person.hashCode()==fruits.hashCode()) {
System.out.println("我们相同");
}else {
System.out.println("我们不一样");
}
8.判断list是否为空;
空则返回true,非空则返回false
if (person.isEmpty()) {
System.out.println("空的");
}else {
System.out.println("不是空的");
}
9.返回Iterator集合对象;
System.out.println("返回Iterator集合对象:"+person.iterator());
10.将集合转换为字符串;
String liString="";
liString=person.toString();
System.out.println("将集合转换为字符串:"+liString);
11.将集合转换为数组;
System.out.println("将集合转换为数组:"+person.toArray());
12.集合类型转换;
//1.默认类型
List<Object> listsStrings=new ArrayList<>();
for (int i = 0; i < person.size(); i++) {
listsStrings.add(person.get(i));
}
//2.指定类型
List<StringBuffer> lst=new ArrayList<>();
for(String string:person){
lst.add(StringBuffer(string));
}
13.去重复;
List<String> lst1=new ArrayList<>();
lst1.add("aa");
lst1.add("dd");
lst1.add("ss");
lst1.add("aa");
lst1.add("ss");
//方法 1.
for (int i = 0; i <lst1.size()-1; i++) {
for (int j = lst1.size()-1; j >i; j--) {
if (lst1.get(j).equals(lst1.get(i))) {
lst1.remove(j);
}
}
}
System.out.println(lst1);
//方法 2.
List<String> lst2=new ArrayList<>();
for (String s:lst1) {
if (Collections.frequency(lst2, s)<1) {
lst2.add(s);
}
}
System.out.println(lst2);
附完整代码
package MyTest01;
?
import java.util.ArrayList;
import java.util.List;
?
public class ListTest01 {
?
?public static void main(String[] args) {
?
??//list中添加,获取,删除元素
??List<String> person=new ArrayList<>();
??person.add("jackie"); //索引为0 //.add(e)
??person.add("peter"); //索引为1
??person.add("annie"); //索引为2
??person.add("martin"); //索引为3
??person.add("marry"); //索引为4
?
??person.remove(3); //.remove(index)
??person.remove("marry"); //.remove(Object o)
?
??String per="";
??per=person.get(1);
??System.out.println(per); .get(index)
?
??for (int i = 0; i < person.size(); i++) {
??System.out.println(person.get(i)); //.get(index)
??}
?
?
?
??//list总是否包含某个元素
??List<String> fruits=new ArrayList<>();
??fruits.add("苹果");
??fruits.add("香蕉");
??fruits.add("桃子");
??//for循环遍历list
??for (int i = 0; i < fruits.size(); i++) {
??System.out.println(fruits.get(i));
??}
??String appleString="苹果";
??//true or false
??System.out.println("fruits中是否包含苹果:"+fruits.contains(appleString));
?
??if (fruits.contains(appleString)) {
??System.out.println("我喜欢吃苹果");
??}else {
??System.out.println("我不开心");
??}
?
??//list中根据索引将元素数值改变(替换)
??String a="白龙马", b="沙和尚", c="八戒", d="唐僧", e="悟空";
??List<String> people=new ArrayList<>();
??people.add(a);
??people.add(b);
??people.add(c);
??people.set(0, d); //.set(index, element) //将d唐僧放到list中索引为0的位置,替换a白龙马
??people.add(1, e); //.add(index, element); //将e悟空放到list中索引为1的位置,原来位置的b沙和尚后移一位
?
??//增强for循环遍历list
??for(String str:people){
??System.out.println(str);
??}
?
??//list中查看(判断)元素的索引
??List<String> names=new ArrayList<>();
??names.add("刘备"); //索引为0
??names.add("关羽"); //索引为1
??names.add("张飞"); //索引为2
??names.add("刘备"); //索引为3
??names.add("张飞"); //索引为4
??System.out.println(names.indexOf("刘备"));
??System.out.println(names.lastIndexOf("刘备"));
??System.out.println(names.indexOf("张飞"));
??System.out.println(names.lastIndexOf("张飞"));
?
??//根据元素索引位置进行的判断
??if (names.indexOf("刘备")==0) {
??System.out.println("刘备在这里");
??}else if (names.lastIndexOf("刘备")==3) {
??System.out.println("刘备在那里");
??}else {
??System.out.println("刘备到底在哪里?");
??}
?
??//利用list中索引位置重新生成一个新的list(截取集合)
??List<String> phone=new ArrayList<>();
??phone.add("三星"); //索引为0
??phone.add("苹果"); //索引为1
??phone.add("锤子"); //索引为2
??phone.add("华为"); //索引为3
??phone.add("小米"); //索引为4
??//原list进行遍历
??for(String pho:phone){
??System.out.println(pho);
??}
??//生成新list
??phone=phone.subList(1, 4); //.subList(fromIndex, toIndex) //利用索引1-4的对象重新生成一个list,但是不包含索引为4的元素,4-1=3
??for (int i = 0; i < phone.size(); i++) { // phone.size() 该方法得到list中的元素数的和
??System.out.println("新的list包含的元素是"+phone.get(i));
??}
?
??//对比两个list中的所有元素
??//两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象
??if (person.equals(fruits)) {
??System.out.println("两个list中的所有元素相同");
??}else {
??System.out.println("两个list中的所有元素不一样");
??}
?
??if (person.hashCode()==fruits.hashCode()) {
??System.out.println("我们相同");
??}else {
??System.out.println("我们不一样");
??}
?
?
??//判断list是否为空
??//空则返回true,非空则返回false
??if (person.isEmpty()) {
??System.out.println("空的");
??}else {
??System.out.println("不是空的");
??}
?
??//返回Iterator集合对象
??System.out.println("返回Iterator集合对象:"+person.iterator());
?
??//将集合转换为字符串
??String liString="";
??liString=person.toString();
??System.out.println("将集合转换为字符串:"+liString);
?
??//将集合转换为数组,默认类型
??System.out.println("将集合转换为数组:"+person.toArray());
?
??将集合转换为指定类型(友好的处理)
??//1.默认类型
??List<Object> listsStrings=new ArrayList<>();
??for (int i = 0; i < person.size(); i++) {
??listsStrings.add(person.get(i));
??}
??//2.指定类型
??List<StringBuffer> lst=new ArrayList<>();
??for(String string:person){
??lst.add(StringBuffer(string));
??}
?
?
?
?
?}
?
?private static StringBuffer StringBuffer(String string) {
?return null;
?}
?
?
?}
ArrayList集合
package com.xt.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
/**
* List 是一个接口
* ArrayList是实现List接口的实现类,内部是一个大小可变的数组
* <String>代表泛型 ,泛型的意思是ArrayList中存的值类型
*/
List<String > names=new ArrayList<String>();
//ArrayList变量.add("泛型型的数据"):添加数据
names.add("张安顺");
names.add("李四");
//ArrayList变量.size():返回大小
for(int i=0;i<names.size();i++) {
//ArrayList变量.get(int型数值):返回下标为该数的存的值
System.out.println(names.get(i));
}
//ArrayList变量.add(index,"##"):表示吧##插入到下标为index的位置,后面的值下标依次往后移
names.add(1, "李银霞");
System.out.println(names.isEmpty());
//ArrayList变量.clear():清除所有数据
//names.clear();
System.out.println(names.isEmpty());
//加强For循环来遍历数组
for (String name : names) {
System.out.println(name);
}
System.out.println("******************************************");
//ArrayList变量.set(Index,"值"):把下标为index的地方替换成"值"
names.set(0, "W卓");
//第三种遍历方法:用迭代器方法。Arraylist变量.iterator()把数组中的值放到了迭代器中,然后在迭代器中遍历
//iterator.hasNext():下标后移,并且判断是否有数据了 iterator.next()就是值
Iterator<String> iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("******************************************");
//ArrayList变量.remove(index):表示把下标为index的值删掉,后面的值下标向前移动
names.remove(1);
Iterator<String> it=names.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println(names.get(1));
}
}
LinkedList集合
add
boolean add(E e):在链表后添加一个元素,如果成功,返回true,否则返回false;
void addFirst(E e):在链表头部插入一个元素;
addLast(E e):在链表尾部添加一个元素;
void add(int index, E element):在指定位置插入一个元素。
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("first");
linkedList.add("second");
linkedList.add("third");
System.out.println(linkedList);
linkedList.addFirst("addFirst");
System.out.println(linkedList);
linkedList.addLast("addLast");
System.out.println(linkedList);
linkedList.add(2, "addByIndex");
System.out.println(linkedList);
}
}
输出:
[first, second, third]
[addFirst, first, second, third]
[addFirst, first, second, third, addLast]
[addFirst, first, addByIndex, second, third, addLast]
remove
E remove();移除链表中第一个元素;
boolean remove(Object o):移除链表中指定的元素;
E remove(int index):移除链表中指定位置的元素;
E removeFirst():移除链表中第一个元素,与remove类似;
E removeLast():移除链表中最后一个元素;
boolean removeFirstOccurrence(Object o):移除链表中第一次出现所在位置的元素;
boolean removeLastOccurrence(Object o):移除链表中最后一次出现所在位置的元素;
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("first");
linkedList.add("second");
linkedList.add("second");
linkedList.add("third");
linkedList.add("four");
linkedList.add("five");
System.out.println(linkedList);
linkedList.remove();
System.out.println("remove: " + linkedList);
linkedList.remove("second");
System.out.println("remove(Object): " + linkedList);
linkedList.remove("six");
System.out.println("remove(Object) not exist: " + linkedList);
linkedList.remove(2);
System.out.println("remove(index): " + linkedList);
linkedList.removeFirst();
System.out.println("removeFirst: " + linkedList);
linkedList.removeLast();
System.out.println("removeLast:" + linkedList);
System.out.println("----------------------------------");
linkedList.clear();
linkedList.add("first");
linkedList.add("second");
linkedList.add("first");
linkedList.add("third");
linkedList.add("first");
linkedList.add("five");
System.out.println(linkedList);
linkedList.removeFirstOccurrence("first");
System.out.println("removeFirstOccurrence: " + linkedList);
linkedList.removeLastOccurrence("first");
System.out.println("removeLastOccurrence: " + linkedList);
}
}
输出:
[first, second, second, third, four, five]
remove: [second, second, third, four, five]
remove(Object): [second, third, four, five]
remove(Object) not exist: [second, third, four, five]
remove(index): [second, third, five]
removeFirst: [third, five]
removeLast:[third]
----------------------------------
[first, second, first, third, first, five]
removeFirstOccurrence: [second, first, third, first, five]
removeLastOccurrence: [second, first, third, five]
get
E get(int index):按照下边获取元素;
E getFirst():获取第一个元素;
E getLast():获取第二个元素;
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("first");
linkedList.add("second");
linkedList.add("second");
linkedList.add("third");
linkedList.add("four");
linkedList.add("five");
System.out.println(linkedList);
linkedList.get(3);
System.out.println("get(index): " + linkedList.get(3));
linkedList.getFirst();
System.out.println("getFirst: " + linkedList.getFirst());
linkedList.getLast();
System.out.println("getLast: " + linkedList.getLast());
System.out.println(linkedList);
}
}
输出:
[first, second, second, third, four, five]
get(index): third
getFirst: first
getLast: five
[first, second, second, third, four, five]
注意到了,链表前后没有产生变化。
push、pop、poll
void push(E e):与addFirst一样,实际上它就是addFirst;
E pop():与removeFirst一样,实际上它就是removeFirst;
E poll():查询并移除第一个元素;
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " + linkedList);
System.out.println("pop: " + linkedList.pop());
System.out.println("after pop: " + linkedList);
System.out.println("poll: " + linkedList.poll());
System.out.println("after poll: " + linkedList);
}
}
输出:
linkedList: [five, four, third, second, second, first]
pop: five
after pop: [four, third, second, second, first]
poll: four
after poll: [third, second, second, first]
如果链表为空的时候,看看poll与pop是啥区别:
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
System.out.println("poll: " + linkedList.poll());
System.out.println("pop: " + linkedList.pop());
}
}
输出:
poll: null
Exception in thread "main" java.util.NoSuchElementException
at java.util.LinkedList.removeFirst(LinkedList.java:270)
at java.util.LinkedList.pop(LinkedList.java:801)
at org.ks.algorithm.LinkedListMethodsDemo.main(LinkedListMethodsDemo.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
可以看出poll返回null,而pop则产生异常。
peek
E peek():获取第一个元素,但是不移除;
E peekFirst():获取第一个元素,但是不移除;
E peekLast():获取最后一个元素,但是不移除;
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " + linkedList);
System.out.println("peek: " + linkedList.peek());
System.out.println("peekFirst: " + linkedList.peekFirst());
System.out.println("peekLast: " + linkedList.peekLast());
System.out.println("linkedList: " + linkedList);
}
}
输出:
linkedList: [five, four, third, second, second, first]
peek: five
peekFirst: five
peekLast: first
linkedList: [five, four, third, second, second, first]
如果没找到对应的元素,统统输出null
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
System.out.println("linkedList: " + linkedList);
System.out.println("peek: " + linkedList.peek());
System.out.println("peekFirst: " + linkedList.peekFirst());
System.out.println("peekLast: " + linkedList.peekLast());
}
}
输出
linkedList: []
peek: null
peekFirst: null
peekLast: null
offer
boolean offer(E e):在链表尾部插入一个元素;
boolean offerFirst(E e):与addFirst一样,实际上它就是addFirst;
boolean offerLast(E e):与addLast一样,实际上它就是addLast;
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " + linkedList);
linkedList.offer("six");
System.out.println("linkedList: " + linkedList);
linkedList.offerFirst("zero");
System.out.println("linkedList: " + linkedList);
linkedList.offerLast("seven");
System.out.println("linkedList: " + linkedList);
}
}
输出:
linkedList: [five, four, third, second, second, first]
linkedList: [five, four, third, second, second, first, six]
linkedList: [zero, five, four, third, second, second, first, six]
linkedList: [zero, five, four, third, second, second, first, six, seven]
LinkedList中常用的方法基本都列出来了,当然还有一些其他的例子,这里就一起演示了:
public class LinkedListMethodsDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.push("first");
linkedList.push("second");
linkedList.push("second");
linkedList.push("third");
linkedList.push("four");
linkedList.push("five");
System.out.println("linkedList: " + linkedList);
System.out.println("linkedList.contains(\"second\"): " + linkedList.contains("second"));
System.out.println("linkedList.contains(\"six\"): " + linkedList.contains("six"));
System.out.println("linkedList.element(): " + linkedList.element());
System.out.println("linkedList: " + linkedList);
System.out.println("linkedList.set(3, \"set\"): " + linkedList.set(3, "set"));
System.out.println("linkedList: " + linkedList);
System.out.println("linkedList.subList(2,4): " + linkedList.subList(2,4));
System.out.println("linkedList: " + linkedList);
}
}
输出:
linkedList: [five, four, third, second, second, first]
linkedList.contains("second"): true
linkedList.contains("six"): false
linkedList.element(): five
linkedList: [five, four, third, second, second, first]
linkedList.set(3, "set"): second
linkedList: [five, four, third, set, second, first]
linkedList.subList(2,4): [third, set]
linkedList: [five, four, third, set, second, first]
从输出可以看出,除了set改变原linkedlist,其他几个方法都不改变原链表。
3.Map接口
Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。
- TreeMap是有序的,HashMap和HashTable是无序的。
- Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
这就意味着:
- Hashtable是线程安全的,HashMap不是线程安全的。
- HashMap效率较高,Hashtable效率较低。
如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。- Hashtable不允许null值,HashMap允许null值(key和value都允许)
- 父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap
3.1.Map遍历的四种方式
方法一:在for循环中使用entries实现Map的遍历:
/**
* 最常见也是大多数情况下用的最多的,一般在键值对都需要使用
*/
Map <String,String>map = new HashMap<String,String>();
map.put("熊大", "棕色");
map.put("熊二", "黄色");
for(Map.Entry<String, String> entry : map.entrySet()){
String mapKey = entry.getKey();
String mapValue = entry.getValue();
System.out.println(mapKey+":"+mapValue);
}
方法二:在for循环中遍历key或者values,一般适用于只需要map中的key或者value时使用,在性能上比使用entrySet较好;
Map <String,String>map = new HashMap<String,String>();
map.put("熊大", "棕色");
map.put("熊二", "黄色");
//key
for(String key : map.keySet()){
System.out.println(key);
}
//value
for(String value : map.values()){
System.out.println(value);
}
方法三:通过Iterator遍历;
Iterator<Entry<String, String>> entries = map.entrySet().iterator();
while(entries.hasNext()){
Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+":"+value);
}
方法四:通过键找值遍历,这种方式的效率比较低,因为本身从键取值是耗时的操作;
for(String key : map.keySet()){
String value = map.get(key);
System.out.println(key+":"+value);
}
3.2.Map集合实现斗地主发牌洗牌的动作
HashMap< Key,Value>集合:键唯一,值可以重复!
Map集合的添加方法:map.put(key,value);
Map集合的获取方法:map.get(key);通过键找到值.
Collections.sort(list) ; 默认进行升序排序.
/*
斗地主综合案例_有序版本
实现步骤:
1.准备牌(Map<key,Value>集合)
2.洗牌(shuffer方法)
3.发牌()
4.排序(sort()方法)
5.看牌(遍历 - 键值对)
前4步都是通过牌的索引来操作 .
看牌 -- 将索引对应的扑克牌拿出来 .
*/
public class DouDiZhu01 {
public static void main(String[] args) {
getPoker();
}
public static void getPoker(){
// 1.准备牌 , 创建一个Map集合 , key为牌的索引 , value为拼装好的牌 .
HashMap<Integer , String> poker = new HashMap<>();
// 创建一个集合 , 用来装牌的索引 .
ArrayList<Integer> pokerIndex = new ArrayList<>();
// 先装大王 , 小王 .
int index = 0;
pokerIndex.add(index);
poker.put(index ++, "大王"); // 0 - 大王 , 完了index+1;
pokerIndex.add(index);
poker.put(index ++, "小王"); // 1 - 小王 , 完了index+1;
// 创建两个数组 , 一个存放花色 , 一个存放点数 .
String[] colors = {"?","?","?","?"};
String[] numbers = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
// 将其余的52张牌拼接好 , 放到集合中.
for (String number : numbers) { // 使用增强for循环 .
for (String color : colors) { //嵌套for,拼装牌
pokerIndex.add(index);
poker.put(index++ , color+number); // 放入索引 , 跟组装好的牌 。index = 2 ...
}
}
// 2. 洗牌 -- 打乱顺序 .
Collections.shuffle(pokerIndex);
// System.out.println(pokerIndex);
// 3. 发牌 -- 创建四个集合分别装三个玩家和底牌 .
ArrayList<Integer> person01 = new ArrayList<>();
ArrayList<Integer> person02 = new ArrayList<>();
ArrayList<Integer> person03 = new ArrayList<>();
ArrayList<Integer> dipai = new ArrayList<>();
// 按照顺序依次发牌 , 最后留三张作为底牌 .
for (int i = 0; i < pokerIndex.size(); i++) {
Integer it = pokerIndex.get(i); // 获取牌的索引值.
if(i >= 51){ // 最后三张 , 放入底牌 .
dipai.add(it);
}else if(i%3 == 0){ // 第一张给了玩家1 .
person01.add(it);
}else if(i%3 == 1){ // 第二张给了玩家2 .
person02.add(it);
}else if(i%3 == 2){ // 第三张给了玩家3 .
person03.add(it);
}
}
// 4. 排序 -- 升序排序 , 就是将大牌在前,小牌在后.
Collections.sort(person01);
Collections.sort(person02);
Collections.sort(person03);
Collections.sort(dipai);
// 5. 看牌 -- 通过索引拿到对应的牌 .
lookPai("周润发",person01,poker);
lookPai("刘德华",person02,poker);
lookPai("周润发",person03,poker);
lookPai("底牌",dipai,poker);
}
// 看牌
public static void lookPai(String name , ArrayList<Integer> index , HashMap<Integer , String> map ){
// s输出姓名不换行 .
System.out.print(name+":");
// 遍历牌的索引 , 拿到索引 .
for (Integer integer : index) {
String paiName = map.get(integer);
System.out.print(paiName+" ");
}
// 输出完一个玩家 , 换行 .
System.out.println();
}
}
运行结果如下:
牌是按照存放顺序的大小展示的,开始都是通过牌的键(索引)来操作,最后通过键获取对应的值(牌).
4.Set
Set 无序,唯一
HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals()LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一TreeSet
底层数据结构是红黑树。(唯一,有序)
1. 如何保证元素排序的呢?
自然排序
比较器排序
2.如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
Set集合的特点:
不能存储相同的元素。
同时因为其是一个抽象的接口:所以不能直接实例化一个set对象。(Set s = new Set() )错误
该接口主要继承于Collections接口,所以具有Collection的一些常见的方法。
Set接口最长用的两大实现:HashSet TreeSet
TreeSet:会将里面的元素默认排序
package oneone;
import java.util.Scanner;
import java.util.TreeSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
Set<Integer> test = new TreeSet<>();
int n = scan.nextInt();
for(int i=0;i<n;i++)
{
int a=scan.nextInt();
test.add(a);
}
System.out.println(test.size());
/* //遍历集合test 利用foreach遍历 //输出结果:1 3 8
for (Integer value : test) {
System.out.print(value+" ");
}
//利用Iterator实现遍历
Iterator<Integer> value = test.iterator();
while (value.hasNext()) {
int s = value.next();
System.out.print(s+" ");
} //输出结果:1 3 8*/
}
}
案例:set集合添加元素并使用迭代器迭代元素。
public class Demo4 {
public static void main(String[] args) {
//Set 集合存和取的顺序不一致。
Set hs = new HashSet();
hs.add("世界军事");
hs.add("兵器知识");
hs.add("舰船知识");
hs.add("汉和防务");
System.out.println(hs);
// [舰船知识, 世界军事, 兵器知识, 汉和防务]
Iterator it = hs.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
4.1.HashSet
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 可以有重复元素的集合
---| ArrayList
---| LinkedList
---| Set接口 不可以有重复元素的集合
---| HashSet 线程不安全,存取速度快。底层是以哈希表实现的。
HashSet
哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
HashSet不存入重复元素的规则.使用hashcode和equals
由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。
当你试图把对象加入HashSet时,HashSet会使用对象的hashCode来判断对象加入的位置。同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的hashCode,HashSet就会假设对象没有重复出现。
简单一句话,如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。
因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。
如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入.
总结:
元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。
哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
4.2.hashtable
图1:hashCode值不相同的情况
图2:hashCode值相同,但equals不相同的情况。
HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。
当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。
HashSet到底是如何判断两个元素重复。
通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型
判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。
注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。
HashSet 和ArrayList集合都有判断元素是否相同的方法,
boolean contains(Object o)
HashSet使用hashCode和equals方法,ArrayList使用了equals方法
案例:
使用HashSet存储字符串,并尝试添加重复字符串
回顾String类的equals()、hashCode()两个方法
public class Demo4 {
public static void main(String[] args) {
// Set 集合存和取的顺序不一致。
Set hs = new HashSet();
hs.add("世界军事");
hs.add("兵器知识");
hs.add("舰船知识");
hs.add("汉和防务");
// 返回此 set 中的元素的数量
System.out.println(hs.size()); // 4
// 如果此 set 尚未包含指定元素,则返回 true
boolean add = hs.add("世界军事"); // false
System.out.println(add);
// 返回此 set 中的元素的数量
System.out.println(hs.size());// 4
Iterator it = hs.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定
public class Demo4 {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("jack", 20));
hs.add(new Person("rose", 20));
hs.add(new Person("hmm", 20));
hs.add(new Person("lilei", 20));
hs.add(new Person("jack", 20));
Iterator it = hs.iterator();
while (it.hasNext()) {
Object next = it.next();
System.out.println(next);
}
}
}
class Person {
private String name;
private int age;
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 int hashCode() {
System.out.println("hashCode:" + this.name);
return this.name.hashCode() + age * 37;
}
@Override
public boolean equals(Object obj) {
System.out.println(this + "---equals---" + obj);
if (obj instanceof Person) {
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age;
} else {
return false;
}
}
@Override
public String toString() {
return "Person@name:" + this.name + " age:" + this.age;
}
}
问题:现在有一批数据,要求不能重复存储元素,而且要排序。ArrayList 、 LinkedList不能去除重复数据。HashSet可以去除重复,但是是无序。
所以这时候就要使用TreeSet了
4.3.TreeSet
案例:使用TreeSet集合存储字符串元素,并遍历
public class Demo5 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("ccc");
ts.add("aaa");
ts.add("ddd");
ts.add("bbb");
System.out.println(ts); // [aaa, bbb, ccc, ddd]
}
}
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 有序,可以重复,有角标的集合
---| ArrayList
---| LinkedList
---| Set接口 无序,不可以重复的集合
---| HashSet 线程不安全,存取速度快。底层是以hash表实现的。
---| TreeSet 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。
4.4.红-黑树
红黑树是一种特定类型的二叉树
红黑树算法的规则: 左小右大。
既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。
1:让存入的元素自定义比较规则。
2:给TreeSet指定排序规则。
方式一:元素自身具备比较性
元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
通过return 0来判断唯一性。
问题:为什么使用TreeSet存入字符串,字符串默认输出是按升序排列的?因为字符串实现了一个接口,叫做Comparable 接口.字符串重写了该接口的compareTo 方法,所以String对象具备了比较性.那么同样道理,我的自定义元素(例如Person类,Book类)想要存入TreeSet集合,就需要实现该接口,也就是要让自定义对象具备比较性.
存入TreeSet集合中的元素要具备比较性.
比较性要实现Comparable接口,重写该接口的compareTo方法
TreeSet属于Set集合,该集合的元素是不能重复的,TreeSet如何保证元素的唯一性
通过compareTo或者compare方法中的来保证元素的唯一性。
添加的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,说明两个对象相等,此时该对象不会添加进来。
比较器接口
----| Comparable
compareTo(Object o) 元素自身具备比较性
----| Comparator
compare( Object o1, Object o2 ) 给容器传入比较器
4.5.TreeSet集合排序的两种方式
一,让元素自身具备比较性。
也就是元素需要实现Comparable接口,覆盖compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。
年龄按照搜要条件,年龄相同再比姓名。
public class Demo4 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Person("aa", 20, "男"));
ts.add(new Person("bb", 18, "女"));
ts.add(new Person("cc", 17, "男"));
ts.add(new Person("dd", 17, "女"));
ts.add(new Person("dd", 15, "女"));
ts.add(new Person("dd", 15, "女"));
System.out.println(ts);
System.out.println(ts.size()); // 5
}
}
class Person implements Comparable {
private String name;
private int age;
private String gender;
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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 String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public int hashCode() {
return name.hashCode() + age * 37;
}
public boolean equals(Object obj) {
System.err.println(this + "equals :" + obj);
if (!(obj instanceof Person)) {
return false;
}
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + ", gender=" + gender
+ "]";
}
@Override
public int compareTo(Object obj) {
Person p = (Person) obj;
System.out.println(this+" compareTo:"+p);
if (this.age > p.age) {
return 1;
}
if (this.age < p.age) {
return -1;
}
return this.name.compareTo(p.name);
}
}
二,让容器自身具备比较性,自定义比较器。
需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。
那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,覆盖compare方法。
并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。
当Comparable比较方式,及Comparator比较方式同时存在,以Comparator
比较方式为主。
public class Demo5 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyComparator());
ts.add(new Book("think in java", 100));
ts.add(new Book("java 核心技术", 75));
ts.add(new Book("现代操作系统", 50));
ts.add(new Book("java就业教程", 35));
ts.add(new Book("think in java", 100));
ts.add(new Book("ccc in java", 100));
System.out.println(ts);
}
}
class MyComparator implements Comparator {
public int compare(Object o1, Object o2) {
Book b1 = (Book) o1;
Book b2 = (Book) o2;
System.out.println(b1+" comparator "+b2);
if (b1.getPrice() > b2.getPrice()) {
return 1;
}
if (b1.getPrice() < b2.getPrice()) {
return -1;
}
return b1.getName().compareTo(b2.getName());
}
}
class Book {
private String name;
private double price;
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Book(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + "]";
}
}
4.6.LinkedHashSet
会保存插入的顺序。
看到array,就要想到角标。
看到link,就要想到first,last。
看到hash,就要想到hashCode,equals.
看到tree,就要想到两个接口。Comparable,Comparator。
内容总结
以上是互联网集市为您收集整理的Java集合中List,Set以及Map等集合全部内容,希望文章能够帮你解决Java集合中List,Set以及Map等集合所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。