Java学习笔记之集合框架
1、集合类的特点:
集合只用于存储对象,集合长度是可变的,集合可用于存储不同长度的对象。
2、集合和数组都是容器,他们有什么不同?
集合只用于存储对象,其长度是可变的;数组也可以存储对象,用于存储基
数据类型,但其长度不可变
3、Collection由两个常见的子接口List(元素有序,元素可以重复,该集合体有索引)和Set(元素无序,元素不可以重复)组成,List常见的子类有ArrayList, LinkedList,Vector;Set常见的子类有HashSet和TreeSet。
出现不同容器的原因是:容器的数据结构不同,即对数据的存储方式不同
4、迭代器 Iterator 一个接口,它对外提供了一个方法iterator();来取出集合中的对象。比喻:电玩城中投游戏币夹子夹玩具的例子,盛玩具和夹子的大容器就相当于集合,夹子就相当于迭代器就是取出方式,定义在容器内部,是内部类,可以直接访问集合内容的元素,玩具就相当于集合中的元素,操纵杆就相当于iterator()方法,调用iterator()方法,取出集合中的元素。
5、Iterator接口有三个方法,hasNext();如果集合中有元素则返回true,否则返回false。next()方法是取出集合中的一个元素,remove()方法移除迭代器返回的最后一个元素。
代码:ArrayList a1=new ArrayList();
//对集合a1添加元素
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");
//获取迭代器,用于取出集合中的元素
Iterator it=a1.iterator();//查阅api可知iterator的返回类型是Iterator
while(it.hasNext())
{
System.out.println(it.next());
}
6. List:特有方法,只要可以在操作角标的方法都是该体系特有的方法,这里只列举它特有的方法
*增:add(index,element); addAll(index,Collection);
*删:remove(index);
*改:set(index,element)
*查:get(index); subList(from,to); listIterator();
代码://获取全部元素,方法一
for(int i=0;i<a1.size();i++)
{
System.out.println(i+"角标处的元素:"+a1.get(i));
}
//获取全部元素,通过迭代器
Iterator lit=a1.iterator();
while(lit.hasNext())
{
System.out.println(lit.next());
}
7、List集合特有的迭代器,ListIterator是Iterator的子类
在迭代时,不可以通过集合对象的方法操作集合中的元素,会发生异常。所以在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,删除,取出操作。如果想要添加,修改等,就需要使用其子接口ListIterator,该接口只能通过List集合的listIterator方法获取。
代码://在迭代过程中准备添加和修改
ListIterator li=a1.listIterator();
while(li.hasNext())
{
Object obj=li.next();
//如果遇到java02就在它后面添加java05
if(obj.equals("java02"))
li.add("java05");
}
System.out.println(a1);
//可以逆向遍历取出,执行到上一行代码,,指针已经落在最后一个元素的后边
while(li.hasPrevious())
{
System.out.println(li.previous());
}
8、List常见的子类:ArryList:底层的数据结构是数组结构,查询速度快,增删较慢;LinkedList:其数据结构是链表形式,查询较慢,增删速度快;Vector:底层是数组数据结构,线程同步。被ArrayList替代。
9、*枚举Enumeration是Vector特有的取出方式,枚举和迭代器其实是一样的,枚举是早期的,因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
代码:Vector v=new Vector();
v.add("day01");
v.add("day02");
v.add("day03");
v.add("day04");
//Enumeration是一个接口,称为枚举,与迭代器类似是Vector特有的取出方式
//它有两种方法:hasMoreElements()和nextElements(),相当于迭代器的hasNext和next()
Enumeration en=v.elements();
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
10、LinkedList特有的方法:
addFirst(); 将元素插入列表头部
addLast(); 将元素插入列表尾部
getFirst(); getLast(); 获取元素但不删除元素,如果集合中没有元素,会出现NoSuchElementException
removeFirst(); removeLast(); 获取元素,但元素被删除,如果集合中没有元素,则会抛出NoSuchElementException
在JDK1.6出现了以下替代方法。
offerFirst(); 将元素插入列表头部
offerLast(); 将元素插入列表尾部
peekFirst(); peekLast();获取元素但不删除元素,如果集合中没有元素,会返回NULL
pollFirst(); pollLast();获取元素但是删除元素,如果集合中没有元素,会返回NULL
11、List集合判断元素是否相同,依据的是元素的equals方法。
调用contains();方法和remove();方法时都在底层自动调用了equals();方法
代码1:例如删除集合中重复的元素,该集合中的元素是字符串
public static ArrayList singleElement(ArrayList a)
{
ArrayList al=new ArrayList();
Iterator it=a.iterator();
//注意在迭代时循环中next调用一次,就要hasNext判断一次
while(it.hasNext())
{
Object obj=it.next();
if(!al.contains(obj))
al.add(obj);
}
return al;
}
代码2:同样删除集合中重复的元素,但该元素是对象;假设是人对象,如果人的姓名和年龄相同则代表元素重复,删除一个。这需要在定义Person类时,重写equals方法,还有打印时注意强制类型转换。
class Person{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
//重写equals方法
public boolean equals(Object obj)
{
//(obj instanceof Person)表示obj这个对象是否是Person类的实例,是返回true,否则返回false
if(!(obj instanceof Person))
return false;
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
//判断集合中的元素是否相同的方法
public static ArrayList isSingleElement(ArrayList al)
{
ArrayList a2=new ArrayList();
Iterator it=al.iterator();
while(it.hasNext())
{
Object obj=it.next();
if(!a2.contains(obj))
a2.add(obj);
}
return a2;
}
//输出集合中的元素,其元素为对象的方法
public static void getSingleElement(ArrayList a)
{
Iterator it= a.iterator();
while(it.hasNext())
{
Object obj=it.next(); //it.next()返回的是Object类型
Person p=(Person)obj;//要使用Person类中的方法必须做强制转换
System.out.printly(p.getName()+":"+p.getAge());
}
}
public static void main(String[] args) {
ArrayList al=new ArrayList();
//像容器中添加人对象
al.add(new Person("liyi",20));
al.add(new Person("lier",20));
al.add(new Person("lisan",24));
al.add(new Person("liyi",20));
al.add(new Person("lier",20));
al=isSingleElement(al);
getSingleElement(al);
}
12、Set:Set集合的功能和Collection的功能一样,但Set集合的元素无序的,不可重复的。其实现的子类常见的有HashSet和TreeSet,前者底层的数据结构是哈希表,线程非同步。后者底层的数据结构是二叉树,二叉树默认从小到大取。
其中哈希表的存储的元素的位置不是按存储的顺序存入的,而是按照存入元素哈希值存储的,但是如果两个对象的地址值相同,则会再判断两个对象是否是同一对象,如果是则不存入哈希表,如果位置一样,但不是同一对象则会存入哈希表,两个对象在同一地址值之上顺延。
13、HashSet是如何保证元素唯一性的?是通过元素的两个方法,hashCode和equals来完成。这两个方法都是在底层内部调用的,当元素存入哈希表时首先会调用hashCode方法来计算元素的哈希值,如果哈希值不同则直接存入哈希表,不再调用equals方法,如果哈希值相同,则调用equals方法来判断这两个元素是否相同,如果不相同则,则两个元素在同一地址上顺延,如果相同则不存入哈希表。
值得注意的是,对于判断元素是否存在,以及删除等操作,HashSet集合首先依赖的是hashCode方法,其次依赖的是equals方法。而ArrayList只依赖equals方法。
一般如果存入的是自定义的对象,则一般要复写该类的hashCode和equals方法来提高效率。
代码:class Person{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//复写hashCode方法
public int hashCode()
{
//
System.out.println(this.name+"--"+this.age);
return name.hashCode()+age*3;//这个年龄乘以3是为了保证不同的元素有不同的哈希值
}
//复写equals方法
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
System.out.println(this.name+"..equals.."+this.age);
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
}
public class HashSetTest {
public static void printHashSet(HashSet hs)
{
Iterator it=hs.iterator();
while(it.hasNext())
{
Object obj=it.next();
Person p=(Person)obj;
System.out.println(p.getName()+":"+p.getAge());
}
}
public static void main(String[] args) {
HashSet hs=new HashSet();
hs.add(new Person("dashan",23));
hs.add(new Person("dashai",27));
hs.add(new Person("xiaotian",17));
hs.add(new Person("dashai",27));
hs.add(new Person("dashan",20));
//判断元素是否存在
System.out.println("dashan:"+hs.contains(new Person("dashan",23)));
//删除元素
hs.remove(new Person("xiaotian",17));
printHashSet(hs);
}
14、TreeSet:可以对set集合中的元素进行排序
值得注意的是,排序时,当主要条件相同时,一定要判断一下下次要条件。
当像TreeSet中存入自定义的对象时,自定义该对象的类时需要实现接口Comparable,并重写compareTo方法
如果想要按照存储的顺序取出,则重写的compareTo方法中只写return 1;即可,都存在了二叉树的右边,一次取出
//如果想按照存储的逆序取出,则compareTo方法中写return -1;即可,元素都排在二叉树的左边,从小到大,从下到上取出
代码:class Student implements Comparable{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s=(Student)obj;
if(this.age>s.age)
return 1;
//当年龄相同,姓名不相同时,如果只判断年龄,另一个存入不进去,所以此时也应该判断一下另一个条件,方法一:
/*if(this.age==s.age&&this.name.equals(s.name))
return 0;*/
//判断次要条件 方法二:
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
if(this.age<s.age)
return -1;
return age;
}
}
public class TreeSetDemo1 {
public static void main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Student("aa1",19));
ts.add(new Student("aa2",23));
ts.add(new Student("aa3",20));
ts.add(new Student("aa4",23));
Iterator it=ts.iterator();
while(it.hasNext())
{
Object obj=it.next();
Student stu=(Student)obj;
System.out.println(stu.getName()+":"+stu.getAge());
}
15、TreeSet:底层数据结构是二叉树。它保证唯一性的依据是:compareTo方法return0;
TreeSet排序的第一种方法:让元素自身具备比较性。元素需要实现Comparable接口,覆盖comparaTo方法,这种方式也成为元素的自然顺序,或者叫默认顺序。
第二种排序方式:当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身具备比较性。定义了比较器,将比较器对象作为参数传递给TreeSet的集合参数。
当两种排序到存在时以比较器为主
import java.util.*;
public class TreeSetTest {
/**
* 按照字符串长度排序
* @param args
*/
public static void main(String[] args) {
TreeSet ts=new TreeSet(new StrLenCompator());
ts.add("ahn");
ts.add("ybbf");
ts.add("cjiiuh");
ts.add("gjyia");
Iterator it=ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class StrLenCompator implements Comparator
{
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
//为了防止相同长度不同内容的字符串被删除
if(num==0)
return s1.compareTo(s2);
return num;
}
}
16、泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一个安全机制。泛型的好处:
第一,将运行时期出现的ClassCastException,转移到了编译时期,方便与程序员解决问题,让运行事情问题减少,安全。
第二,避免了强制转换的麻烦
泛型格式:通过< >来定义要操作的引用数据类型。在使用Java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到< >就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到< >中即可。
17、什么时候定义泛型类。
当类中要操作的引用数据类型不确定时(注意必须是引用数据类型,不能传递基本数据类型),早期定义Object来完成扩展,但是需要强制类型转换。现在使用泛型来扩展免去了强转的麻烦。
泛型中的术语
1,ArrayList<E>整个成为泛型类型
2,ArrayList<E>中的E成为类型变量或类型参数
3,整个ArrayList<Integer>成为参数化的类型
4,ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
5,ArrayList<Integer>中的<>称为typeof,整体念做ArrayList typeof Integer。是什么类型的ArrayList。
6,ArrayList成为原始类型
7,参数化类型与原始化类型的兼容性。
参数化类型可以引用一个原始类型的对象,编译报告警告,例如
Collection<String> c=new Vector();
原始类型可以引用一个参数化类型的对象,编译报告警告,例如
Collection c=new Vector<String>();//如果原来的方法接受一个集合参数,新的类型也要能传进去。
8,参数化类型不考虑类型参数的继承关系
Vector<String> v=new Vector<Object>();//错误
Vector<Object> v=new Vector<String>();//错误
9,在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:
Vector<Integer> vectorList[]=new Vector<Integer>[10];
18、泛型类定义的泛型在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同的方法可以操作不同的类型,而且类型还不确定。那么可以将泛型定义在方法上。
(特殊之处:静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定,可以将泛型定义在静态方法上。静态泛型。
格式:public static <W> void f(W w)
{
System.out.println(w);
})
比如:class Demo{
public <T> void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
}
Class A
{public static void main(String[] args) {
Demo d=new Demo();
d.show("come on");
d.show(new Integer(12));
d.print(1.3);
d.print("jiayou");}}
19、泛型可以定义在接口上。
Interface Inter<T>
{ public void show(T t);}
Class InteIm implements Inter<String>
{public void show(String s)
{System.out.println(“show:”+t);}
}
20、泛型的限定:?表示通配符,也可以理解为占位符
? extends E :表示可以接收E类型或者E的子类型。上限
? super E :可以接收E类型或者E的父类型。 下限
要求:可以打印任意类型的集合,代码示例:
/**
* @param args
* 通配符:?可以引用其他各种参数化的类型,?同配股定义的变量主要用作引用,可以
* 调用与参数化无关的方法,不能调用与参数化有关的方法。
*不能把通配符?给一个具体的类型,如果某个方法的返回类型是带?的,
*不能将它赋值给一个具体的类型
*/
//要求:打印任意类型的集合
public static void printCollection(Collection<?> c){
//c.add("string");错误,因为?表示不确定什么类型,而add方法的参数是有固定类型的
c.size();//没错,因为size方法没有参数,每个类型都有size方法
for(Object obj:c){
System.out.println(obj);
}
c=new HashSet<Date>();//这是可以的
}
代码:public class GenericDemo5 {
public static void main(String[] args) {
ArrayList<Person> al=new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
ArrayList<Stu> al1=new ArrayList<Stu>();
al1.add(new Stu("bnoe1"));
al1.add(new Stu("bnoe2"));
al1.add(new Stu("bnoe3"));
printCol(al);
printCol(al1);
}
//此函数可以打印Person及Person的子类
public static void printCol(ArrayList<? extends Person> a)
{
Iterator<? extends Person> it=a.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
class Person{
private String name;
Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
}
class Stu extends Person{
Stu(String name)
{
super(name);
}
}
20、Map集合的特Map<K,V>:该集合存储键值对。一对一往里存,而且保证键的唯一性。基本方法有:
1,添加:V put(K key,V value);将指定的值与此映射中的指定键相关联,put方法会返回这个键对应的原来的值
void putAll(Map<? extends K,? extends V> m) 将指定映射中所有映射关系复制到此映射中
2,删除: void clear();清空集合 V remove(Object Key);将含有此键的映射关系移除
3,判断:containsKey(Object key):是否包含指定键 containsValue(Object value):是否包含指定值 。isEmpty();如果此映射未包含键—值映射关系。则返回true
4,获取:V get(Object key)返回此映射中指定键的值 int size();返回此集合中的映射关系数 values():返回此映射所包含的值的Collection视图。 entrySet() keySet()
代码:public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
//像集合中添加元素
map.put("01","xc1");
map.put("02","zdf");
map.put("03","lulu");
//打印该集合
System.out.println(map);
//判断
System.out.println(map.containsKey("01"));
System.out.println(map.containsValue("lulu"));
//删除元素
System.out.println("remove:"+map.remove("02"));
//获取
System.out.println("get:"+map.get("03"));
//获取map集合中所有的值
Collection col=map.values();
System.out.println(col);
//添加元素时,如果出现添加时相同的键,那么后添加的值会覆盖原有的值
//并且put方法返回被覆盖的值
System.out.println("put1:"+map.put("02","ppq1" ));//输出null
System.out.println("put1:"+map.put("02","ppq2" ));//输出ppq1
System.out.println(map);
}
21、 * Map集合的两种取出方式:keySet和entrySet
* keySet:将map中所有的键存入到Set集合中。因为Set具备迭代器
* 所以可以通过迭代方式取出所有的键,再根据get方法获取每一个键对应的值
* Map集合的第一种取出原理:将map集合转成set集合,再通过迭代器取出
* Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到set集合中
* 而这个关系的数据类型就是:Map.Entry 关系对象Map.Entry获取到后就可以通过它 的getKey()和getValue()方法来获取关系中的键和值
Map.Entry<K,V>是一个接口,具有自己的方法有点像迭代器
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
map.put("11", "as1");
map.put("12", "as2");
map.put("13", "as3");
map.put("14", "as4");
//通过keySet方法将所有的键取出,存放到Set集合中
Set<String> keySet=map.keySet();
//通过迭代器以及get方法将所有的键及其对应的值取出
Iterator<String> it=keySet.iterator();
while(it.hasNext())
{
String key=it.next();
String value=map.get(key);
System.out.println("key:"+key+",value:"+value);
}
//通过entrySet方法取出Map集合中的映射关系,存入到Set集合中
Map<Integer,String> map1=new HashMap<Integer,String>();
map1.put(1, "q1");
map1.put(2, "q2");
map1.put(3, "q3");
Set<Map.Entry<Integer, String>> entrySet=map1.entrySet();
//遍历结果时,可以用for循环
for(Map.Entry<String,Integer> me: entrySet){
System.out.println("key:"+me.getKey()+" value:"+me.getValue());
}
//也可以用Iteraotr迭代器
Iterator<Map.Entry<Integer, String>> it1=entrySet.iterator();
while(it1.hasNext())
{
Map.Entry<Integer, String> me=it1.next();
Integer key1=me.getKey();
String value1=me.getValue();
System.out.println("key1:"+key1+"--value1:"+value1);
}
}
}
22、/*练习:给一个字符串比如“fsdsjdjdaer”获取该字符串中的字母出现的次数
并且打印结果形式为:a(1)b(3)...
注意:字母和次数之间存在映射关系,应首先想到map集合,因为map集合中存放
的就是映射关系。
思路:
1,首先将字符串转换成字符数组。因为要对每一个字母进行操作
2,定义一个map集合,因为打印结果有顺序所以应使用TreeMap
3,将每一个字母作为键去查map集合。如果返回null,则证明该集合中没有该
字母的映射关系,则向集合中存入该字母和1。如果返回不是null,则证明该集合
中已存在此字母及其对应的次数,那么就获取该字母对应的次数进行自增,然后将
该字母和自增后的次数重新存入到map集合中*/
public class MapTest2 {
public static void main(String[] args) {
String s=getCharNum("bdkjee,aehadad");
System.out.println(s);
}
public static String getCharNum(String str)
{
//首先将字符串转换成字符数组
char[] ch=str.toCharArray();
//定义一个map集合,注意泛型类型的传入,不能用char等基本数据类型
TreeMap<Character,Integer> tm=new TreeMap<Character,Integer>();
//遍历字符数组,判断方法一
for(int i=0;i<ch.length;i++)
{
//如果该字符串中还有一些非字母类的字符比如逗号句号等,而我们在判断打印时不需要则
if(!(ch[i]>='a'&&ch[i]<='z'||ch[i]>='A'&&ch[i]<='Z'))
continue;
Integer value=tm.get(ch[i]);
if(value==null)
{
tm.put(ch[i], 1);
}
else
{
value=value+1;
tm.put(ch[i], value);
}
}
/*int count=0;
//遍历字符数组,判断 方法二 优化方法一
for(int i=0;i<ch.length;i++)
{
if((ch[i]>='a'&&ch[i]<='z'||ch[i]>='A'&&ch[i]<='Z'))
{
Integer value=tm.get(ch[i]);
//如果value不为空,则获取其值自增,如果value为空则不获取它的值,直接自增存入
if(value!=null)
count=value;
count=count+1;
tm.put(ch[i],count);
//注意需要将count清零
count=0;
}
}*/
//这样输出不符合题目要求的格式,所以需要使用map集合的那两种特殊的取出方式中的一种
System.out.println(tm);
//StringBuilder 字符串缓冲区的append方法可以以上述形式输出
StringBuilder sb=new StringBuilder();
Set<Map.Entry<Character,Integer>> entrySet=tm.entrySet();
Iterator<Map.Entry<Character,Integer>>it=entrySet.iterator();
while(it.hasNext())
{
Map.Entry<Character,Integer> me=it.next();
Character key=me.getKey();
Integer val=me.getValue();
sb.append(key+"("+val+")");
}
//因为sb是StringBulider类型所以需要将其转换成字符串用toString()方法
return sb.toString();
//return null;
}
}
23、//Map扩展:一对多方法一 将下列映射关系存储,
"yureban" "01" "zs"
"yureban" "02" "lisi"
"jiuyeban" "01" "wangwu"
"jiuyeban" "02" "zhaoliu"
public class MapDemo3 {
public static void main(String[] args) {
HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();
HashMap<String,String> yure=new HashMap<String,String>();
HashMap<String,String> jiuye=new HashMap<String,String>();
czbk.put("yureban", yure);
czbk.put("jiuyeban",jiuye);
yure.put("01", "zs");
yure.put("02", "lisi");
jiuye.put("01","wangwu");
jiuye.put("02","zhaoliu");
//遍历czbk集合,获取所有的教室
Iterator<String> it=czbk.keySet().iterator();
while(it.hasNext())
{
String roomName=it.next();
HashMap<String,String> room=czbk.get(roomName);
System.out.println(roomName);
getStudentInfo(room);
}
//getStudentInfo(yure);
//getStudentInfo(jiuye);
}
//打印教室里的所有学生
public static void getStudentInfo(HashMap<String,String> roomMap)
{
Set<String> keySet=roomMap.keySet();
Iterator<String> it=keySet.iterator();
while(it.hasNext())
{
String id=it.next();
String name=roomMap.get(id);
System.out.println(id+":"+name);
}
}
}
24、 Map扩展一对多,一个学校有很多教室,一个教室有很多学生。教室有教室名,学生有学号和姓名.上面的代码形式不常用,通常将学生封装成对象
class Student1{
private String id;
private String name;
public Student1(String id,String name)
{
this.id=id;
this.name=name;
}
public String toString()
{
return id+"--"+name;
}
}
public class MapDemo3kuozhan {
public static void main(String[] args) {
HashMap<String,List<Student1>> hm=new HashMap<String,List<Student1>>();
List<Student1> yure=new ArrayList<Student1>();
List<Student1> jiuye=new ArrayList<Student1>();
yure.add(new Student1("01","zx"));
yure.add(new Student1("02","sx"));
jiuye.add(new Student1("01","lu"));
jiuye.add(new Student1("02","mei"));
hm.put("yureban", yure);
hm.put("jiuyeban", jiuye);
Set<String> keySet=hm.keySet();
Iterator<String> it1=keySet.iterator();
while(it1.hasNext())
{
String roomName=it1.next();
List<Student1> room=hm.get(roomName);
getStuInfo(room);
}
}
//取出教室中的学生,遍历List集合
public static void getStuInfo(List<Student1> list)
{
Iterator<Student1> it=list.iterator();
while(it.hasNext())
{
Student1 s=it.next();
System.out.println(s);
}
}
}
25、Collections工具类,该类中所有方法都是静态的,用类名直接调用。其中常用方法,sort()方法排序,max()方法求最大值,binarySearch()方法二分查找,fill()方法替换掉集合中的所有元素,repalaceAll()用一个新值替换集合中的旧值,reverse()反转,shuffle()把集合中的元素按照随机的方式进行排放。等
代码1:public static void sortDemo()
{
List<String> list=new ArrayList<String>();
list.add("abxd");
list.add("bss");
list.add("e");
list.add("oo");
list.add("bss");
//未排序之前
System.out.println(list);
//调用Collections的sort方法进行排序自然排序,不能给Set集合排序
Collections.sort(list);
System.out.println(list);
//按字符串长度排序则传入自定义比较器的对象
Collections.sort(list,new StrLenComparator());
System.out.println(list);
}
//如果想要对字符串按长度排序,则自定义比较器
class StrLenComparator implements Comparator<String>{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
return 1;
if(s1.length()<s2.length())
return -1;
return s1.compareTo(s2);
}
}
代码2:public static void maxDemo()
{
List<String> list=new ArrayList<String>();
list.add("abxd");
list.add("bss");
list.add("e");
list.add("oo");
list.add("bss");
Collections.sort(list);
//在自然排序的情况下获取最大值
String max=Collections.max(list); //输出oo
System.out.println(max);
//在比较器规定的情况下获取最大值
String max1=Collections.max(list,new StrLenComparator()); //输出abxd
System.out.println(max1);
}
代码3:public static void binarySearchDemo()
{
List<String> list=new ArrayList<String>();
list.add("abxd");
list.add("bss");
list.add("e");
list.add("oo");
list.add("bss");
Collections.sort(list,new StrLenComparator());
System.out.println(list);
int index=Collections.binarySearch(list,"e");//返回角标
System.out.println("index="+index);
int index1=halfSearch2(list,"bss",new StrLenComparator());
System.out.println("index1="+index1);
}
//二分查找的原理binarySearch(List<? extends Comparable<? super T>> list, T key
public static int halfSearch(List<String>list,String key)
{
int max,min,mid;
max=list.size()-1;
min=0;
//只要min下雨max就可以折半
while(min<=max)
{
mid=(max+min)>>1; //相当于除以2
String str=list.get(mid);
int num=str.compareTo(key);
if(num>0) //证明key在中间值左边,改变max值
max=mid-1;
else if(num<0)
min=mid+1;
else return mid;
}
return -min-1; //min为插入点
}
//二分查找原理二,当比较对象不具备比较性时需要传入比较器
//binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
public static int halfSearch2(List<String>list,String key,Comparator<String> cmp)
{
int max,min,mid;
max=list.size()-1;
min=0;
//只要min下雨max就可以折半
while(min<=max)
{
mid=(max+min)>>1; //相当于除以2
String str=list.get(mid);
int num=cmp.compare(str,key);
if(num>0) //证明key在中间值左边,改变max值
max=mid-1;
else if(num<0)
min=mid+1;
else return mid;
}
return -min-1; //min为插入点
}
代码4:public static void fillDemo()
{
ArrayList<String> al=new ArrayList<String>();
al.add("xiaxue");
al.add("zhongmou");
al.add("zijia");
System.out.println(al);//打印结果:[xiaxue, zhongmou, zijia]
//替换
Collections.replaceAll(al,"zhongmou","haha");
System.out.println(al);//打印结果:[xiaxue, haha, zijia]
//替换所有
Collections.fill(al, "erhuo");
System.out.println(al);//打印结果:[erhuo, erhuo, erhuo]
}
public static void reverseDemo()
{
ArrayList<String> al=new ArrayList<String>();
al.add("xiaxue");
al.add("zhongmou");
al.add("zijia");
System.out.println(al);//打印结果:[xiaxue, zhongmou, zijia]
//反转
Collections.reverse(al);
System.out.println(al);//打印结果:[zijia, zhongmou, xiaxue]
}
26、Collections工具类中的另外两个重要方法:
Collections工具类中的reverseOrder()方法:返回一个比较器,它强行反转实现 Comparable 接口那些对象 collection 上的自然顺序。
reverseOrder(Comparator<T> cmp) 方法:返回一个比较器,它强行反转指定比较器的顺序
代码:public class CollectionsDemo2 {
public static void main(String[] args) {
orderDemo();
}
public static void orderDemo()
{
TreeSet<String> ts=new TreeSet<String>();
ts.add("qq");
ts.add("kfdj");
ts.add("jfrod");
ts.add("djd");
System.out.println(ts);//打印结果是有顺序的,按照自然排序 [djd, jfrod, kfdj, qq]
//要想让它按照自然排序的逆序输出,以前的做法是自定义比较器
TreeSet<String> ts1=new TreeSet<String>(new StrComparator());
ts1.add("qq");
ts1.add("kfdj");
ts1.add("jfrod");
ts1.add("djd");
System.out.println(ts1); //打印结果自然排序的逆序 [qq, kfdj, jfrod, djd]
//但是这样需要重新定义比较器,比较麻烦,应首先想到Collections的reverseOrder()方法,该方法返回一个强行逆转的比较器
TreeSet<String> ts2=new TreeSet<String> (Collections.reverseOrder());
ts2.add("qq");
ts2.add("kfdj");
ts2.add("jfrod");
ts2.add("djd");
System.out.println(ts2); //打印结果同上[qq, kfdj, jfrod, djd]
//按照长度排序,是由短到长的
TreeSet<String> ts3=new TreeSet<String>(new StrLengthComparator());
ts3.add("qq");
ts3.add("kfdj");
ts3.add("jfrod");
ts3.add("djd");
System.out.println(ts3);//打印结果[qq, djd, kfdj, jfrod]
//如果想要让它按照从长到短排序,而不改写比较器的代码,使用Collections的reverseOrder(Comparator<T> cmp)方法
TreeSet<String> ts4=new TreeSet<String>(Collections.reverseOrder(new StrLengthComparator()));
ts4.add("qq");
ts4.add("kfdj");
ts4.add("jfrod");
ts4.add("djd");
System.out.println(ts4);//打印结果[jfrod, kfdj, djd, qq]
}
class StrComparator implements Comparator<String>{
public int compare(String s1,String s2)
{
return s2.compareTo(s1);
}
}
//按照长度由短到长排序,自定义比较器
class StrLengthComparator implements Comparator<String>{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
return 1;
else if(s1.length()<s2.length())
return -1;
return s1.compareTo(s2);
}
}
27、Arrays:用于操作数组的工具类。里面都是静态方法 比如排序和搜索等各种方法
* 一个比较特殊的方法:将数组转换成List集合。asList(T... a) 返回一个受指定数组支持的固定大小的列表
/*把数组变成集合的好处:可以使用集合的思想和方法来操作数组中的元素
注意:将数组变成集合不可以使用集合的增删操作,因为数组的长度是固定的
但是可以使用比如:contains(),get(),indexOf()等
*/
String[] arr1=new String[]{"ab","dfs","eef"};
List<String> list=Arrays.asList(arr1);
System.out.println(list);
28、 集合变数组:Collection接口中的toArray方法
*/
public static void main(String[] args) {
ArrayList<String> al=new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
/*注意:1,指定类型的数组到底应定义多长?
当指定类型的数组长度小于集合的size,那么该方法内部会创建一个
新的数组;当指定类型的数组长度大于了集合的size,就不会创建新的数组,
而使用传递进来的数组。所以创建一个刚刚好的数组最优。即长度为list.size();
2,为什么要将集合变数组
为了限定对元素的操作,不要进行增删。
*/
String[] arr=al.toArray(new String[al.size()]);
System.out.println(Arrays.toString(arr));}
28、/*高级for循环:JDK1.5 对迭代器进行了封装,简化书写
格式:
for(数据类型 变量名:被遍历的集合(Collection)或者数组){ }
此格式对集合进行遍历只能获取集合元素,但是不能对集合进行操作。
迭代器除了遍历,还可以对集合进行remove操作.如果使用ListIterator,
还可以在遍历过程中对集合进行增删改查等操作。
传统For循环和高级for有什么区别?
高级for有一个局限性,必须有被遍历的目标
建议在遍历数组时尽量使用传统for,因为传统for可以对角标进行操作
*/
public class ForEachDemo {
public static void main(String[] args) {
ArrayList<String> al=new ArrayList<String>();
al.add("asd1");
al.add("des2");
al.add("dif3");
for(String s:al)
{
System.out.println(s);//打印结果:asd1 des2 dif3
}
//对Map集合的打印,先转成Set集合再用高级for循环
HashMap<Integer,String> hm=new HashMap<Integer,String>();
hm.put(1, "a");
hm.put(2, "b");
hm.put(3, "c");
//方法一:keySet
Set<Integer> keySet=hm.keySet();
for(Integer i: keySet)
{
System.out.println(i+"::"+hm.get(i));
}
//方法二:entrySet
Set<Map.Entry<Integer,String>> entrySet=hm.entrySet();
for(Map.Entry<Integer,String> me:entrySet)
{
System.out.println(me.getKey()+"---"+me.getValue());
}
}
}
29、JDK1.5版本新特性:可变参数:int...arr
其实就是数组参数的简写形式。不用每一次都手动的建立数组对象。只要将要操作的元素作为参数传递即可。隐式将这些参数封装成立数组。
Public static void show(int...arr)
{
System.out.println(arr.length);
}
Public static void main(String[] args)
{
只要传入参数类型相同,可以可变长度,在底层自动封装成数组
show(1,2,3); //打印结果为3
show(1,2,3,4,5);//打印结果为5
}