ArrayList:数组存储方式,可以利用索引访问元素。它的优点在于遍历元素和随机访问元素的效率比较高。而且ArrayList存储元素有序,且元素可以重复。
package com.itheima01;
import java.util.ArrayList;
/*
* 持有数据:
* 单一数据,可以定义对应类型的变量直接持有
* 多个数据,可以使用数组的方式记录,通过索引访问数据
* 又在面向对象的基础上,可以使用集合的方式记录,最开始最常用ArrayList,该集合类同样可以通过索引访问数据
*
* 集合的基本使用:
* 1创建集合对象
* 2向集合中添加元素
* 3从集合中获取元素/其他信息(集合的长度)
*/
public class Demo01ArrayList {
public staticvoid main(String[] args) {
//创建集合对象
ArrayList<Integer>list = newArrayList<Integer>();
//向集合中添加元素
list.add(10);
list.add(100);
list.add(2000);
//从集合中获取元素/其他信息(集合的长度)
Integerinteger = list.get(2);
System.out.println(integer);
int size = list.size();
System.out.println(size);
System.out.println("===============================");
//遍历集合
for (inti = 0; i < list.size(); i++) {
//通过索引依次获取集合中每一个元素
IntegerthisNumber = list.get(i);
//打印每个元素
System.out.println(thisNumber);
}
}
}
迭代器概述:
java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。
我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。
Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
集合中把这种取元素的方式描述在Iterator接口中。Iterator接口的常用方法如下:
hasNext()方法:用来判断集合中是否有下一个元素可以迭代。如果返回true,说明可以迭代。
next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。
package com.itheima01;
import java.util.ArrayList;
import java.util.Iterator;
/*
* 在java当中不止ArrayList一个集合,java提供了众多的集合.
*
* 不同的容器完成不同方式的数据存储.
* 不同集合的特点不同,ArrayList有序且可重复且带索引的集合.但是有的集合不带索引.所以如果使用其他集合,可能无法通过get+索引的方式获取元素
*
* 所有集合的通用获取元素方法并不是通过索引获取,而是通过迭代器获取.
* 迭代器:iterator
*/
public class Demo02iterator {
public staticvoid main(String[] args) {
//创建集合对象
ArrayList<Integer>list = newArrayList<Integer>();
//向集合中添加元素
list.add(10);
list.add(100);
list.add(2000);
//获取该集合的迭代器
Iterator<Integer>iterator = list.iterator();
//使用迭代器的方法,迭代集合(遍历集合)
while(iterator.hasNext()) {
//获取集合中元素
IntegerthisNumber = iterator.next();
System.out.println(thisNumber);
}
}
}
迭代器原理:
package com.itheima01;
import java.util.ArrayList;
import java.util.Iterator;
/*
* 集合用来持有数据,所有常用集合都具备了可迭代功能iterator方法,该方法用于迭代集合,该方法才是最为通用的集合迭代方法。
*
* 迭代器:集合迭代(集合遍历)的工具
*
* 集合的获取迭代器方法
* public Iterator<E> iterator() 获取某个集合的迭代器实例对象
*
* Iterator:迭代器接口
* booleanhasNext() 判断集合中是否有下一个元素 不移动元素指针
* Enext() 获取集合中下一个元素 移动指针,指向下一个元素
*/
public class Demo03iterator {
public staticvoid main(String[] args) {
//创建集合对象
ArrayList<Integer>list = newArrayList<Integer>();
//向集合中添加元素
list.add(10);
list.add(100);
list.add(2000);
//调用集合的iterator方法,返回迭代器对象
Iterator<Integer>itr = list.iterator();
//混合使用hasNext与next方法,循环获取元素
while(itr.hasNext()) {
//如果有元素,就获取元素
IntegerthisNumber = itr.next();
System.out.println(thisNumber);
}
}
}
泛型:
A:泛型用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数传递。
B:泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型
ArrayList<String> al=newArrayList<String>();//ArrayList<String>看作数据类型
C:泛型的定义:定义泛型可以在类中预支地使用未知的类型。
//在ArrayList类的add()方法的源码中定义的E e,使用了e
public boolean add(Ee) {
ensureCapacityInternal(size + 1);
elementData[size++] =e;
return true;
}
D:泛型的使用:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
ArrayList al=new ArrayList();
al.add(“abc”);
al.add(1);//由于在定义集合时没有指定泛型,add()方法的形参为Object类型,所以可以往集合中添加任意任意类型的数据(多态特点)
泛型格式:
class 类名<E,T,……>{//<>中的泛型可以写无数个
//E,T……能够做为类型在该类内部被使用
}
package com.itheima03.type2;
/*
* 在该类中定义一个成员变量,使用泛型
*
* 不指定其数据类型,是一个不确定的数据类型.
* 创建不同的对象时,指定不同的数据类型
*
*/
public classMyClass4Type<T> {
private T myField;
public T getMyField() {
return myField;
}
public voidsetMyField(T myField) {
this.myField= myField;
}
}
package com.itheima03.type2;
/*
* 泛型类:
* 在类中使用泛型
*
* 定义:类名后<变量> 如:class A<E>{使用E完全类的定义}
* 使用:创建对象时确定类型
*
* 一般定义泛型使用E,T,V,K
*
* 泛型方法:
* 定义:方法返回值前<变量>如:public <T> void method(){使用T}
* 使用:调用方法时确定类型
*/
public class Demo01type_class {
public staticvoid main(String[] args) {
//测试使用自己定义的泛型类
MyClass4Type<String>mc4t = newMyClass4Type<String>();
//调用了使用类泛型的方法
mc4t.setMyField("Jack");
StringmyField = mc4t.getMyField();
System.out.println(myField);
//创建对象时指定泛型为Integer则所有使用了泛型的方法根据对象类型一起改变
MyClass4Type<Integer>mc4t2 = newMyClass4Type<Integer>();
mc4t2.setMyField(12);
System.out.println(mc4t2.getMyField();
}
}
泛型接口:
interface 接口名<Q,E,R……>{
public abstract voidmethod(T t);//假设定义一个方法
}
class 类名 implements 接口<实际类型>{
@Override
public void method(String t) {
System.out.println(t);
}
}
package com.itheima04.type3;
/*
* 接口上定义泛型
*/
public interfaceMyInter4Type<T> {
//接口的方法中使用接口泛型
public abstractvoid method(T t);
}
package com.itheima04.type3;
/*
* 定义类时,就指定接口中的数据类型,定义一个不含泛型的正常类
*/
public class MyClass4Inter implements MyInter4Type<String> {
//使用指定的接口中的数据类型,重写方法
@Override
public voidmethod(String t) {
System.out.println(t);
}
}
泛型通配符:?
定义:(查看ArrayList的构造方法)无法在类中使用
使用:调用方法时可以给予任意类型。参照Arraylist的构造方法
? extends E代表只要是E类型的子类即可
? super E代表只要是E类型的父类即可
并发修改异常:
在前一个迭代器迭代自定义数据类型的基础上,添加新的需求:
使用集合存储多个Person对象,当遇到16岁的人时,就添加一个90岁的人
package com.itheima01;
/*
* 人类:
* 年龄 姓名
*/
public class Person {
private String name;
private intage;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name =name;
this.age =age;
}
public String getName() {
return name;
}
public voidsetName(String name) {
this.name =name;
}
public intgetAge() {
return age;
}
public voidsetAge(int age) {
this.age =age;
}
}
在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。
解决并发修改异常,重新获取迭代器
package com.itheima01;
import java.util.ArrayList;
import java.util.Iterator;
/*
* 使用集合存储多个Person对象,当遇到16岁的人时,就添加一个90岁的人
*
* 该例中可能会产生并发修改异常:迭代器所认为的集合状态与集合真正的状态不统一了!就会出现该异常.
*/
public classDemo05ConcurrentModificationException {
public staticvoid main(String[] args) {
//创建集合对象
ArrayList<Person>list = new ArrayList<Person>();
//向集合中添加元素
Personp = new Person("Jack",18);
Personp2 = new Person("Rose",16);
Personp3 = new Person("Trump",62);
Personp4 = new Person("Obama",56);
Personp5 = new Person("Castro",90);
list.add(p);
list.add(p2);
list.add(p3);
list.add(p4);
//调用集合的iterator方法,返回迭代器对象
Iterator<Person>itr = list.iterator();
//混合使用hasNext与next方法,循环获取元素
while(itr.hasNext()) {
//如果有元素,就获取元素
PersonthisP = itr.next();
//判断年龄是否为16岁
if(thisP.getAge() == 16) {
//如果存在16岁的人,就加入90岁的卡斯特罗
list.add(p5);
//当集合加入了一个元素后,就不要再使用迭代器操作元素了
break;
}
}
//重新打印集合结果
Iterator<Person>itr2 = list.iterator();
while (itr2.hasNext()) {
Personperson = (Person) itr2.next();
System.out.println(person.getAge()+"岁的"+person.getName());
}
}
增强for循环遍历集合
package com.itheima01;
import java.util.ArrayList;
/*
* foreach循环(又叫增强for循环)来完成容器中元素的获取
*
* 增强for循环用来迭代集合或数组,格式如下:
* for(容器内类型临时变量:容器){
* 内部可以直接使用临时变量访问数据
* }
*
* 增强for循环源代码底层就是迭代器.所以不能在增强for循环的过程当中为集合添加或者删除元素.因为会产生并发修改异常.
* 所以,增强for循环只用来查看数据,不作数据修改.
*/
public class Demo06foreach {
public staticvoid main(String[] args) {
//创建集合对象
ArrayList<Integer>list = newArrayList<Integer>();
//向集合中添加元素
list.add(10);
list.add(100);
list.add(2000);
//使用增强for循环迭代集合
for(Integer thisNumber : list) {
System.out.println(thisNumber);
}
System.out.println("=======================");
//增强for循环便利数组
String[]arr = {"Jack","Rose","Trump","Obama"};
for (String thisName : arr) {
System.out.println(thisName);
}
}
}
LinkedList:与ArrayList不同,LinkedList是方便添加删除的List。实际开发中对一个元素的添加与删除经常涉及到首尾操作。
LinkedList采用链表存储方式,优点在于插入、删除元素时效率比较高。
每种集合的特点不同(如更适合增删还是更适合查找),是因为底层的数据结构不同。
数据结构指的数据存储和组织方式, 这里介绍最常用的数据结构:
栈结构:容器先进后出规则
* stack栈结构:先进后出
*
* LinkedList是支持栈结构的.
* 对应的方法
* push压栈
* pop弹栈
* peek查询出即将要弹出的是哪个元素,检查有没有要弹出的元素
*
* java提供了一个专门用于栈结构的类,Stack
*/
publicclass Demo02stack {
publicstaticvoid main(String[] args) {
//创建栈结构的集合
LinkedList<String> stack = newLinkedList<String>();
stack.push("Jack");
stack.push("Rose");
stack.push("Trump");
System.out.println(stack);
//获取一个元素,此时,由于是栈结构,所以获取的是最后压栈的元素
String popName = stack.pop();
System.out.println(popName);
//弹栈动作,集合中减少元素
System.out.println(stack);
String peekName = stack.peek();
System.out.println(peekName);
//peek查看元素不会减少元素
System.out.println(stack);
}
}
数组结构:一块连续的存储区域
链表结构:每个元素指向下一个元素
队列结构:
容器先进先出的规则
* queue队列结构:
*
* LinkedList是支持队列结构的
* 对应的方法
* offer加入队列
* poll离开队列
* peek查询出即将要离开队列的是哪个元素,检查有没有要离开队列的元素
*/
publicclass Demo03queue {
publicstaticvoid main(String[] args) {
//创建栈结构的集合
LinkedList<String> queue = newLinkedList<String>();
queue.offer("Jack");
queue.offer("Rose");
queue.offer("Trump");
System.out.println(queue);
String pollName = queue.poll();
System.out.println(pollName);
System.out.println(queue);
String peekName = queue.peek();
System.out.println(peekName);
System.out.println(queue);
}
}
ArrayList数组实现的原理
数组实现的特点: 查询快,增删慢
原因:
查询快: 由于数组的索引支持,那么可以通过索引直接计算出元素的地址值,因此就可以直接通过
元素的地址值获取到指定的元素
增删慢: 由于在添加元素的时候,实际上底层会先创建一个新数组(新数组的长度为原数组的长度+1),
那么在添加新元素的时候,先需要对数组中原有的数据进行拷贝,其次在末尾进行添加新的元素
因此,这样操作的效率的极低的(删除元素 刚好和添加的操作相反)
LinkedList链表实现的原理
链表结构: 查询慢,增删快
查询慢:由于不能直接找到元素的地址,需要上一个元素推导出下一个元素的地址,
这种查询速度较慢
增删快:在添加的时候,只需要更改元素所记录的地址值即可
HashSet的特性和基本使用
HashSet是Set接口的子类,不包含重复元素相同元素,且无序。
HashSet下还有子类LinkedHashSet,可预测迭代顺序的Set集合。
/*
* HashSet,不包含重复元素相同元素,且无序.不提供索引,所以不能通过索引获取元素,只能通过迭代器访问数据.
*/
publicclass Demo01HashSet {
publicstaticvoid main(String[] args) {
//创建集合对象
HashSet<String> set = newHashSet<String>();
//向集合中添加元素
set.add("Jack");
set.add("Rose");
set.add("Trump");
set.add("Obama");
set.add("Obama");
System.out.println(set);
//获取元素,只能用迭代器
Iterator<String> itr = set.iterator();
while(itr.hasNext()) {
String thisName = itr.next();
System.out.println(thisName);
}
System.out.println("================");
for (String thisName : set) {
System.out.println(thisName);
}
}
}
package com.itheima08.hashset;
import java.util.HashSet;
/*
* 求一个字符串"aiodjl;hriWFUADJSVUEHiowfjnivowe"中一共有几个不重复的字母,区分大小写,如a,A算两个字符
*
* 将字符串拆分成一个个单个字符
* 判断字符是否为字母
* 如果是字母,放到一个HashSet集合中
* 查看集合长度
*/
public class Test {
public static void main(String[] args) {
String s = "aiodjl;hriWFUADJSVUEHiowfjnivowe";
//定义不包含重复元素的HashSet集合
HashSet<Character> set = new HashSet<Character>();
//将字符串拆分成一个个单个字符
char[] charArray =s.toCharArray();
//使用增强for循环遍历数组
for (char c : charArray) {
//判断字符是否为字母
if(('a'<=c&&c<='z')||('A'<=c&&c<='Z')) {
//如果是字母,放到一个HashSet集合中
set.add(c);
}
}
//查看集合长度
System.out.println("在该字符串中,一共存在不重复的字母"+set.size()+"个");
}
}
ArrayList中Contains方法如何判断是否有重复元素
自定义类型Person类是Object类的子类,所以Person具备equals方法contains方法会调用参数的equals方法,
依次与集合当中已经存在的Person对象比较.当Person类没有重写equals方法时,直接使用Object类基础过来的equals方法,
而该方法比较的是对象地址值当Person类重写equals方法后,就可以讲比较规则由比较地址值改为比较属性值
public classDemo02ArrayList_contains {
public staticvoid main(String[] args) {
// ArrayList<String> list = new ArrayList<String>();
//
// list.add("Jack");
// list.add("Rose");
// list.add("Trump");
//
// //判断集合中是否存在Jack
// System.out.println(list.contains("Jack"));
//ArrayList当中存储自定义数据类型Person
ArrayList<Person>list2 = newArrayList<Person>();
Personp = new Person("Jack",18);
Personp2 = new Person("Rose",16);
Personp3 = new Person("Trump",62);
list2.add(p);
list2.add(p2);
list2.add(p3);
System.out.println(list2.contains(new Person("Jack",18)));
// System.out.println(list2.contains(p));
}
自定义类需要满足咱们认为的效果,也就是不同的对象但是属性值相同就认为是同一个对象
在集合里只存其一的效果,就必须重写equals方法,且更改该方法里的比较规则
/*
* 如果没有重写该equals方法,则比较地址值.
* 我们希望比较两个对象时,比较属性内容,所以重写该方法.
*/
@Override
publicboolean equals(Object obj) {
System.out.println("equals方法被调用了");
//this:contains方法的参数对象 obj:集合当中老元素
//将Object类型的obj强转为子类类型
Person otherP = (Person)obj;
//比较姓名
if(!this.name.equals(otherP.name)) {
returnfalse;
}
//比较年龄
if(this.age != otherP.age){
returnfalse;
}
//如果所有属性值均相同,就返回true
returntrue;
}
HashSet判断元素唯一性规则
Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。
HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:
先判断新元素与集合内已经有的旧元素的HashCode值
如果不同,判断元素不同。
如果相同,再判断equals比较结果,返回true则相同,返回false则仍然不同。
所以,使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,则判断重复时,使用的地址值,如果想通过内容比较元素是否相同,需要重写该类的hashcode与equals方法。
hashCode方法重写规则:将该对象的各个属性值hashCode相加即是整个对象的HashCode值。如果是基本类型,类似int,则直接返回int值就是该属性的hash值,如果是引用类型,类似String,就调用该成员变量的hashCode方法返回该成员变量hash值。这样可以根据对象的内容返回hashCode值,从而可以根据hashCode判断元素是否唯一。
但是由于在一些”碰巧的”情况下,可能出现内容不同但hashCode相同的情况,为了避免这些情况,我们加入一些干扰系数。
可是加入干扰系数后,仍会出现一些”碰巧”的情况,所以我们还要进行equals的二次判断
//没有重写equals方法,equals方法继承父类方法,通过判断地址值比较对象
@Override
publicboolean equals(Object obj) {
System.out.println("equals方法被调用了");
//this:add方法的参数对象 obj:集合当中老元素
//将Object类型的obj强转为子类类型
Animal otherA = (Animal)obj;
//比较姓名
if(!this.name.equals(otherA.name)) {
returnfalse;
}
//比较年龄
if(this.age != otherA.age){
returnfalse;
}
//如果所有属性值均相同,就返回true
returntrue;
}
//没有重写hashCode方法时,hashCode方法继承父类方法,返回的是地址值
//重写hashCode方法,通过属性值返回一个整数数字
//即对象的hashCode值,就是各个属性的hashCode值之和
//引用数据类型属性,调用hashCode方法回去
//基本数值类型属性,直接就是数值本身
@Override
publicint hashCode() {
//张三 18 >> 56*系数 + 18 = 74
//李四 56 >> 18*系数 + 56 = 74
//理想上,不同属性值应该返回不同的hashCode值,可以在每次结果后乘以一个固定系数,避免该情况发生
//定义变量,记录要返回的hashCode值
int thisHashCode = 0;
//获取name属性的hashCode值
thisHashCode += name.hashCode()*17;
//获取age数只给你的hashCode值
thisHashCode += age;
return thisHashCode;
}
//eclipse可以使用快捷键自动生成对应的hashCode方法与equals方法
@Override
publicint hashCode() {
//定义系数
finalint prime = 31;
//定义返回的hashCode值
int result = 1;
//每次将结果*系数,再加下一个成员变量,可以大大降低不同成员变量返回相同hashCode值的情况
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
publicboolean equals(Object obj) {
//自身与自身比较直接返回true
if (this == obj)
returntrue;
//参数是null直接返回false
if (obj == null)
returnfalse;
//如果调用方法的类型与参数类型不一样,则直接返回false
if (getClass() != obj.getClass())
returnfalse;
//如果类型相同,就转成(强制类型转换)相同的类型继续比较属性值
Animal other = (Animal) obj;
//比较年龄
if (age != other.age)
returnfalse;
//比较姓名
if (name == null) {
if (other.name != null)
returnfalse;
} elseif (!name.equals(other.name))
returnfalse;
//如果一切不相同的情况都不符合,则说明两个对象的属性值相同,返回true
returntrue;
}
双列集合Map:
双列集合是每个元素都有键与值两部分组成的集合,记录的是键值对对应关系。即通过键可以找到值。
常用子类:
最常用的双列集合是Map下的子类HashMap。
Hashtable也是Map集合的一种已被HashMap取代。
Map集合的特点,如是否可重复,是否有序仅作用在键上,如HashMap集合的键不得重复,值可以重复。
1.1.1 案例代码一:
packagecom.itheima09.map;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Set;
/*
* Map:双列集合,每个元素分为键与值两部分,是一个键值得对应关系.我们经常使用键找值
*
* 最常用的Map集合是HashMap:键是唯一的且无序
*
* 用法:
*
*/
publicclass Demo01Test_Map {
publicstatic void main(String[] args) {
//创建集合对象
HashMap<String,String> map = new HashMap<String,String>();
//向集合中添加元素
map.put("姓名", "Jack");
map.put("性别", "男");
map.put("年龄", "18");
map.put("分数", "18");
//可以通过键获取值
String value =map.get("姓名");
System.out.println(value);
}
}
1.1 Map基本使用
A:Map(HashMap)的使用:创建对象时加入两个泛型。
Map<k,v>
key - 此映射所维护的键的类型
value - 映射值的类型
B:常用方法:
public V put(K key,V value) //加入元素,则新值会覆盖掉旧值
public V get(Object key) //根据键找值
1.1.1 案例代码二:
packagecom.itheima09.map;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Set;
/*
* Map:双列集合,每个元素分为键与值两部分,是一个键值得对应关系.我们经常使用键找值
*
* 最常用的Map集合是HashMap:键是唯一的且无序
*
* 用法:
* 创建对象时,要分别制定键的泛型与值的泛型
*
* Map(HashMap)的使用:创建对象时加入两个泛型。
* Map<k,v>
* key- 此映射所维护的键的类型
* value- 映射值的类型
*
* 常用方法:
* publicV put(K key,V value)//加入元素,则新值会覆盖掉旧值
* publicV get(Object key) //根据键找值
* publicSet<K> keySet() //返回所有键的集合
* publicCollection<V> values() //返回所有值的集合
*
*/
publicclass Demo01Test_Map {
public static voidmain(String[] args) {
//创建集合对象
HashMap<String, String> map = newHashMap<String, String>();
//向集合中添加元素
map.put("及时雨", "宋江");
map.put("玉麒麟", "卢俊义");
map.put("智多星", "高俅");
map.put("智多星", "吴用");
System.out.println(map);
//可以通过键获取值
String name = map.get("及时雨");
System.out.println(name);
String name2 = map.get("母夜叉");
System.out.println(name2);
}
}
1.1 Map集合遍历方式1
第1种遍历方式是,使用Map集合的keySet()方法
A:思路:
* 通过keySet()方法获取所有键的集合
* 遍历键的集合,获取到每一个键
* 根据键找值
1.1.1 案例代码三:
packagecom.itheima09.map;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Set;
/*
* Map:双列集合,每个元素分为键与值两部分,是一个键值得对应关系.我们经常使用键找值
*
* 最常用的Map集合是HashMap:键是唯一的且无序
*
* 用法:
* 创建对象时,要分别制定键的泛型与值的泛型
*
* Map(HashMap)的使用:创建对象时加入两个泛型。
* Map<k,v>
* key- 此映射所维护的键的类型
* value- 映射值的类型
*
* 常用方法:
* publicV put(K key,V value)//加入元素,则新值会覆盖掉旧值
* publicV get(Object key) //根据键找值
* publicSet<K> keySet() //返回所有键的集合
* publicCollection<V> values() //返回所有值的集合
* Map没有迭代器方法,最常用的遍历方法:先获取所有键的集合,迭代该集合,依次获取每一个键.通过键找值.
*/
publicclass Demo01Test_Map {
public static voidmain(String[] args) {
//创建集合对象
HashMap<String, String> map = newHashMap<String, String>();
//向集合中添加元素
map.put("及时雨", "宋江");
map.put("玉麒麟", "卢俊义");
map.put("智多星", "高俅");
map.put("智多星", "吴用");
//返回所有键的集合
Set<String> keySet = map.keySet();
System.out.println(keySet);
//返回所有值得集合
Collection<String> values = map.values();
System.out.println(values);
//map集合的常用遍历
Set<String> keySet2 = map.keySet();
System.out.println("==========================");
//迭代所有键的Set集合,依次获取每一个键
Iterator<String> iterator = keySet2.iterator();
while(iterator.hasNext()) {
String thisKey = iterator.next();
//通过键找值,记住这里使用map集合通过键找值
String thisValue = map.get(thisKey);
System.out.println(thisKey+"="+thisValue);
}
}
}
1.1 Map集合遍历方式2
第2种遍历方式是,使用Map集合的entrySet()方法
A:思路:
* 通过entrySet()方法获取所有键值对对象的集合
* 遍历键值对对象的集合,获取到每一个键值对对象
* 根据键值对对象找键和值
B: entrySet()方法解释
Set<Map.Entry<K,V>> entrySet() 方法用于返回某个集合所有的键值对对象。
Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中。可以从一个Entry对象中获取一个键值对的键与值。
C: Entry中的方法如下:
K getKey() 获取键
V getValue() 获取值
1.1.1 案例代码四:
packagecom.itheima09.map;
importjava.util.HashMap;
importjava.util.Map.Entry;
importjava.util.Set;
/*
* Map集合的第二种遍历方式:
*
* Set<Map.Entry<K,V>> entrySet() 方法用于返回某个集合所有的键值对对象。
* Entry将键值对对应关系封装成了对象。可以从一个Entry对象中中获取一个键值对的键与值。
*
* Map.Entry是一个嵌套类
*
* Entry中的方法如下:
* K getKey() 获取键
* V getValue() 获取值
*/
publicclass Demo02Entry {
public staticvoid main(String[] args) {
//创建集合对象
HashMap<String,String> map = new HashMap<String,String>();
//向集合中添加元素
map.put("及时雨", "宋江");
map.put("玉麒麟", "卢俊义");
map.put("智多星", "吴用");
//获取集合中所有的键值对对象的Set集合
Set<Entry<String,String>>entrySet = map.entrySet();
//迭代集合,依次获取每一个键值对对象
for(Entry<String,String>thisEntry: entrySet) {
//通过键值对对象获取键
String key = thisEntry.getKey();
//通过键值对对象获取值
String value =thisEntry.getValue();
System.out.println(key+":"+value);
}
}
}
1.1 LinkedHashMap
A:LinkedHashMap:
*Linked链表结构,保证元素有顺序
*Hash结构保证元素唯一
*以上约束对键起作用
B: LinkedHashMap的特点
* 底层是链表实现的可以保证怎么存就怎么取
1.1.1 案例代码五:
package com.itheima09.map;
import java.util.LinkedHashMap;
import java.util.Set;
/*
* LinkedHashMap:
* Linked链表结构,保证元素有顺序
* Hash结构保证元素唯一
* 以上约束对键起作用
*/
publicclass Demo03LinkedHashMap {
publicstaticvoid main(String[] args) {
//创建集合对象
LinkedHashMap<String,String> map = new LinkedHashMap<String, String>();
//向集合中添加元素
map.put("近平", "丽媛");
map.put("路人甲", "路人乙");
map.put("Jack", "Rose");
map.put("Jack", "Lily");
//观察集合元素
System.out.println(map);
//遍历集合
//获取所有键的集合
Set<String> keys = map.keySet();
//迭代所有键的集合
for(String thisKey: keys) {
//通过键找值
String thisValue = map.get(thisKey);
//打印信息
System.out.println(thisKey+":"+thisValue);
}
}
}
1.1 可变参数
Collections中有一个方法可以一次加入多个元素
publicstatic <T> boolean addAll(Collection<? super T> c,T... elements)
该方法使用到了可变参数,即定义时并不知道要传入多少个实际参数。此时定义成...的方式,此时可以在调用该方法时,一次传入多个参数。传入的多个数将被自动组织成数组,我们只要操作生成的数组即可。
注:可变参数只能放在最后定义。可变参数方法本质是数组,所以不可以与数组类型参数重载。
1.1.1 案例代码六:
package com.itheima10CollectionOthers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/*
* 可变参数:
* 参数可变
* Collections:
* public static <T> booleanaddAll(Collection c<? super T>, T... elements) 将指定的元素添加到集合
*
* 数据类型... 代表可变参数. 即可以传入任何多个该类型的数据
* 可变参数不能放在前边,只能放在最后
* 可变参数的方法与数组的方法不能重载,因为可变参数实质上就是数组
*/
public class Demo01args {
public staticvoid main(String[] args) {
Collection<String>c = newArrayList<String>();
//向c集合中添加N个元素
Collections.addAll(c, "Jack","Rose","Trump");
System.out.println(c);
System.out.println("=====================================");
int sum = add(10,20,30,40);
System.out.println(sum);
}
//用...定义可变参数,a表示了所有传进来的参数,a就是一个数组名称,存储了所有的参数
//求任意个数的和
public staticint add(int...a) {
//用来记录所有数的和
int sum =0;
//遍历可变参数a代表的数组
for(inti=0; i<a.length; i++) {
int j = a[i];
System.out.println(j);
//每次遇到一个数,就将该数累加到和中
sum += j;
}
//返回和
return sum;
}
/*可变参数方法不能与数组方法重载
public static void add(int[] x) {
}
*/
}
1.1 Collections的shuffle方法
shuffle方法的作用:
打乱集合中元素顺序
1.1.1 案例代码七:
package com.itheima10CollectionOthers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
* Collections:集合工具类,包含了众多集合的方法
*
* public static <T> voidsort(List<T> list) //排序
* public static <T> intbinarySearch(List<?> list,T key) //查找元素索引
* 二分法查找:在一个集合当中,查找一个指定元素的索引是多少,如果不存在该元素,就返回负数索引
* 二分法查询必须要求集合中的元素排好顺序
*
* public static void shuffle(List<?>list) //打乱元素顺序
*
* 有顺序(有序):第一个元素是多少,第二个元素是多少,第几个元素对应的是第几,顺序不变.
* 排序:不管是第几个放的,只要到集合中(以Integer集合为例),就按照一定的顺序重新排列了.
*/
public class Demo02Collections {
public staticvoid main(String[] args) {
//准备集合及元素
List<Integer>list = newArrayList<Integer>();
list.add(2);
list.add(7);
list.add(6);
list.add(10);
list.add(9);
System.out.println(list.get(0));
//打乱集合顺序
Collections.shuffle(list);
//打印集合
System.out.println(list);
}
}
1.2 Collections的sort方法
A:sort方法的作用:
对集合中元素排序
B:sort方法签名
public static<T> void sort(List<T> list)
有顺序(有序):第一个元素是多少,第二个元素是多少,第几个元素对应的是第几,顺序不变.
排序:不管是第几个放的,只要到集合中(以Integer集合为例),就按照一定的顺序重新排列了.
1.2.1 案例代码八:
package com.itheima10CollectionOthers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
* Collections:集合工具类,包含了众多集合的方法
*
* public static <T> voidsort(List<T> list) //排序
* public static <T> intbinarySearch(List<?> list,T key) //查找元素索引
* 二分法查找:在一个集合当中,查找一个指定元素的索引是多少,如果不存在该元素,就返回负数索引
* 二分法查询必须要求集合中的元素排好顺序
*
* public static void shuffle(List<?>list) //打乱元素顺序
*
* 有顺序(有序):第一个元素是多少,第二个元素是多少,第几个元素对应的是第几,顺序不变.
* 排序:不管是第几个放的,只要到集合中(以Integer集合为例),就按照一定的顺序重新排列了.
*/
public class Demo02Collections {
public staticvoid main(String[] args) {
//准备集合及元素
List<Integer>list = newArrayList<Integer>();
list.add(2);
list.add(7);
list.add(6);
list.add(10);
list.add(9);
//将集合排好顺序(Integer数字的自然顺序是从小到大排列)
Collections.sort(list);
System.out.println(list);
//如果放字符串(字符串的顺序是字母排序.)
List<String>list2 = newArrayList<String>();
list2.add("a");
list2.add("d");
list2.add("c");
list2.add("b");
System.out.println(list2);
Collections.sort(list2);
System.out.println(list2);
//如果放Person对象(人这个自定义数据类型的对象没有比较顺序,不知道什么样的人叫大,什么样的人叫小,所以人不能比较.就不能排序)
Personp = newPerson("Jack",18);
Personp2 = newPerson("Rose",20);
Personp3 = newPerson("Adda",24);
List<Person>list3 = newArrayList<Person>();
list3.add(p);
list3.add(p2);
list3.add(p3);
// Collections.sort(list3);
}
}
1.1 Collections的二分法查找
A: binarySearch方法的作用:
查找集合中指定元素的索引
B:binarySearch方法签名
public static <T> int binarySearch(List<?> list,T key)
1.1.1 案例代码九:
package com.itheima10CollectionOthers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
* Collections:集合工具类,包含了众多集合的方法
*
* public static <T> voidsort(List<T> list) //排序
* public static <T> intbinarySearch(List<?> list,T key) //查找元素索引
* 二分法查找:在一个集合当中,查找一个指定元素的索引是多少,如果不存在该元素,就返回负数索引
* 二分法查询必须要求集合中的元素排好顺序
*
* public static void shuffle(List<?>list) //打乱元素顺序
*
* 有顺序(有序):第一个元素是多少,第二个元素是多少,第几个元素对应的是第几,顺序不变.
* 排序:不管是第几个放的,只要到集合中(以Integer集合为例),就按照一定的顺序重新排列了.
*/
public class Demo02Collections {
public staticvoid main(String[] args) {
//验证二分法查找元素必须有序
List<Integer>list4 = newArrayList<Integer>();
list4.add(2);
list4.add(7);
list4.add(6);
list4.add(10);
list4.add(9);
int binarySearch= Collections.binarySearch(list4, 9);
System.out.println(binarySearch);
Collections.sort(list4);
System.out.println(list4);
int binarySearch2= Collections.binarySearch(list4, 9);
System.out.println(binarySearch2);
}
}
1.2 Arrays的toString方法
A: toString方法的作用:
返回字符串内容
B:toString方法签名:
publicstatic String toString(Xxx[] a)
1.2.1 案例代码十:
package com.itheima10CollectionOthers;
import java.util.Arrays;
/*
* Arrays:数组工具类,包含了许多数组工具方法
*
* public static int binarySearch(Xxx[]a,Xxx key) //查找元素索引
* public static void sort(Xxx[] a) //排序
* public static String toString(Xxx[]a) //返回字符串内容
*/
public class Demo03Arrays {
public staticvoid main(String[] args) {
String[]arr = {"Jack","Rose","Trump"};
// Integer[] arr = {3,1,5,6,2,19};
System.out.println(arr);
//调用Arrays的toString方法
System.out.println(Arrays.toString(arr));
System.out.println(Demo03Arrays.toString(arr));
}
}
1.3 数组转集合
数组转集合使用的是,Arrays类中的asList方法
方法签名如下:
public static <T> List<T>asList(T... a)
解释:
静态方法,直接类名.方式调用
方法的形参是可变参数类型,可变参数本质也是数组,传入实际数组,将该数组转成集合返回
注意:
数组转成集合之后,该集合不支持添加或者删除操作,否则会抛出UnsupportedOperationException异常
1.3.1 案例代码十一:
package com.itheima10CollectionOthers;
import java.util.Arrays;
import java.util.List;
/*
* 数组转集合
*
* Arrays:
* publicstatic <T> List<T> asList(T... a) //数组转集合
*
* UnsupportedOperationException:不支持的添加或者删除操作
*/
public class Demo04Arrays_asList{
public staticvoid main(String[] args) {
List<String>newList = Arrays.asList("Jack","Rose","Trump");
System.out.println(newList);
//使用asList转成的集合,不能添加或者删除元素,该方法返回的集合长度不能改变!所以,22行运行报错.
newList.add("Obama");
System.out.println(newList);
}
}
1.4 集合转数组
集合ArrayList转数组使用的是,ArrayList中的toArray()方法。
该方法是重载的方法:
public Object[] toArray()
public <T> T[] toArray(T[] a)
1.4.1 案例代码十二:
package com.itheima10CollectionOthers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*
* 集合转数组:
* 集合ArrayList转为数组的方法为ArrayList的以下两个方法:
* publicObject[] toArray() //集合转数组
* public<T> T[] toArray(T[] a)
*/
public classDemo05ArrayList_toArray {
public staticvoid main(String[] args) {
List<Integer>list = newArrayList<Integer>();
list.add(2);
list.add(7);
list.add(6);
list.add(10);
list.add(9);
//调用方法,将集合转为Object类型数组
Object[]objArr = list.toArray();
System.out.println(Arrays.toString(objArr));
Integeri = (Integer) objArr[0];
//如果使用元素类型Integer的特有方法,则必须先强转成Integer,否则intValue方法不能使用,比较麻烦
System.out.println(i.intValue());
System.out.println("=======================");
//调用方法,将集合转为带类型的数组
Integer[]intArr = newInteger[2];
Integer[]returnArr = list.toArray(intArr);
//如果参数数组足够放下集合中所有元素,就放入参数数组中,返回参数数组
//如果参数数组无法放下集合中所有元素,则参数数组只起到确定类型作用,方法逻辑会自动创建新数组存储集合内容,并返回.
System.out.println(Arrays.toString(intArr));
System.out.println(Arrays.toString(returnArr));
//带泛型后,元素类型直接就是集合中的元素类型,避免了强转的问题
Integerinteger = returnArr[0];
System.out.println(integer.intValue());
}
}
斗地主发牌洗牌案例:
需求分析:
A:准备牌:
完成数字与纸牌的映射关系:
使用双列Map(HashMap)集合,完成一个数字与字符串纸牌的对应关系(相当于一个字典)。
B:洗牌:
通过数字完成洗牌发牌
C:发牌:
将每个人以及底牌设计为ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
存放的过程中要求数字大小与斗地主规则的大小对应。
将代表不同纸牌的数字分配给不同的玩家与底牌。
D:看牌:
通过Map集合找到对应字符展示。
通过查询纸牌与数字的对应关系,由数字转成纸牌字符串再进行展示。
package com.itheima09.map;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/*
* 按照斗地主的规则,完成洗牌发牌的动作。
* ♣♦♠♥ 大☺小☺
* 具体规则:
* 使用54张牌打乱顺序
* 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
*
* 逻辑分析:
*
* 每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合嵌套迭代完成每张牌的组装。
* 使用一个Map集合,<<将小的数字与小的牌对应起来>>,做成Map集合的键与值
* 即:
* 键:数字
* 值:花色+数字的字符串(牌)
*
* 准备牌:
* 牌可以设计为一个ArrayList<Integer>,每个数字为一张牌。
* 牌由Collections类的shuffle方法进行随机排序。
* 发牌:
* 将每个人以及底牌设计为ArrayList<Integer>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
* 看牌:
* 将所有集合排序Collections类的sort方法进行排序
* 将每个集合的数字依次找到对应的纸牌字符串打印出来
*/
public class Test{
public static void main(String[] args) {
//确立纸牌与数字的对应关系
Map<Integer, String> map = new HashMap<Integer, String>();
//花色集合
ArrayList<String> colors = new ArrayList<String>();
colors.add("♣");
colors.add("♦");
colors.add("♠");
colors.add("♥");
//数字集合,加入数字时,直接按照从小到大的顺序加入
ArrayList<String> numbers = new ArrayList<String>();
for (int i = 3; i <= 10; i++) {
numbers.add(i+"");
}
Collections.addAll(numbers, "J","Q","K","A","2");
//定义数字,用于记录数字与字符串纸牌的对应关系
int card_number = 0;
//遍历数字集合,使用每个数字匹配每种花色
for (String thisNumber : numbers){
//使用数字匹配所有花色
for (String thisColor : colors) {
String thisCard = thisColor+ thisNumber;
//匹配数字与字符串纸牌,完成对应关系
map.put(card_number, thisCard);
//每加入一个对应关系,就让数字加1
card_number++;
}
}
//加入大小王对应关系
map.put(card_number++, "小☺");
map.put(card_number, "大☺");
System.out.println(map);
//准备牌:
ArrayList<Integer> poker = new ArrayList<Integer>();
for (int i = 0; i < 54; i++) {
poker.add(i);
}
//打乱顺序
Collections.shuffle(poker);
//发牌:
ArrayList<Integer> player01 = new ArrayList<Integer>();
ArrayList<Integer> player02 = new ArrayList<Integer>();
ArrayList<Integer> player03 = new ArrayList<Integer>();
ArrayList<Integer> dipai = new ArrayList<Integer>();
for (int index = 0; index <poker.size(); index++) {
//通过索引,获取代表牌的数字
Integer integer_card =poker.get(index);
//是否为底牌的判断
if(index>=51) {
dipai.add(integer_card);
}else {
//对3取模判断发给哪个玩家
if(index%3==0) {
player01.add(integer_card);
}else if(index%3==1){
player02.add(integer_card);
}else {
player03.add(integer_card);
}
}
}
//将所有集合排序Collections类的sort方法进行排序
Collections.sort(player01);
Collections.sort(player02);
Collections.sort(player03);
Collections.sort(dipai);
//看牌
for (Integer integer : player01){
String realCard =map.get(integer);
System.out.print(realCard+" ");
}
System.out.println();
for (Integer integer : player02){
String realCard =map.get(integer);
System.out.print(realCard+" ");
}
System.out.println();
for (Integer integer : player03){
String realCard =map.get(integer);
System.out.print(realCard+" ");
}
System.out.println();
for (Integer integer : dipai) {
String realCard =map.get(integer);
System.out.print(realCard+" ");
}
}
}