------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一.集合框架
1.概念:
用于存储数据的容器。
2.特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
3.集合和数组的区别:
1)、数组是固定长度的;集合可变长度的。
2)、数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
3)、数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
4.对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。集合容器在不断向上抽取过程中。出现了集合体系。在使用一个体系时,原则:参阅顶层内容。建立底层对象。
二.Collection
1.Collection是集合框架中的常用接口。其下有两个子接口:List(列表),Set(集)。
所属关系:
Collection:
|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|--Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
2.Collection接口中的常见操作:
注意:集合中存储的都是对象的引用(地址)。
1)、添加:
add(object):添加一个元素。 例:coll.add(“abc1”);
addAll(另一集合) :添加一个集合中的所有元素。例: Coll_1.addAll(coll_2);
2)、删除:
clear():将集合中的元素全删除,清空集合。 例:Coll.clear();
remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。 例:Coll.remove(“abc1”);
removeAll(另一集合):调用者只保留另一集合中没有的元素。 例:coll_1.removeAll(coll_2);
3)、判断:
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Coll) :集合中是否包含指定的多个元素。
boolean isEmpty():集合中是否有元素。
4)、获取:
size():获取个数,集合长度。 例:Coll.size();
Iterator:迭代器:集合中取出元素的方式。(注:下面专门介绍)
5)、取交集:
retainAll(另一集合):调用者只保留两集合的共性元素。
6)、将集合变成数组:
toArray();
3.迭代器:
1)、理解:是一个接口。作用:用于取出集合中的元素。
每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素。将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口。也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。
2)、迭代器常见操作:
hasNext(); 有下一个元素,返回真。
next(); 取出下一个元素。
remove(); 移除。
迭代器例子:
第一种写法:
Iterator it = coll.iterator();
while(it.hasNext())
System.out.println(it.next());
第二种写法:
for(Iterator it = coll.iterator(); it.hasNext(); )
System.out.println(it.next());
3)、注意:
迭代器的next方法是自动向下取元素。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
三.List
1.概述:
元素是有序的,元素可以重复。
List本身是Collection接口的子接口,具备了Collection的所有方法。
2.List包括:
1)、ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
2)、LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。(改变链表的地址)
3)、Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都非常慢。被ArrayList替代了。
3.List特有方法:凡是可以操作角标的方法。
1)、添加:
add(index,element) :在指定的索引位插入元素。Index是相应的位置,element是相应元素。
addAll(index,collection) :在指定的索引位插入一堆元素。collection是一个对象。
2)、删除:
remove(index) :删除指定索引位的元素。返回被删的元素。
3)、修改:
set(index,element):修改指定位置的元素。
4)、查找:
get(index):通过角标获取元素。List集合因为角标有了自己的获取元素的方式:遍历。
subList(from,to):获取部分对象元素。(包含头,不包含尾)
listIterator():List特有的迭代器。
indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;所以,通过-1,可以判断一个元素是否存在。
4.ListIterator:
1)、概述:ListIterator是List集合特有的迭代器,是Iterator的子接口。
2)、在迭代器时,只能用迭代器的方法操作元素。可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。
如果想要其他的操作,如添加、修改等,就需要使用其子接口:ListIterrator。该接口只能通过List集合的ListIterator方法获取。
(代码 ListIteratorDemo.java):
import java.util.*;
class ListIteratorDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
ArrayList a = new ArrayList();
a.add("java01");
a.add("java02");
a.add("java03");
sop(a);
Iterator it = a.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(obj.equals("java02"))
/* 在迭代时,不可以通过集合对象的方法操作集合中的元素。(a.add("java000");)
因为会发生ConcurrentModificationException异常。
导致的原因是:
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,
在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
*/
//a.add("java000");
it.remove();//将java02的引用从集合中删除了。
sop("obj= "+obj);
}
sop(a);
}
}
3)、ListIterator特有的方法:
add(obj); 增加。
set(obj); 修改为obj。
hasPrevious(); 判断前面有没有元素。
previous(); 取前一个元素。
5.可变长度数组的原理:
当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。
ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。
Vector:是按照原数组的100%延长。
6.枚举Enumeration:
枚举就是Vector特有的取出方式。
例如:
Vector v=new Vector();
for(Enumeration e=v.elements();e.hasMoreElements();)
{
System.out.println(e.nextElements());
}
7.LinkedList:
LinkedList:特有方法:
addFirst();
addLast();
getFirst();
getLast();获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException。
removeFirst();
removeLast();获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException。
在JDK1.6出现了替代方法。
offerFirst();
offerLast();
peekFirst();
peekLast();获取元素,但不删除元素。如果集合中没有元素,会返回null。
pollFirst();
pollLast();获取元素,但删除元素。如果集合中没有元素,会返回null。
练习:(代码 LinkedListDemo.java):
//使用LinkedList模拟一个队列数据结构
//队列:先进先出
import java.util.*;
class LinkedListDemo
{
public static void main(String[] args)
{
DuiLie d = new DuiLie();
d.add("java01");
d.add("java02");
d.add("java03");
while(!d.isNull())
{
System.out.println(d.get());
}
}
}
class DuiLie
{
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
public void add(Object obj)
{
link.addFirst(obj);
}
public Object get()
{
return link.removeLast();
}
public boolean isNull()
{
return link.isEmpty();
}
}
8.练习题:
(代码 ArrayListDemo.java):
//去除ArrayList集合中的重复元素。
import java.util.*;
class ArrayListDemo
{
public static void main(String[] args)
{
ArrayList a = new ArrayList();
a.add("java01");
a.add("java02");
a.add("java03");
a.add("java01");
System.out.println(a);
System.out.println(quchu(a));
}
public static ArrayList quchu(ArrayList a)
{
ArrayList newa = new ArrayList();
Iterator it = a.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!newa.contains(obj))
newa.add(obj);
}
return newa;
}
}
(代码 ArrayListDemo2.java):
/*
将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
比如:存人对象,同姓名同年龄,视为同一个人,为重复元素。
*/
import java.util.*;
class ArrayListDemo2
{
public static void main(String[] args)
{
ArrayList a = new ArrayList();
a.add(new Person("zhangsan",10));
a.add(new Person("lisi",11));
a.add(new Person("wangwu",12));
a.add(new Person("lisi",11));
//sop(a);
a = quchu(a);
Iterator it = a.iterator();
while(it.hasNext())
{
Object obj = it.next();
Person p = (Person)obj;
sop(p.getName()+"..."+p.getAge());
}
}
public static ArrayList quchu(ArrayList a)
{
ArrayList newa = new ArrayList();
Iterator it = a.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!newa.contains(obj))//contains依据的是equals方法。
newa.add(obj);
}
return newa;
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
//List集合判断元素是否相同,依据的是元素的equals方法。
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
/*
注意:
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
*/
四.Set
1.理解:
无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
Set集合的功能和Collection是一致的。Set接口取出方式只有一种,迭代器。
2.分类:HashSet和TreeSet。
1)、HashSet:
底层数据结构是哈希表,线程是不同步的(线程不安全)。无序,高效。存取速度快。
HashSet集合保证元素唯一性:
通过元素的hashCode和equals方法完成的。
如果元素的hashCode值相同,才继续判断元素的equals是否为true。
如果元素的hashCode值不同,那么不判断equals,从而提高对象比较的速度。
(复写hashCode和equals)
public int hashCode()
{
return name.hashCode()+age;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p = Person(obj);
return this.name.equals(p.name) && this.age==p.age;
}
下面用代码体现:
(代码 HashSetDemo.java):
/*
往HashSet集合中存入自定义对象。
姓名和年龄相同为同一个人,重复元素。
*/
import java.util.*;
class HashSetDemo
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a3",13));
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
Iterator it = hs.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"..."+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()
{
return name.hashCode()+age;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
//注意:
//对于HashSet集合,判断元素是否存在(contains),或者删除元素(remove),
//底层依据的是hashCode方法和equals方法。
2)、TreeSet:
可以对Set集合中的元素进行排序。默认按照字母的自然排序。底层数据结构是二叉树。线程是不同步的(线程不安全)。
保证元素唯一性的依据:compareTo方法return 0。
TreeSet的第一种排序方式:
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
这种方式也称为元素的自然顺序,或者叫做默认顺序。
下面用代码体现:
(代码 TreeSetDemo.java):
/*
需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
记住:排序时,当主要条件相同时,一定要判断一下次要条件。
*/
import java.util.*;
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("lisi01",11));
ts.add(new Student("lisi03",13));
ts.add(new Student("lisi02",12));
ts.add(new Student("lisi01",11));
ts.add(new Student("lisi0002",12));
Iterator it = ts.iterator();
while (it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = 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)
return this.name.compareTo(s.name);
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
TreeSet的第二种排序方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让容器自身具备比较性。
在集合初始化时就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。
第二种方式较为灵活。
下面用代码体现:
(代码 TreeSetDemo2.java):
import java.util.*;
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = 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)
return this.name.compareTo(s.name);
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyCompare());
ts.add(new Student("lisi01",11));
ts.add(new Student("lisi03",13));
ts.add(new Student("lisi02",12));
ts.add(new Student("lisi01",11));
ts.add(new Student("lisi0002",12));
Iterator it = ts.iterator();
while (it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"::"+stu.getAge());
}
}
}
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num==0)
{
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
/*
if(s1.getAge()>s2.getAge())
return 1;
if(s1.getAge()==s2.getAge())
return 0;
return -1;
*/
}
return num;
}
}
3.知识总结(需要注意的知识点):
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
4.练习题:
(代码 TreeSetTest.java):
/*
练习:按照字符串长度排序。
字符串本身具备比较性,但是他的比较方式不是所需要的。
这时就必须自定义一个比较器。
*/
import java.util.*;
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyCompare());
ts.add("bb");
ts.add("cba");
ts.add("ba");
ts.add("a");
ts.add("bb");
ts.add("abcd");
Iterator it = ts.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2)
{
String s1 = (String)o1;
String s2 = (String)o2;
/*
if(s1.length()>s2.length())
return 1;
if(s1.length()==s2.length())
return s1.compareTo(s2);
return -1;
*/
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}
五.泛型。表现格式:< 引用数据类型 >
1.理解:
JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
(定义数组时先定义了具体类型,例如int类型,所以比较安全。而集合定义时并没有定义任何类型。)
2.好处:
1)、将运行时期出现问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,安全。
2)、避免了强制转换的麻烦。
3.泛型格式:
通过<>来定义要操作的引用数据类型。
4.在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,只要见到<>就要定义泛型。
其实<>就是来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。
5.
1)、泛型类:将泛型定义在类上。
class Tool<Q> {
private Q obj;
public void setObject(Q obj) {
this.obj = obj;
}
public Q getObject() {
return obj;
}
}
2)、方法上的泛型:当方法操作的引用数据类型不确定的时候,可以将泛型定义在方法上。
public <W> void method(W w) {
System.out.println("method:"+w);
}
3)、静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
public static <Q> void function(Q t) {
System.out.println("function:"+t);
}
4)、泛型定义在接口上:
interface Inter<T> {
void show(T t);
}
class InterImpl<T> implements Inter<T> {
public void show(T t) {
System.out.println("show:"+t);
}
}
6.泛型高级应用:
? 通配符。也可以理解为占位符。
可以解决当具体类型不确定的时候,这个通配符就是 ? 。当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能,那么可以用 ? 通配符来表未知类型。
泛型的限定:
? extends E:可以接受E类型或者E的子类型。上限。
? super E:可以接受E类型或者E的父类型。下限。
五.Map
1.Map集合:该集合存储键值对。一对一往里存。而且要保证键的唯一性。
Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。
2.Map集合的常用方法:
1)、添加:
put(K key,V value):添加元素。当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。
putAll(Map):添加一个集合。
2)、删除:
clear():清空。
remove(key) :删除指定键值对。
3)、判断:
containsValue(value):判断值是否存在。
containsKey(key):判断键是否存在。
isEmpty():判断是否为空。
4)、获取:
get(key):通过键获取对应的值。(注意:可以通过get方法的返回值来判断一个键是否存在,通过返回null来判断)
size():获取集合的长度。
values():获取集合中所有的值。返回值类型是集合Collection。
keySet():
entrySet():
3.Map分类(Map集合的子类):
1)、Hashtable:底层是哈希表数据结构,是线程同步的。效率低。不可以存储null键,null值。
2)、HashMap:底层是哈希表数据结构,是线程不同步的。效率高。可以存储null键,null值。替代了Hashtable.
3)、TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。
Map和Set很像。其实Set底层就是使用了Map集合。
4.Map集合的两种取出方式:
1)、Set<k> keySet:将Map集合中所有的键存入到Set集合。
因为Set具备迭代器。
所以可以通过迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
Map集合的取出原理:将Map集合转成Set集合,再通过迭代器取出。
(代码 MapDemo.java):
import java.util.*;
class MapDemo
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
map.put("03","zs3");
map.put("01","zs1");
map.put("04","zs4");
map.put("02","zs2");
//先获取Map集合的所有键的Set集合,keySet();
Set<String> keySet = map.keySet();
//有了Set集合,就可以获取其迭代器。
Iterator<String> it = keySet.iterator();
while(it.hasNext())
{
String key = it.next();
//有了键就可以通过Map集合的get方法获取其对应的值。
String value = map.get(key);
System.out.println("key="+key+",value="+value);
}
}
}
2)、Set<Map.Entry<k,v>> entrySet:将Map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是:Map.Entry。
(代码 MapDemo2.java):
import java.util.*;
class MapDemo2
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
map.put("03","zs3");
map.put("01","zs1");
map.put("04","zs4");
map.put("02","zs2");
//将Map集合中的映射关系取出,存入到Set集合中。
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String,String>> it = entrySet.iterator();
while(it.hasNext())
{
Map.Entry<String,String> me = it.next();
String key = me.getKey();
String value = me.getValue();
System.out.println(key+"::"+value);
}
}
}
5.练习:
(代码 MapTest.java):
/*
练习:
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
*/
/*
步骤:
1,描述学生。
2,定义Map容器,将学生作为键,地址作为值,存入。
3,获取Map集合中的元素。
*/
import java.util.*;
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()
{
return name.hashCode()+age*34;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public int compareTo(Student c)
{
int num = new Integer(this.age).compareTo(new Integer(c.age));
if(num==0)
return this.name.compareTo(c.name);
return num;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//复写toString,自定义输出内容.
public String toString()
{
return name+"::"+age;
}
}
class MapTest
{
public static void main(String[] args)
{
HashMap<Student,String > hm = new HashMap<Student,String >();
hm.put(new Student("lisi",12),"beijing");
hm.put(new Student("lisi",11),"shanghai");
hm.put(new Student("lisi",10),"tianjin");
hm.put(new Student("lisi",14),"nanjing");
hm.put(new Student("lisi",13),"wuhan");
//第一种取出方式keySet
Set<Student> keySet = hm.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext())
{
Student stu = it.next();
String addr = hm.get(stu);
System.out.println(stu+"..."+addr);
}
//第二种取出方法Map.Entry
Set<Map.Entry<Student,String>> entrySet = hm.entrySet();
Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();
while(iter.hasNext())
{
Map.Entry<Student,String> me = iter.next();
Student stu = me.getKey();
String addr = me.getValue();
System.out.println(stu+"......"+addr);
}
}
}
(代码 MapTest2.java):
/*
练习:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2).....
通过结果发现,每一个字母都有对应的次数。
说明字母和次数之间都有映射关系。
当发现有映射关系时,可以选择Map集合。
因为Map集合中存放的就是映射关系。
*/
/*
思路:
第一次用s字母作为键去找集合,那么集合没有s这个键,
所以也没有对应的次数,返回null。
如果为null,就将s字母和1存入集合。
如果指定的键已经存在,说明有对应的次数。
就将对应的次数取出,并自增后重新存入集合。
*/
/*
步骤:
1,将字符串转成字符数组,因为要对每一个字母进行操作。
2,定义一个Map集合,因为打印结果的字母有顺序,所以使用TreeMap集合。
3,遍历字符数组。
4,将Map集合中的数据变成指定的字符串返回。
*/
import java.util.*;
class MapTest2
{
public static void main(String[] args)
{
String s = "sdfgzxcvasdfxcvdf";
System.out.println(method(s));
}
public static String method(String s)
{
char[] chs = s.toCharArray();
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
for(int x=0;x<chs.length;x++)
{
if(!(chs[x]>='a'&&chs[x]<='z'||chs[x]>='A'&&chs[x]<='Z'))
continue;
Integer value = tm.get(chs[x]);
if(value==null)
tm.put(chs[x],1);
else
{
value = value + 1;
tm.put(chs[x],value);
}
}
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 value = me.getValue();
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
6.Map扩展知识:
在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。
(代码 MapTuoZhan.java):
import java.util.*;
class MapTuoZhan
{
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","zhou");
yure.put("02","wu");
jiuye.put("01","zheng");
jiuye.put("02","wang");
//getStudentInfo(yure);
//getStudentInfo(jiuye);
Set<String> keySet = czbk.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext())
{
String key = it.next();
HashMap<String,String> value = czbk.get(key);
System.out.println(key);
getStudentInfo(value);
}
}
public static void getStudentInfo(HashMap<String,String> roomMap)
{
Set<String> keySet = roomMap.keySet();
Iterator<String> it = keySet.iterator();
while(it.hasNext())
{
String key = it.next();
String value = roomMap.get(key);
System.out.println(key+":"+value);
}
}
}
六.集合总结
1.看到Array就是数组结构,有角标,查询速度很快。
2.看到Linked就是链表结构,增删速度快。
3.看到Hash就是哈希表,就要想到哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
4.看到Tree就是二叉树,就要想到排序,就想要用到比较。
比较的两种方式:
一个是Comparable:覆盖compareTo方法;
一个是Comparator:覆盖compare方法。
5.集合什么时候用?
当存储的是一个元素时,就用Collection。保证唯一,就用Set。不保证唯一,就用List。
当存储对象之间存在着映射关系时,就使用Map集合。
6.用到集合时,代码中必须先导包 import java.util.*;
七.集合框架的工具类Collections
1.Collections:
Collections是集合框架中的一个工具类。它的出现给集合(list)操作提供了更多的功能。这个类不需要创建对象,内部提供的都是静态方法。
2.方法:
(代码 CollectionsDemo.java):
import java.util.*;
class CollectionsDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
List<String> list = new ArrayList<String>();
list.add("dd");
list.add("abc");
list.add("bbb");
list.add("ss");
list.add("a");
//sortDemo(list);
//maxDemo(list);
//binarySearchDemo(list);
//fillDemo(list.subList(0,3));//将list集合中的部分元素替换成指定元素
//replaceAllDemo(list);
//reverse(list);
//swap(list);
shuffle(list);
}
public static void sortDemo(List<String> list)//排序
{
sop(list);
Collections.sort(list,new myCompare());
sop(list);
}
public static void maxDemo(List<String> list)//最大值
{
String max = Collections.max(list,new myCompare());
sop(max);
}
public static void binarySearchDemo(List<String> list)
{
sop(list);
Collections.sort(list);
int index = Collections.binarySearch(list,"bbb");//二分查找,返回角标。前提是有序的对象。如果没找到则返回(-插入点)-1
sop(index);
}
public static void fillDemo(List<String> list)
{
sop(list);
Collections.fill(list,"pp");//把集合中的所有元素都变成pp
sop(list);
}
public static void replaceAllDemo(List<String> list)
{
sop(list);
Collections.replaceAll(list,"abc","w");//把集合中指定元素变成w
sop(list);
}
public static void reverse(List<String> list)
{
sop(list);
Collections.reverse(list);//反转
sop(list);
}
public static void swap(List<String> list)
{
sop(list);
Collections.swap(list,0,1);//互换位置
sop(list);
}
public static void shuffle(List<String> list)
{
sop(list);
Collections.shuffle(list);//随机对list中的元素进行位置的置换。相当于洗牌。
sop(list);
}
}
class myCompare implements Comparator<String>//按指定的比较器方法排序
{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
return 1;
if(s1.length()==s2.length())
return s1.compareTo(s2);
else
return -1;
}
}
(代码 CollectionsDemo2.java):
import java.util.*;
class CollectionsDemo2
{
public static void main(String[] args)
{
reverseOrderDemo();//逆向反转排序
}
public static void reverseOrderDemo()
{
TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder());
ts.add("dd");
ts.add("ghjk");
ts.add("a");
ts.add("bcd");
Iterator<String> it = ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
3.同步的集合:
List<T>synchronizedList(List<T> list); 返回支持的同步(线程安全的)List集合。
Map<K,V>synchronizedList(Map<K,V> m); 返回支持的同步(线程安全的)Map集合。
八.Arrays
1.用于操作数组对象的工具类,里面都是静态方法。
2.方法:
1)、String toString(); 可以接收各种数组类型参数,并返回指定数组内容的字符串表现形式。
例:int[] arr = {2,4,5};
System.out.println(Arrays.toString(arr));//转换为字符串形式
2)、asList方法:数组变集合。
例:String[] arr = {"abc","kk","qq"};
List<String> list = Arrays.asList(arr);//将arr数组转成list集合。
将数组转换成集合,有什么好处呢?
可以使用集合的思想和方法来操作数组中的元素。
注意:
将数组变集合,不能使用集合的增删操作,因为数组的长度是固定的。如果进行增删操作,则会产生UnsupportedOperationException的编译异常。
如果数组中的元素都是对象,则变成集合时,数组中的元素就直接转为集合中的元素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
3.toArray():集合变数组。
用的是Collection接口中的方法:toArray();
例:ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
//将集合变为String数组
String[] arr = al.toArray(new String[al.size()]);
//利用Arrays操作数组的方法
System.out.println(Arrays.toString(arr));
指定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。
当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。
所以创建一个刚刚好的数组最优。
为什么要将集合变数组?
为了限定对元素的操作。不需要进行增删了。
九.(1.5版本新特性)高级for
1.Collection在jdk1.5以后,有了一个父接口Iterable,这个接口的出现的将iterator方法进行抽取,提高了扩展性。
2.格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{
}
3.高级for对集合进行遍历,只能获取集合元素,但不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合中元素的操作。
如果是ListIterator,还可以在遍历过程中对集合进行增删改查的操作。
传统for和高级for有什么区别?
高级for有一个局限性,必须有遍历的目标。
建议在遍历数组的时候,还是希望用传统for,因为传统for可以定义角标。
4.定义一个HashMap集合:
例子:
HashMap<Integer,String> hm = new HashMap<Integer,String>();
hm.put(1,"a");
hm.put(2,"b");
hm.put(3,"c");
//keySet取出方式的高级for遍历
Set<Integer> keySet = hm.keySet();
for(Integer i : keySet)
{
System.out.println(i+"::"+hm.get(i));
}
//entrySet取出方式的高级for遍历
for(Map.Entry<Integer,String> me : hm.entrySet())
{
System.out.println(me.getKey()+"------"+me.getValue());
}
十.(1.5版本新特性)方法的可变参数
1.可变参数:其实就是数组参数的简化形式,不用每一次都手动的建立数组对象。只要将要操作的元素作为参数传递即可。隐式将这些参数封装成了数组。
2.例:
public static void main(String[] args)
{
show("haha",1,2,3,4,5,6);
}
public static void show(String str,int... arr)//...就表示可变参数
{
System.out.println(arr.length);
}
在使用时注意:可变参数一定要定义在参数列表的最后面。
十一.(1.5版本新特性)静态导入
1.导入了类中的所有静态成员,简化静态成员的书写。
2.写法:
import static java.util.Arrays.*; 导入的是Arrays这个类中的所以静态成员。
import static java.lang.System.*; 导入了Sytem类中所以静态成员。
3.注意:
当类名重名时,需要指定具体的包名。
当方法重名时,指定具体所属的对象或者类。