文章目录
概述
体系
基本方法演示
java文档中的java.util–>接口–>collection
Collection接口中的共性功能。
1.添加。
boolean add(Object obj);一次添加一个
boolean addAlll(Collection c);接收的是容器。将指定容器中的所有元素添加。
2.删除。
void clear();将容器中所有元素清除
boolean remove(Object o);
boolean removeAlll(Collection c);
3.获取长度
int size();
4.判断
boolean isEmpty();是否为空
boolean contains(Object o);是否包含该元素
boolean containsAll(Collection c);
boolean retainAll(Collection c);
5.将集合转成数组。
toArray();
toArray([]);
6.取出集合元素
Iterator iterator();返回在此collection的元素上进行迭代的迭代器。
获取集合中元素上迭代功能的迭代器对象。
迭代:取出元素的一种方式。
迭代器:具备着迭代功能的对象。
而迭代器对象不需要new。直接通过iterator()方法获取接口即可。
演示Collection中的基本功能。
class ExtendsDemo3 {
public static void main(String[] args) {
Collection coll=new ArrayList();//虽然Collection是接口,无法new,但可以找出它地子类来新建对象,这里找ArrayList。
methodDemo(coll);
}
public static void methodDemo(Collection coll) {
//添加和删除元素会改变集合的长度。
//1.添加元素
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
System.out.println(coll.size());//看大小
System.out.println(coll.toString());//看内容
//2.删除
coll.remove("abc2");
System.out.println(coll);//看内容
//3.清除
coll.clear();
System.out.println(coll);//看内容
//4.包含
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
System.out.println("contains:"+coll.contains("abc"));//看是否包含
}
}
演示带All的方法
import java.util.ArrayList;
/*
* 对一个有多个数值的字符串,进行数值的排序。
*/
import java.util.Arrays;
import java.util.Collection;
//MyStringBuilder
class ExtendsDemo3 {
public static void main(String[] args) {
methodAllDemo(coll);
}
public static void methodAllDemo(Collection coll) {
// 1.创建两个容器。
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
// 2.添加元素。
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
c2.add("abc2");
c2.add("abc3");
c2.add("abc5");
/*
* //判断c1中是否包含c2的所有元素, boolean b=c1.containsAll(c2);
* System.out.println("b="+b);//输出false
*
* //往c1中添加c2 c1.addAll(c2); System.out.println(c1);
*
* //从c1中删除c2 c1.removeAll(c2);//将c1中和c2相同的元素从c1中删除。
* System.out.println(c1);//输出[abc1, abc4]
*/
c1.retainAll(c2);// 将c1中c2不同是我元素从c1中删除。保留c1中和c2相同的元素。如果没有相同的,返回[]。
System.out.println(c1);
}
}
演示迭代器
class ExtendsDemo3 {
public static void main(String[] args) {
//1.创建集合。
Collection coll=new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//获取该容器的迭代器。
java.util.Iterator it=coll.iterator();
//================常用方法=============
for (java.util.Iterator iterator = coll.iterator(); iterator.hasNext();) {
System.out.println(iterator.next());
}
//================第二种方法=============
/*while(it.hasNext()) //如果有元素,循环。
{
System.out.println(it.next());
}*/
//================第三种方法=============
/*
* System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());//报错。Exception in thread "main" java.util.NoSuchElementException
*/ }
}
迭代器原理
迭代器是取出collection集合中元素的公共方式。
实现方法是接口
List
List和set的区别
Collection
|--List:有序(存入的顺序和取出的顺序一致)。有索引。允许重复元素。
|--Set:不允许重复元素。
List的常见方法
重点List接口中的特有方法:它的特有方法都是围绕索引定义的。
支持增删改查
增
add(index,element)
删
remove(index)
改
set(index,nevelement)
查
int indexOf(element);
element get(index);
演示List特有的方法
class ExtendsDemo3 {
public static void main(String[] args) {
List list = new ArrayList();
methodDemo(list);
}
public static void methodDemo(List list) {
// 1.常规添加元素
list.add("abc1");
list.add("abc2");
list.add("abc3");
// 2.插入元素
list.add(1, "hehe");
System.out.println(list);
// 3.删除元素
list.remove(1);
// list.remove(1);
System.out.println(list);
// 4.获取。
System.out.println(list.get(1));// 报错,Exception in thread "main" java.lang.IndexOutOfBoundsException
System.out.println(list.indexOf("abc1"));
// 5.修改
list.set(1, "k");
System.out.println(list);
// 取出集合中所有的元素(迭代方式)
for (java.util.Iterator it = list.iterator(); it.hasNext();) {
System.out.println("iterator:" + it.next());
}
// List集合特有的取出方式。
for (int i = 0; i < list.size(); i++) {
System.out.println("get:" + list.get(i));
}
}
}
ListIterator
如果迭代过程中同时add其他元素。会引发异常。
迭代过程中使用了其他集合对象同时对元素进行操作,导致了迭代的不确定性。引发了该异常。
解决思想:在迭代过程中,想要执行一些操作,使用迭代器的方法即可。
使用list集合的特有的迭代器:ListIterator。通过List集合的方法ListIterator()获取该迭代器对象。
ListIterator可以实现在迭代过程中的增删改查。它使用角标实现方法的。
它除了有next(),还可以previous()。
注意:迭代器Iterator只有三个方法,不能完成增改查‘当要用到增改查的时候,就要用ListIterator。
boolean hasNext()
如果仍有元素可以迭代,则返回 true。
boolean next()
返回迭代的下一个元素。
void remove()
从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
举例:
class IteratorDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//在遍历的过程中,如果遍历到abc2,添加一个元素haha
for (java.util.Iterator it = list.iterator(); it.hasNext();) {
Object obj = it.next();
if(obj.equals("abc2"))
list.add("haha");// 报错,并发修改java.util.ConcurrentModificationException
//4个迭代器,但有5个元素。
}
System.out.println(list);
}
}
改进:
class IteratorDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//在遍历的过程中,如果遍历到abc2,添加一个元素haha
for (java.util.ListIterator it = list.listIterator(); it.hasNext();) {
Object obj = it.next();
if(obj.equals("abc2"))
it.add("haha");
}
System.out.println(list);
}
}
List子类介绍
List集合的具体子类.子类之所以区分是因为内部的数据结果(存储数据方式)不同。
|--Vector:数据结构是数组。数据是可变长度的(不断new新数组并将原数组元素复制到新数组)。线程同步的。
JDK1.0(JDK1.0只有集合对象 )。都慢。
|--ArrayList:也是数组结构,也是长度可变。JDK1.2(集合框架从1.2开始),线程不同步的,替代了Vector。
增删速度不快。查询速度很快。
|--LinkedList:链表结构。线程不同步的。增删速度很快。
ArrayList
一、存储自定义对象
需求:往ArrayList中存储自定义对象。Person(name,age)
思路:
1.描述Person。
2.定义容器对象。
3.将多个Person对象,存储到集合中。
4.取出Person对象。
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
class ExtendsDemo3 {
public static void main(String[] args) {
// 1.创建ArrayList集合对象
List list = new ArrayList();
// 2.添加Person类型的对象
Person p1 = new Person("lisi1", 21);
Person p2 = new Person("lisi2", 22);
list.add(p1);// add(Object obj)
list.add(p2);
list.add(new Person("lisi3", 23));
// 取出元素,用普通迭代器的方法。
for (java.util.Iterator it = list.listIterator(); it.hasNext();) {
// it.next();取出的元素都是Object类型的。需要用到具体对象的内容时,需要向下转型。
Person p = (Person) it.next();// 向下转型
System.out.println(p.getName() + ":" + p.getAge());
}
}
}
练习二:去除重复元素
需求:定义功能:请除去ArrayList集合中的重复元素。
方法1:
class ExtendsDemo3 {
public static void main(String[] args) {
// 1.创建ArrayList集合对象
List list = new ArrayList();
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
System.out.println(list);
singleElement(list);
System.out.println(list);
}
// 定义功能,取出重复元素。
public static void singleElement(List list) {
for (int x = 0; x < list.size() - 1; x++) {
Object obj_x = list.get(x);
for (int y = x + 1; y < list.size(); y++) {
if (obj_x.equals(list.get(y))) {
list.remove(y);// 一旦remove,长度改变。所以y还得再回到原位进行比较。
y--;
}
}
}
}
}
方法2:
思路:
1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。
2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这个功能。判断元素是否存在。
3.存在就不存储,不存在就存储。
4.遍历完原容器后,临时容器中存储的就是唯一性的容器。
//IteratorDemo
class ExtendsDemo3 {
public static void main(String[] args) {
// 1.创建ArrayList集合对象
List list = new ArrayList();
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
System.out.println(list);
singleElement2(list);
System.out.println(list);
}
// 去除重复元素方式二:
public static void singleElement2(List list) {
//1.定义一个临时容器。
List temp=new ArrayList();
//2.遍历原容器
for (java.util.Iterator iterator = list.iterator(); iterator.hasNext();) {
Object obj= (Object) iterator.next();
//3.在临时容器中判断遍历到的元素是否存在。
if(!(temp.contains(obj))) {
//4.如果不存在,就存储到临时容器中。
temp.add(obj);
}
}
//5.将原容器清空。
list.clear();
//6.将临时容器中的元素都存储到原容器中。
list.addAll(temp);
}
}
把这个思想用到自定义对象:
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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;
}
//建立Person类自己的判断对象是否相同的依据,必须要覆盖Object类中的equals方法。
public boolean equals(Object obj) {
System.out.println(this+"...."+obj);//这里的this是temp。
//为了提高效率,如果比较的对象是同一个,直接返回true。
if(this==obj) {
return true;
}
if(!(obj instanceof Person)) {
throw new ClassCastException("类型错误");
}
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
class IteratorDemo {
public static void main(String[] args) {
// 1.创建ArrayList集合对象
List list = new ArrayList();
// 2.添加Person类型的对象
Person p1 = new Person("lisi1", 21);
Person p2 = new Person("lisi2", 22);
list.add(p1);// add(Object obj)
list.add(p1);// add(Object obj)//存储了一个地址相同的对象。
list.add(p2);
list.add(new Person("lisi3", 23));
list.add(new Person("lisi1", 21));
list.add(new Person("lisi2", 22));
System.out.println(list);
singleElement2(list);//去除重复元素
System.out.println(list);
}
// 去除重复元素方式二:
public static void singleElement2(List list) {
//1.定义一个临时容器。
List temp=new ArrayList();
//2.遍历原容器
for (java.util.Iterator iterator = list.iterator(); iterator.hasNext();) {
Object obj= (Object) iterator.next();
//3.在临时容器中判断遍历到的元素是否存在。
if(!(temp.contains(obj))) {//contains实际是equals的封装,Object中的equals是看地址是否一致。
//4.如果不存在,就存储到临时容器中。
temp.add(obj);
}
}
//5.将原容器清空。
list.clear();
//6.将临时容器中的元素都存储到原容器中。
list.addAll(temp);
}
}
LinkedList
特殊的方法
class IteratorDemo {
public static void main(String[] args) {
//1.创建一个链表对象。//演示XXXFirst XXXLast。
LinkedList link=new LinkedList();
//2.添加方法
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
//3.获取元素
System.out.println(link.getFirst());//abc3
System.out.println(link.getFirst());//abc3
/*//4.删除元素
System.out.println(link.removeFirst());//abc3,先返到开头
System.out.println(link.removeFirst());//去除,abc2
System.out.println(link.removeFirst());//去除,abc1
*/
//5.取出link中所有元素。
while(!link.isEmpty()) {
System.out.println(link.removeFirst());//removeLast();
}
}
}
实现队列结构
需求:请通过LinkedList实现一个堆栈,或者队列数据结构。
堆栈:先进后出。First In Last Out FILO.
队列:先进先出。First In First Out FIFO.
class MyQueue {
private LinkedList link;
MyQueue(){
link=new LinkedList();
}
/*
* 添加元素的方法
*/
public void myAdd(Object obj) {
//内部使用的是linkedList的方法。
link.addFirst(obj);
}
/*
* 获取队列元素的方法
*/
public Object myGet() {
return link.removeLast();
}
/*
* 集合中是否有元素的方法
*/
public boolean isNull() {
return link.isEmpty();
}
}
class MyQueueDemo {
public static void main(String[] args) {
//1.创建自定义的队列对象
MyQueue queue=new MyQueue();
//2.添加元素
queue.myAdd("abc1");
queue.myAdd("abc3");
queue.myAdd("abc4");
queue.myAdd("abc5");
//3.获取所有元素。先进先出。
while(!queue.isNull()) {
System.out.println(queue.myGet());
}
}
}
Hash
Set集合:不允许重复元素。和Collection的方法相同。Set集合取出方法只有一个:迭代器。
|--HashSet:不保证有序。哈希(散列)表结构。
如何保证唯一性?
元素必须覆盖hashCode和equals方法。
覆盖hashCode方法是为了根据元素自身的特点确定hash值。
覆盖equals方法,是为了解决哈希值的冲突。
|--TreeSet:二叉树数据结构。可以对元素进行排序。不同步的。
如何保证元素唯一性?
参考的就是比较方法的返回值是否是0,是,就是重复元素,不存。
排序方式:需要元素具备比较功能。所以元素需要实现Comparable接口。覆盖compareTo方法。
HashSet集合演示
//HashSetDemo
class ExtendsDemo3 {
public static void main(String[] args) {
//1.创建一个Set容器对象。
Set set=new HashSet();
//2.添加元素
set.add("haha");
set.add("abc");
set.add("nba");
set.add("heihei");
//3.只能用迭代器取出。
for (java.util.Iterator it= set.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
结果:
haha
abc
heihei
nba
哈希表
哈希表_冲突的解决
当哈希算法算出的两个元素的值相同时,称为哈希冲突。
冲突后,需要对元素进行进一步的判断。判断的是元素的内容。equals();
哈希算法:hashcode();
在java.lang中的Object中的方法摘要中。
哈希表在哦安端圆度是否相同,依据hashcode方法。
如果哈希重复(哈希值相同),再判断元素的equals方法。如果equals方法返回true,不存,返回false,存储。
哈希表_存储自定义对象
需求:往HashSet中存储学生对象(姓名,年龄)。通姓名。同年龄视为同一个人 。不存。
思路:
1.描述学生。
2.定义容器。
3.将学生对象存储到容器中。
public class Student {
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
/*
* 覆盖hashCode方法。根据对象自身的特点定义哈希值。
*
*/
public int hashCode(){
final int Number=37;
return name.hashCode()+age*Number;//哈希冲突降低
}
/*
* 需要定义对象自身判断内容相同的依据,覆盖equals方法。
*/
public boolean equals(Object obj){
if(this==obj) {
return true;
}
if(!(obj instanceof Student)) {
throw new ClassCastException(obj.getClass().getName()+"类型错误");
}
Student stu=(Student) obj;
return this.name.equals(stu.name)&&this.age==stu.age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
}
class HashSetDemo {
public static void main(String[] args) {
//发现存储了同姓名同年龄的学生时可以的。
//原因是每一次存储学生对象,都先调用hashCode方法获取哈希值。
//但是调用的是Object类中的hashCode,所以不同的对象,哈希值也不同。
//这就是同姓名同年龄存入的原因。
/*
* 解决:
* 需要根据学生对象自身的特点来定义哈希值。
* 所以就需要覆盖hashCode()方法。
*/
//1.创建容器对象。
Set set=new HashSet();
//2.存储学生对象。
set.add(new Student("xiaoqiang",20));
set.add(new Student("xiaoqiang",20));//原本应该去掉这个结果,但是这里的地址不同。
set.add(new Student("wangcai",27));
set.add(new Student("xiaoming",22));
set.add(new Student("daniu",24));
//3.获取所有学生
for (java.util.Iterator it= set.iterator(); it.hasNext();) {
Student stu=(Student)it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
字符串String也有自己hashCode()方法:
public int hashCode()
返回此字符串的哈希码。 String 对象的哈希码根据以下公式计算:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s[i] 是字符串的第 i 个字符, n 是字符串的长度, ^ 表示求幂。(空字符串的哈希值为 0。)
LinkedHashSet
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
实现有序
把Set set=new HashSet();
改为Set set=new LinkedHashSet();
即可。
TreeSet
演示
class TreeSetDemo{
public static void main(String[] args) {
Set set=new TreeSet();
set.add("abc");
set.add("nba");
set.add("heihei");
set.add("haha");
set.add("heihei");
for (java.util.Iterator it= set.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
自定义演示
public class Student implements Comparable{
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
//学生就具备了比较功能。该功能是自然排序使用的方法。
//自然排序就年龄的升序排序为主。
@Override
public int compareTo(Object o) {
Student stu=(Student)o;
System.out.println(this.name+":"+this.age+"......"+stu.name+":"+stu.age);
if(this.age>stu.age)
return 1;
if(this.age<stu.age)
return -1;
return 0;
}
}
class TreeSetDemo {
public static void main(String[] args) {
Set set=new TreeSet();
set.add(new Student("xiaoqiang",20));
//java,lang.AlassCastException:因为学生要排序,就需比较,二没有定义比较方法,无法完成排序。
//比较add方法中使用的是Comparable接口的比较方法。
set.add(new Student("xiaoming",22));
set.add(new Student("daniu",24));
for (java.util.Iterator it= set.iterator(); it.hasNext();) {
Student stu=(Student)it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
结果:
xiaoqiang:20......xiaoqiang:20
xiaoming:22......xiaoqiang:20
daniu:24......xiaoqiang:20
daniu:24......xiaoming:22
xiaoqiang::20
xiaoming::22
daniu::24
TreeSet_比较功能compareTo
注意:
把
if(this.age>stu.age)
return 1;
if(this.age<stu.age)
return -1;
return 0;
改为
return 1;//就成为有序的。
TreeSet_比较功能注意事项
假如年龄相同而名字不同,那么可以把上述代码的第一段改成如下:
public class Student implements Comparable{
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
//学生就具备了比较功能。该功能是自然排序使用的方法。
//自然排序就年龄的升序排序为主。
@Override
public int compareTo(Object o) {
Student stu=(Student)o;
System.out.println(this.name+":"+this.age+"......"+stu.name+":"+stu.age);
int temp=this.age-stu.age;
return temp==0?this.name.compareTo(stu.name):temp;//比大小。
}
}
TreeSet比较器
需求中也有这样一种情况,元素具备的比较功能不是所需要的,也就是说不想按照自然排序的方式,而是按照自定义的排序方式,对元素进行排序。
而且,存储到TreeSet中的元素万一没有比较功能,该如何排序呢?
这时,就只能使用第二种比较方式——是让集合具备比较功能。定义一个比较器。
实现Comparator接口,覆盖compare方法。将Comparator接口的对象作为参数传递给TreeSet集合的构造函数。
比较器更为灵活。自然排序通常都作为元素的默认排序。
int compare(Object o1,Object o2);
boolean equals(Object obj) ;指示某个其他对象是否“等于”此 Comparator。
/*
* 自定义图=一个比较器。用来对学生对象按照姓名进行排序。
*/
public class ComparatorByName extends Object implements Comparator{
public int compare(Object o1,Object o2) {
Student s1=(Student)o1;
Student s2=(Student)o2;
int temp=s1.getName().compareTo(s2.getName());
return temp==0?s1.getAge()-s2.getAge():temp;
}
}
public class Student implements Comparable{
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
}
class ExtendsDemo3 {
public static void main(String[] args) {
//初始化Treeset集合明确一个比较器。
Set set=new TreeSet(new ComparatorByName());
set.add(new Student("xiaoqiang",20));
set.add(new Student("daniu",24));
set.add(new Student("xiaoming",22));
set.add(new Student("tudou",18));
set.add(new Student("daming",22));
set.add(new Student("dahuang",19));
for (java.util.Iterator it= set.iterator(); it.hasNext();) {
Student stu=(Student)it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
集合名词阅读技巧
技巧:
jdk1.2以后出现的集合框架中的常用子类对象,存在的规律。
前缀名数据结构面,后缀名是所属体系名。
ArrayList:数组结构。看到数组就知道查询快,看到List就知道可以重复,可以增删改查。
LinkedList::链表结构,增删快。XXXFirst; XXXLast;XXX:add get remove
HashSet:哈希表,就要想到元素必须覆盖hashCode equals。查询速度更快。不保证有序。看到Set就知道不可以重复。
LinkedHashSet::链表+哈希表,可以实现有序。
TreeSet:二叉树,可以排序。就要想要两种比较方式:一种是自然排序comparable 一种是比较器Comparator。
Foreach语句
JDK1.5特性:
增强for循环。作用:用于遍历Collection集合or数组。
格式:
for(元素类型变量:Collection容器or数组)
{}
对于数组的遍历,如果不操作其角标,可以使用增强for;
如果要操作角标,使用传统for循环。
传统for循环和增强for循环有什么区别呢?
增强for必须有遍历目标,而该目标只能是Collection数组。
class ExtendsDemo3 {
public static void main(String[] args) {
Collection coll=new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
/*for(java.util.Iterator it=coll.iterator();it.hasNext();) {
Object obj=it.next();
System.out.println(obj);
}*/
for(Object obj:coll) {
System.out.println(obj);
}
//对于数组的遍历,如果不操作其角标,可以使用增强for;
//如果要操作角标,使用传统for循环。
int[] arr= {23,15,32,78};
for(int x:arr) {
System.out.println(x);
}
}
}
Enumeration接口
Enumeration:枚举。
具枚举取出方式的容器只有Vector。
class ExtendsDemo3 {
public static void main(String[] args) {
Vector v=new Vector();
v.add("abc1");
v.add("abc2");
v.add("abc3");
v.add("abc4");
//获取枚举(已过时)
for(Enumeration en=v.elements();en.hasMoreElements();) {
System.out.println("enumeration:"+en.nextElement());
}
//获取迭代(可以在迭代过程中进行操作)
for (java.util.Iterator it = v.iterator(); it.hasNext();) {
System.out.println("iterator:"+it.next());
}
//高级or(最简单)
for(Object obj:v) {
System.out.println("foreach:"+obj);
}
}
}
练习
需求1:对多个字符串(不重复)按照长度排序(由短到长)。
思路:
1.多个字符串,需要容器存储。
2.选择哪个容器。字符串是对象,可以选择集合,而且不重复,选择Set集合。
3.还需要排序,可以选择TreeSet集合。
public class ComparatorByLength implements Comparator{
public int compare(Object o1,Object o2) {
//对字符串按照长度比较。
String s1=(String)o1;
String s2=(String)o2;
//比较长度。
int temp=s1.length()-s2.length();
//长度相同,再按字典顺序。
return temp==0?s1.compareTo(s2):temp;
}
}
class ExtendsDemo3 {
public static void main(String[] args) {
sortStringByLength();
}
public static void sortStringByLength() {
Set set=new TreeSet(new ComparatorByLength());//自然排序的方式。
set.add("haha");
set.add("abc");
set.add("zz");
set.add("nba");
set.add("xixixi");
set.add("haha");
for(Object obj:set){
System.out.println(obj);
}
}
}
需求2:对多个字符串(重复),按照长度排序。
思路:
1.能使用TreeSet么?不能。
2.可以存储到数组,list。这里先选择数组。
回顾:
之前写的按照自然排序的方法。
class ExtendsDemo3 {
public static void main(String[] args) {
sortStringByLength2();
}
public static void sortStringByLength2() {
String[] strs= {"haha","abcccc","zero","xixi","nba","abcccc","cctv","zero"};
//排序就需要嵌套循环。位置变换。
for(int x=0;x<strs.length-1;x++) {
for(int y=x+1;y<strs.length;y++) {
if(strs[x].compareTo(strs[y])>0) {
swap(strs,x,y);
}
}
}
for(String s:strs) {
System.out.println(s);
}
}
private static void swap(String[] strs, int x, int y) {
String temp=strs[x];
strs[x]=strs[y];
strs[y]=temp;
}
}
在新的需求下:
public class ComparatorByLength implements Comparator{
public int compare(Object o1,Object o2) {
//对字符串按照长度比较。
String s1=(String)o1;
String s2=(String)o2;
//比较长度。
int temp=s1.length()-s2.length();
//长度相同,再按字典顺序。
return temp==0?s1.compareTo(s2):temp;
}
}
class ExtendsDemo3 {
public static void main(String[] args) {
sortStringByLength2();
}
public static void sortStringByLength2() {
String[] strs= {"haha","abcccc","zero","xixi","nba","abcccc","cctv","zero"};
//自然排序可以使用String类中的compareTo方法。
//但是现在要的是长度排序,这就需要比较器。
//定义一个按照长度排序的比较器对象。
Comparator comp=new ComparatorByLength();
//排序就需要嵌套循环。位置变换。
for(int x=0;x<strs.length-1;x++) {
for(int y=x+1;y<strs.length;y++) {
//if(strs[x].compareTo(strs[y])>0) {//按照字典顺序。
if(comp.compare(strs[x],strs[y])>0) {//按照长度顺序。
swap(strs,x,y);
}
}
}
for(String s:strs) {
System.out.println(s);
}
}
private static void swap(String[] strs, int x, int y) {
String temp=strs[x];
strs[x]=strs[y];
strs[y]=temp;
}
}
集合框架_泛型
概述
class ExtendsDemo3 {
public static void main(String[] args) {
int[] arr=new int[2];
arr[0]=2.0;//会报错
List list=new ArrayList();
list.add("abc");
list.add(4);//List.add(Integer.valueOf(4));自动装箱
for (java.util.Iterator it = list.iterator(); it.hasNext();) {
//Object obj=it.next();
String str=(String) it.next();
//System.out.println(it.next()); //这里调用的是toString方法
System.out.println(str.length());//java.lang.ClassCastException:
//java.lang.Integer cannot be cast to java.lang.String
}
}
}
出现报错
为了运行时期不出现类型异常。可以在定义容器时,就明确容器中的元素的类型。
这样在集合中传入其他类型时,就会报错,保证了其安全性。
//HashSetDemo
class GenericDemo {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("abc");
list.add(4);//List.add(Integer.valueOf(4));自动装箱
for (java.util.Iterator<String> it = list.iterator(); it.hasNext();) {
//Object obj=it.next();
String str=it.next();//这里就不需要强转。
//System.out.println(it.next());
System.out.println(str.length());
}
}
}
总结:
泛型:
在JDK1.4版本之前,容器什么类型的对象都可以存储。但是在取出时,需要用到对象的特有内容时,需要做向下转型。
但是对象的类型不一致,导致了向下转型发生了ClassaCastException异常,
为了避免这个问题,只能主观上控制往集合中存储的对象类型保持一致。
JDK1.5以后解决了该问题,在定义集合时,就直接明确集合中存储元素的具体类型。
这样,编译器在编译时,就可以对几何中存储的对象类型进行检查。
一旦发现类型不匹配,就编译失败。这个技术就是泛型 技术。
好处:
1.将运行时期的问题转移到了编译时期,可以更好地让程序员发现问题并解决问题。
2.避免了向下转型的麻烦。
综合以上:泛型就是应用在编译时期的一项安全机制。
**泛型的擦除:**编译器通过泛型对元素类型进行检查,只要检查通过,就会生成class文件中,就将泛型标识去掉了。
**泛型的表现:**泛型技术在集合框架中应用的范围很大,什么时候需要写泛型?
1.只要看到类,或者接口在描述时右边定义<>,就需要泛型。
其实时,容器在不明确操作元素的类型的情况下,对外提供了一个参数<>。
使用容器时,只要将具体的类型实参传递给该参数即可。
说白了,泛函就是,传递类型参数。
class GenericDemo2 {
public static void main(String[] args) {
//创建一个List集合.存储整数.List ArratList
List<Integer> list=new ArrayList<Integer>();
list.add(5);
list.add(6);
for(java.util.Iterator<Integer> it=list.iterator();it.hasNext();) {
Integer integer=it.next();
System.out.println(integer);
}
}
}
class GenericDemo3 {
public static void main(String[] args) {
Set<String> set=new TreeSet<String>();
set.add("abcd");
set.add("aa");
set.add("nba");
set.add("cba");
for(String s:set) {
System.out.println(s);}
}
}
当对象为Student类型时,
import java.util.LinkedList;
public class Student implements Comparable<Student>{
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
//学生就具备了比较功能。该功能是自然排序使用的方法。
//自然排序就年龄的升序排序为主。
@Override
public int compareTo(Student o) {
Student stu=o;
int temp=this.age-stu.age;
return temp==0?this.name.compareTo(stu.name):temp;//比大小。
}
}
import java.util.Set;
import java.util.TreeSet;
//GenericDemo3
class ExtendsDemo3 {
public static void main(String[] args) {
Set<Student> set<Student>=new TreeSet<Student>();
set.add(new Student("xiaoqiang",20));
set.add(new Student("xiaoming",22));
set.add(new Student("daniu",24));
for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {
Student stu=it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
Set List Iterator comparable comparator后面都要加
或者
import java.util.Comparator;
/*
* 自定义图=一个比较器。用来对学生对象按照姓名进行排序。
*/
public class ComparatorByName extends Object implements Comparator{
public int compare(Object o1,Object o2) {
Student s1=(Student)o1;
Student s2=(Student)o2;
int temp=s1.getName().compareTo(s2.getName());
return temp==0?s1.getAge()-s2.getAge():temp;
}
}
import java.util.Set;
import java.util.TreeSet;
import javax.naming.CompoundName;
//GenericDemo3
class ExtendsDemo3 {
public static void main(String[] args) {
Set<Student> set=new TreeSet<Student>(new ComparatorByName());
set.add(new Student("xiaoqiang",20));
set.add(new Student("xiaoming",22));
set.add(new Student("daniu",24));
for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {
Student stu=it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
当TreeSet变为HashSet,对象中有重复对象时,应该把重复对象去掉,这时的结果是没有重复结果且无规律的。
import java.util.LinkedList;
public class Student {
private String name;
private int age;
Student(){
}
Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public String toString() {
return "Student[name"+name+",age="+age+"]";
}
@Override
public int hashCode() {
final int NUMBER = 38;
return this.name.hashCode()+age*NUMBER;
}
@Override
public boolean equals(Object obj) {//注意,这里的强转是必须的,否则不能覆盖.
if(this==obj)//如果是同一个
return true;
if(!(obj instanceof Student))
throw new ClassCastException();
Student stu=(Student)obj;
return this.getName().equals(stu.getName())&&this.getAge()==stu.getAge();
}
}
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.naming.CompoundName;
//GenericDemo3
class ExtendsDemo3 {
public static void main(String[] args) {
Set<Student> set=new TreeSet();
set=new HashSet<Student>();
set.add(new Student("xiaoqiang",20));
set.add(new Student("xiaoqiang",20));
set.add(new Student("xiaoming",22));
set.add(new Student("xiaoming",22));
set.add(new Student("daniu",24));
for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {
Student stu=it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
泛型类
- 创建一个用于操作Student对象的工具类,对对象进行设置和获取.
- 太有局限性了,可不可以定义一个可以操作所有对象的工具呢?
- 类型向上抽取.
- 当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成.
- 但是这种方式有一些小弊端,回出现转型,向下转型容易在运行时期发生ClassCastException.
- jdk1.5以后,新的解决方案.
- 类型不确定时,可以对外提供参数.由使用者通过传递参数的形式完成类型的确定.
- 在定义时就明确参数。由使用该类的调用者来传递具体的类型。
/*
* 创建一个用于操作Student对象的工具类,对对象进行设置和获取.
* 太有局限性了,可不可以定义一个可以操作所有对象的工具呢?
* 类型向上抽取.
* 当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成.
* 但是这种方式有一些小弊端,回出现转型,向下转型容易在运行时期发生ClassCastException.
*
* jdk1.5以后,新的解决方案.
* 类型不确定时,可以对外提供参数.由使用者通过传递参数的形式完成类型的确定.
* 在定义时就明确参数。由使用该类的调用者来传递具体的类型。
*/
//=========================老老版===============
/*class Tool{
private Student stu;
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
}*/
//=======================jdk1.4==================
class Tool{
private Object obj;
public Tool() {
super();
}
public Tool(Object obj) {
super();
this.obj = obj;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
//=======================jdk1.5==================
//在定义时就明确参数。由使用该类的调用者来传递具体的类型。
class Util<W>{//泛型类
private W obj;
public W getObj() {
return obj;
}
public void setObj(W obj) {
this.obj = obj;
}
}
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
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="+getName()+",age="+getAge()+"]";
}
}
public class Student extends Person{
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name="+getName()+",age="+getAge()+"]";
}
}
public class Worker extends Person
{
public Worker() {
super();
}
public Worker(String name,int age) {
super(name,age);
}
@Override
public String toString() {
return "Worker [name()="+getName()+",age()="+getAge()+"]";
}
}
//GenericDemo4
class ExtendsDemo3 {
public static void main(String[] args) {
/*Tool tool=new Tool();
tool.setObj(new Student());//Object obj=new Student();已经被提升为Object
//Student stu=tool.getObj();//student类型就不能接收Object类型,要加强转.
tool.setObj(new Worker());//编译没问题,但会出现ClassCastException.
Student stu=(Student)tool.getObj();*/
Util<Student> util=new Util<Student>();
util.setObj(new Student());
//util.setObj(new Worker());//如果类型不匹配,直接编译失败。
Student stu=util.getObj();//避免了向下转型。
System.out.println(stu);
}
}
泛型方法
class GenericDemo5 {
public static void main(String[] args) {
Demo<String> d=new Demo<String>();
d.show("abc");
//d.print(6);//报错,那么如何打印int型?
Demo<Integer> d1=new Demo<Integer>();
d1.show(6);
//d1.show("abc");//这时候就会有问题。
}
}
class Demo<W>{
public void show(W w) {
System.out.println("show:"+w);
}
public void print(W w) {
System.out.println("print:"+w);
}
}
如何改进?
除了在类上定义泛型,还可以在方法上定义泛型:
class GenericDemo5 {
public static void main(String[] args) {
Demo<String> d=new Demo<String>();
d.show("abc");
//d.print(6);//报错,那么如何打印int型?
Demo<Integer> d1=new Demo<Integer>();
d1.print(6);
//d1.show("abc");//这时候就会有问题。
Demo<String> d2=new Demo<String>();
d2.show("abc");//还是只能用String。
d2.print(6);//可以写任何类型。
}
}
class Demo<W>{
public void show(W w) {//加static会失败。静态是无法访问类上定义的泛型的。因为泛型在new对象时才存在。而静态优先于new对象存在。
//如果静态方法需要定义泛型,泛型只能定义在方法上。
System.out.println("show:"+w);
}
public static <A> void staticShow(A a) {
System.out.println("static show:"+a);
}
public <Q> void print(Q w) {//泛型方法。
System.out.println("print:"+w);
}
}
泛型接口
//GenericDemo6
class ExtendsDemo3 {
public static void main(String[] args) {
SubDemo d=new SubDemo();
d.show("abc");
}
}
interface Inter<T>{//泛型接口
public void show(T t);
}
//============在类上定义泛型================
class InterImpl1<W> implements Inter<W>{
@Override
public void show(W t) {
System.out.println("show:"+t);
}
}
//====子类确定泛型===
class SubDemo extends InterImpl1<String>{
}
//=============类上确定接口的泛型===============
class InterImpl2 implements Inter<String>{
@Override
public void show(String t) {
System.out.println("show:"+t);
}
}
泛型_通配符
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.text.html.HTMLDocument.Iterator;
//GenericDemo7
class ExtendsDemo3 {
public static void main(String[] args) {
List<Student> list=new ArrayList<Student>();
list.add(new Student("abc1",21));
list.add(new Student("abc2",22));
list.add(new Student("abc3",23));
list.add(new Student("abc4",24));
printCollection(list);
Set<String> set=new HashSet<String>();
set.add("haha");
set.add("xixi");
set.add("hoho");
printCollection(set);
}
private static void printCollection(Collection<?> coll) {//在不明确具体类型的情况下,可以使用通配符来表示。
for(java.util.Iterator<?> it=coll.iterator();it.hasNext();) {
Object obj=it.next();
System.out.println(obj);
}
}
}
泛型_限定
泛型的限定:
? extends E:接收E类型或者E的子类型。泛型上限
? super E:接收E类型或者E的父类型。泛型下限
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.text.html.HTMLDocument.Iterator;
//GenericDemo7
class ExtendsDemo3 {
public static void main(String[] args) {
List<Student> list=new ArrayList<Student>();
list.add(new Student("abc1",21));
list.add(new Student("abc2",22));
list.add(new Student("abc3",23));
list.add(new Student("abc4",24));
printCollection(list);
Set<Worker> set=new HashSet<Worker>();
set.add(new Worker("haha",23));
set.add(new Worker("xixi",24));
set.add(new Worker("hoho",21));
set.add(new Worker("haha",29));
printCollection(set);
}
private static void printCollection(Collection<? extends Person> coll) {
//在不明确具体类型的情况下,可以使用通配符来表示。
for(java.util.Iterator<? extends Person> it=coll.iterator();it.hasNext();) {
Person p=it.next();
System.out.println(p.getName());
}
}
}
泛型_限定应用
显示泛型限定在api中的体现。
TreeSet的构造函数。
TreeSet(Collection<? extends E> coll);
上限?
什么时候会用到上限呢?
一般往集合存储元素时。如果集合定义了E类型,通常情况下应该存储E类型的对象。
对于E的子类型的对象E类型也可以接受。所以这时可以将泛型从E改为? Extends E
import java.util.ArrayList;
import java.util.Collection;
import java.util.TreeSet;
//GenericDemo9
class ExtendsDemo3 {
public static void main(String[] args) {
Collection<Student> coll=new ArrayList<Student>();
coll.add(new Student("abc1",21));
coll.add(new Student("abc2",22));
coll.add(new Student("abc3",23));
coll.add(new Student("abc4",24));
TreeSet<Person> ts=new TreeSet<Person>(coll);
ts.add(new Person("abc8",21));
for (java.util.Iterator<Person> it= ts.iterator(); it.hasNext();) {
Person person = it.next();
System.out.println(person.getName());
}
}
}
class MyTreeSet<E>{
MyTreeSet(){
}
MyTreeSet(Collection<? extends E> c){
}
}
下限
什么时候会用到下限呢?
当从容器中取出元素操作时,可以用E类型接收,也可以用E的父类型接收。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
//GenericDemo9
class ExtendsDemo3 {
public static void main(String[] args) {
//创建一个比较器。
Comparator<Person> comp=new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getAge()-o2.getAge();
return temp==0?o1.getName().compareTo(o2.getName()):temp;
}
};
TreeSet<Student> ts=new TreeSet<Student>(comp);
ts.add(new Student("abc1",21));
ts.add(new Student("abc2",28));
ts.add(new Student("abc3",23));
ts.add(new Student("abc4",25));
TreeSet<Worker> ts1=new TreeSet<Worker>(comp);
ts1.add(new Worker("abc11",21));
ts1.add(new Worker("abc22",27));
ts1.add(new Worker("abc33",22));
ts1.add(new Worker("abc44",29));
for (Iterator<Student> it = ts.iterator(); it.hasNext();) {
Student student = it.next();
System.out.println(student);
}
}
}
class YouTreeSet<E>{
YouTreeSet(Comparator<? super E> comparator){
}
YouTreeSet(Collection c){
}
}
集合框架_Map
特点&常见方法
Map:双列集合,一次存一对,键值对。要保证键的唯一性。
共性的功能:
1.添加
v put(key,value);
putAll(Map<k,v> map)
2.删除
void clear();
v remove(key);
3.判断
boolean contiansKey(object);
boolean contiansValue(object);
boolean isEmpty();
4.获取
V get(Value);
int size();
演示:
import java.util.HashMap;
import java.util.Map;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<Integer,String>();
methodDemo(map);
/*
* 需求:Map集合中存储学号,姓名。
*/
}
public static void methodDemo(Map<Integer,String> map) {
//存储键值对。如果键相同,会出现值覆盖。
System.out.println(map.put(3, "xiaoqiang"));//结果为null
System.out.println(map.put(3, "erhu"));//返回的是旧值。结果为xiaoqiang
map.put(7, "wangcai");
map.put(2, "daniu");
//System.out.println(map.remove(7));//wangcai,移除会改变长度
System.out.println(map.get(7));//wangcai
System.out.println(map);//{2=daniu, 3=erhu, 7=wangcai}
}
}
keySet方法
keySet方法。取出所有的键,并存储到set集合中。
map集合没有迭代器,但是可以将map集合转成set集合,再使用迭代器即可。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 取出map中所有的元素。
* map存储姓名--归属地。
*/
Map<String,String> map=new HashMap<String,String>();
map.put("xiaoqiang","Beijing");
map.put("wangcai","funiushan");
map.put("daniu","heifengzhai");
map.put("erhu","wohudong");
//keySet方法。取出所有的键,并存储到set集合中
Set<String> keySet=map.keySet();
for (Iterator<String> it = keySet.iterator(); it.hasNext();) {
String key=it.next();
String value=map.get(key);
System.out.println(key+":"+value);//结果是无序的
}
}
}
entrySet()方法
Map.Entry
其实就是一个Map接口中的内部接口。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 取出map中所有的元素。
* map存储姓名--归属地。
*/
Map<String,String> map=new HashMap<String,String>();
map.put("xiaoqiang","Beijing");
map.put("wangcai","funiushan");
map.put("daniu","heifengzhai");
map.put("erhu","wohudong");
//演示entrySet
Set<Map.Entry<String,String>> entrySet=map.entrySet();
for (Iterator<Map.Entry<String,String>> it = entrySet.iterator(); it.hasNext();) {
Map.Entry<String, String> entry = it.next();
String key=entry.getKey();
String value=entry.getValue();
System.out.println(key+":"+value);
}
}
}
对Map.Entry
的解释:
interface MyMap{
//entry就是map接口中的内部接口
public static interface MyEntry{
}
}
class MyDemo implements MyMap.MyEntry{
}
value()方法
可以重复,所以是Collection
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 取出map中所有的元素。
* map存储姓名--归属地。
*/
Map<String,String> map=new HashMap<String,String>();
map.put("xiaoqiang","Beijing");
map.put("wangcai","funiushan");
map.put("daniu","heifengzhai");
map.put("erhu","wohudong");
map.put("zhizunbao","wohudong");
//演示value()所有的值
Collection<String> values=map.values();
for (Iterator<String> it = values.iterator(); it.hasNext();) {
String value = it.next();
System.out.println(value);
}
}
}
Map_常见子类
Map
|--Hashtable:哈希表,同步,JDK1.0,不允许null键,null值。
|--HashMap:哈希表,是不同步的,允许null键,null值。
|--TreeMap:二叉树,不同步的。可以对map集合中的键进行排序。
HashSet和TreeSet是以HashMap和TreeMap为底层。
Map存储自定义对象练习
需求:
学生对象(姓名;年龄)都有对应的归属地。
key=Student value=String.
1.将员工和归属存储到HashMap集合中并取出。
同姓名同年龄视为同一个员工。
2.按照员工的年龄进行升序排序并取出。
按照员工的姓名进行升序排序并取出。
需求1:
public class Employee {
private String name;
private int age;
public Employee() {
super();
}
public Employee(String name, int age) {
super();
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 "Employee [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) 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;
}
}
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 1.将员工和归属存储到HashMap集合中并取出。同姓名同年龄视为同一个学生。
*/
Map<Employee,String> map=new HashMap<Employee,String>();
map.put(new Employee("xiaozhang",24), "北京");
map.put(new Employee("laoli",34), "上海");
map.put(new Employee("mingming",26), "南京");
map.put(new Employee("xili",30), "广州");
map.put(new Employee("laoli",34), "铁岭");
Set<Employee> keySet=map.keySet();
for(Employee employee:keySet) {
String value=map.get(employee);
System.out.println(employee.getName()+":"+employee.getAge()+"..."+value);
}
/*for (Iterator<Employee> it = keySet.iterator(); it.hasNext();) {
Employee employee = it.next();
}*/
/*for (Employee employee:map.keySet()) {
}*/
}
}
需求2:
public class Employee implements Comparable<Employee>{
private String name;
private int age;
public Employee() {
super();
}
public Employee(String name, int age) {
super();
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 "Employee [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Employee o) {
int temp=this.age-o.age;
return temp==0?this.name.compareTo(o.name):temp;
}
}
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 按照员工的年龄进行升序排序并取出。
*/
Map<Employee,String> map=new TreeMap<Employee,String>();
map.put(new Employee("xiaozhang",24), "北京");
map.put(new Employee("laoli",34), "上海");
map.put(new Employee("mingming",26), "南京");
map.put(new Employee("xili",30), "广州");
map.put(new Employee("laoli",34), "铁岭");
//entrySet
Set<Map.Entry<Employee,String>> entrySet=map.entrySet();
for(Map.Entry<Employee,String> me:entrySet) {
Employee key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+"..."+value);
}
}
}
或者
public class Employee {
private String name;
private int age;
public Employee() {
super();
}
public Employee(String name, int age) {
super();
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 "Employee [name=" + name + ", age=" + age + "]";
}
}
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
/*
* 按照员工的姓名进行升序排序并取出。
*/
//自定义比较器
Comparator<Employee> comparator=new Comparator<Employee>() {
public int compare(Employee o1, Employee o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
};
Map<Employee,String> map=new TreeMap<Employee,String>(comparator);
map.put(new Employee("xiaozhang",24), "北京");
map.put(new Employee("laoli",34), "上海");
map.put(new Employee("mingming",26), "南京");
map.put(new Employee("xili",30), "广州");
map.put(new Employee("laoli",34), "铁岭");
//entrySet
Set<Map.Entry<Employee,String>> entrySet=map.entrySet();
for(Map.Entry<Employee,String> me:entrySet) {
Employee key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+"..."+value);
}
}
}
LinkedHashMap
无序变有序
把HashMap改成LinkedHashMap即可。
Map查表法
当什么时候使用map集合呢?
当需求中出现映射关系时,应该最先想到map集合。
import java.util.HashMap;
import java.util.Map;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
String cnweek=getCnWeek(3);
System.out.println(cnweek);
String EnWeek=getEnWeek(cnweek);
System.out.println(EnWeek);
}
//根据中文星期,获取对应的英文星期。
//中文和英文相对应。可以建立表。没有有序的编号,只能通过map集合。
public static String getEnWeek(String cnWeek) {
//创建一个表。
Map<String,String> map=new HashMap<String,String>();
map.put("星期一", "Monday");
map.put("星期二", "TuesDday");
map.put("星期三", "Wednesday");
map.put("星期四", "Thursday");
map.put("星期五", "Friday");
map.put("星期六", "Saturday");
map.put("星期日", "Sunday");
return map.get(cnWeek);
}
/*
* 根据用户的指定的数据获取对应的星期。
*/
public static String getCnWeek(int num) {
if(num>7||num<=0) {
throw new NoWeekException(num+",没有对应的星期");
}
String[] cnWeeks= {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
return cnWeeks[num];
}
}
Map查表法练习
需求:
“bwbaerbctyxacecrtdcvr”
获取字符串中每一个字母出现的次数,要求结果格式:a(2)b(1)d(3)……
思路:
1.获取到字母。
2.如何获取字母次数?比较?
发现字母和次数有对应关系。而且对应关系的一方具备唯一性。
就想到了Map集合。map集合就是一张表。
3.使用查表法就可以。
先查第一个字母在表中的次数。如果次数不存在,说明是第一次出现,将该字母和1存储到表中。
以此类推。当要查的次数存在,将次数取出并自增后,再和对应的字母存储到表中,map表的特点是相同键,值覆盖。
4.查完每一个字母后,表中存储的就是每一个字母出现的次数。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
//MapDemo
class ExtendsDemo3 {
public static void main(String[] args) {
String str="bwa+ercty=xace-crtdcvr";
String char_count=getCharCount(str);
System.out.println(char_count);
}
private static String getCharCount(String str) {
//1.将字符串转成字符数组。
char[] chs=str.toCharArray();
//2.定义map集合表。
Map<Character,Integer> map=new TreeMap<Character,Integer>();
//3.遍历字符数组。获取每一个字母。
for (int i = 0; i < chs.length; i++) {
//只对字母操作。
if(!(chs[i]>='a'&&chs[i]<='z'||chs[i]>='A'&&chs[i]<='Z'))
continue;
//将遍历到的字母作为键去查表。获取值。
Integer value=map.get(chs[i]);
int count=0;//用于记录次数。
//如果次数存在,就用count记录该次数。如果次数不存在,就不记录,只对count自增变成1.
if(value!=null){
count=value;
}
count++;
map.put(chs[i], count);
//=======或者下面这个方法====
/*if(value==null) {
map.put(chs[i], 1);
}else {
value++;
map.put(chs[i],value);
}*/
}
return toString(map);
}
/*
* 将map集合中的元素转成指定格式的字符串。a(2)b(1)d(3)……
*/
private static String toString(Map<Character, Integer> map) {
//1.数据多,无论类型是什么,最终都要变成字符串,所以可以使用StringBuilder
StringBuilder sb=new StringBuilder();
//2.遍历集合map。
Set<Character> keySet=map.keySet();
for (Iterator<Character> it = keySet.iterator(); it.hasNext();) {
Character key = it.next();
Integer value=map.get(key);
//将键值存储到sb中
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
Collections方法
集合框架的工具类:
Collections:定义的都是操作Collection的静态方法。
排序&逆序
1.对list排序
sort(list);
排序方法上泛型的具体解释:
class Student implements Comparable<Person>
{
public int compareTo(Person p) {
}
}
public static<T extends Comparable<? super T> > void sort(List<T> list)//加泛型 这里的Comparable是接口
{
}
public static void sort(List<Student> list)
{
stu1.compareTo(stu2);
}
2.逆序
reverseOrder();
具体方法演示:
import java.util.Comparator;
public class ComparatorByLength implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
int temp=o1.length()-o2.length();
return temp==0? o1.compareTo(o2):temp;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
//Collecions
class ExtendsDemo3 {
public static void main(String[] args) {
methodDemo1();
}
private static void methodDemo1() {
List<String> list=new ArrayList<String>();
list.add("abcd");
list.add("z");
list.add("hehe");
list.add("nba");
System.out.println(list);
//对list排序。自然排序。使用的是元素的comparaTo方法。
Collections.sort(list);
System.out.println(list);
//想按照长度排序
Collections.sort(list,new ComparatorByLength());
System.out.println(list);
//强行逆转比较器的顺序,Collections.reverseOrder();
Collections.sort(list,Collections.reverseOrder(new ComparatorByLength()));
System.out.println(list);
}
}
最值&同步方法
3.最值
.max min
具体演示:
import java.util.Comparator;
public class ComparatorByLength implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
int temp=o1.length()-o2.length();
return temp==0? o1.compareTo(o2):temp;
}
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.text.html.HTMLDocument.Iterator;
//Collecions
class ExtendsDemo3 {
public static void main(String[] args) {
Collection<String> coll=new ArrayList<String>();
coll.add("abcd");
coll.add("aa");
coll.add("zzzz");
coll.add("nba");
String max=getMax(coll);
String max1=Collections.max(coll);//和上一行的功能其实是一样的
String max2=Collections.max(coll,new ComparatorByLength());//找最长的
System.out.println(max);
System.out.println(max1);
System.out.println(max2);
}
/*
* 模拟一个获取集合最大值的功能。
*/
public static<T extends Object&Comparable<? super T>> T getMax(Collection<? extends T> coll) {//传进来的是T 方法是T 返回是T
//public static String getMax(Collection<String> coll) {//传进来的是T 方法是T 返回是T
//Collection只支持迭代
//java.util.Iterator<String> it=coll.iterator();
java.util.Iterator<? extends T> it= coll.iterator();//迭代器哪里来的,就要和哪里一致。
//1.定义变量记录容器中其中一个。
//String max=it.next();//第一个
T max=it.next();
//2.遍历容器所有的元素。
while(it.hasNext()) {
//String temp=it.next();//第二个
T temp=it.next();
//3.在遍历过程中进行比较,只要比变量中的值哒。用变量记录下来。
if(temp.compareTo(max)>0) {
max=temp;
}
}
return max;
}
}
练习:
模拟一个Collection min(Collection coll,Comparator comp)
4.二分查找
5.将非同步集合转成同步集合。
同步重点
ArrayList和List有什么区别:
List安全 ArrayList不安全,但是ArrayList快。
多线程可以用集合框架工具类Collections中的同步集合方法,将非同步转成同步
(JDK1.2没有不同步)
Collections中有一个可以将非同步集合转成同步集合的方法。
sysnchronized集合(非同步集合)
Arrays方法
用来操作数组的工具类,方法都是静态的。
import java.util.Arrays;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
Integer[] arr=new Integer[3];
swap(arr,1,2);
String[] arr1=new String[3];
swap(arr1,1,2);
int[] arr2= {45,23,78,11,99};
System.out.println(Arrays.toString(arr2));
}
/*public static void swap(int[] arr,int x,int y) {
int temp=arr[x];
arr[x]=arr[y];
arr[y]=temp;
}*/
public static<T> void swap(T[] arr,int x,int y) {
T temp=arr[x];
arr[x]=arr[y];
arr[y]=temp;
}
}
数组转成集合
Arrays–>Collections
Arrays.asList();
数组转成集合,就是为了使用集合的方法操作数组中的元素。
**注意:不能使用集合的增删方法。不能改变长度。**因为数组长度不可变。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
String[] strs= {"abc","haha","nba","zz"};
boolean b=myContains(strs,"nba");
System.out.println(b);
//发现集合中本身有这个方法contains
//将数组转成集合。即可。
List<String> list=Arrays.asList(strs);
list.add("qq");// java.lang.UnsupportedOperationException
//注意:不能使用集合的增删方法。
System.out.println(list.contains("nba"));
}
public static boolean myContains(String[] arr,String key) {
for (int i = 0; i < arr.length; i++) {
String str = arr[i];
if(str.equals(key))
return true;
}
return false;
}
}
如果数组中都是引用数据类型,转成集合时,数组元素直接作为集合元素。
如果数组中的都是基本数据类型,会将数组对象作为集合中的元素。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
int[] arr= {45,23,78,11,99};
List list=Arrays.asList(arr);
System.out.println(list.size());//结果为1
System.out.println(list.get(0));//结果为[I@15db9742
}
}
如何使用泛型
int<>也是元素类型
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
int[] arr= {45,23,78,11,99};
List<int[]> list=Arrays.asList(arr);//写元素类型
System.out.println(list.size());//
System.out.println(list.get(0));//
}
}
把int改为Integer:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
Integer[] arr= {45,23,78,11,99};
List list=Arrays.asList(arr);//写元素类型
System.out.println(list.size());//5
System.out.println(list.get(0));//45
}
}
集合转成数组
Collections–>Arrays
Collection.toArray(T[] a);
传入的数组长度如果小于集合长度,方法中会创建一个新的长度和集合长度一致的数组。
如果传入的数组长度大于等于集合长度,会使用传入的数组,所以建议长度定义为集合的size();
为什么要把集合转成数组?
就是为了限定对元素的操作,比如增删。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//Arrays
class ExtendsDemo3 {
public static void main(String[] args) {
//集合转成数组
List<String> list=new ArrayList<String>();
list.add("abc");
list.add("haha");
String[] arr=list.toArray(new String[3]);
System.out.println(Arrays.toString(arr));//把数组转成字符串,结果为[abc, haha, null]
}
}
可变参数
JDK1.5
可变参数需要注意,只能定义在参数列表的最后。
以前怎么写?
//ParamDemo
class ExtendsDemo3 {
public static void main(String[] args) {
int sum = add(4, 5);
int sum1 = add1(4, 5, 6);
int[] arr= {34,1,5,7};
int sum2 = add2(arr);
}
private static int add(int i, int j) {
return i + j;
}
private static int add1(int i, int j, int k) {
return i + j + k;
}
public static int add2(int[] arr) {
int sum=0;
for (int i = 0; i < arr.length; i++) {
sum=arr[i];
}
return sum;
}
}
现在可以这么写:
//ParamDemo
class ExtendsDemo3 {
public static void main(String[] args) {
int sum=add(43,4,5,6,7);
int sum1=add(43,4,5,6,7,8,9);
}
public static int add(int... arr) {
int sum=0;
for (int i = 0; i < arr.length; i++) {
sum=arr[i];
}
return sum;
}
}
静态导入
加static
import java.util.*;
import static java.util.Collections.*;
import static java.lang.System.*;
//StaticImportDemo
class ExtendsDemo3 {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("a");
list.add("c");
//Collections.sort(list);
//Collections.max(list);
sort(list);//调用的都是静态方法
System.out.println(max(list));
out.print("hello");
}
}