1—Collection集合
一:集合简述
Collection集合:
它是集合的根接口,不可以直接实现。
Collection 实现了 Iterable 接口,可以用iterator()【迭代器】遍历对象。Collection集合常用方法:
boolean add (E e) //添加一个待定类型的元素,添加成功返回 true ,添加失败返回 false 。 boolean isEmpty () //判断集合是否为空,是的话就返回true 。 boolean contains (Object o) //判断集合中是否包含元素 o(注意o的类型)。 boolean equals (Object o) //判断集合与指定对象是否相等,已经覆盖了上帝类中的equals 。 boolean remove(Object o) //移除一个元素,移除成功返回true。 int size () //返回集合中的元素个数。 int hashCode () //返回集合的哈希值。 void clear () //移除Collection中所有元素。 Iterator<> iterator() //返回集合元素的迭代。
数组和集合同是容器,其不同在于:
数组长度是固定的。集合长度是可变的。
数组可以存储基本数据类型,集合只能存储对象,而且可以存储不同类型的对象。迭代器的概念:
集合的内部都定义了集合元素的取出方式,每种集合的数据结构都不同,迭代器就是抽取了取出方式的共性内容。泛型:
集合在创建对象时最好明确要存入的元素的类型,这样更安全。
形式如:ArrayList<String> list=new ArrayList<String>(); //指定集合中只能存储字符串类型。
这就是泛型限定。
泛型的好处:
如果不指定集合的类型,用户在传值时,有可能传入不同类型的元素,而取出时按照统一类型取出,就会出现异常。
所以泛型的出现,就把运行时容易出现的问题ClassCastException 转移到编译时期。
泛型也避免了强转。
泛型类:
当类中要操作的引用数据类型不确定时,就 在类上定义泛型,如:class Demo<T> { private T t; public T show() { return t; } }
注意:
静态方法加载时,泛型还未指定,所以不可以访问类上定义的泛型。
定义了泛型之后,创建该类对象时需要指定类型,这样就只可以存入一种类型的元素。
但是创建了对象之后,泛型就被锁定,不可以再传入其他类型,这是泛型类的局限性。泛型方法:
把泛型定义在方法上,可以在同一个对象引用中操作不同类型。
形式:class Demo { public <T> void show(T t) {} //方法上的泛型放在返回值类型前。 public <T> void print(T t) {} }
这样定义的泛型就只在本方法中有效,可以一个对象调用多种类型数据。
如果类上的泛型和类中方法上的泛型同名,那么类上的泛型被锁定时,类中方法上的泛型也被锁定。
泛型接口:
就是在接口上使用泛型,由实现它的类或者该类的对象指定泛型,如:interface Inter<T> { void show(T t); } class Demo implements Inter<String> //接口被实现时指定了泛型,有局限性。 { public void show(String t) {} } class Demo_2<T> implements Inter<T> //接口被实现时不指定类型。 { public void show(T t) {} }
泛型限定:
当不同类型的泛型调用同一个方法时,该方法不确定是哪一种类型的泛型,所以就用一个占位符表示,
形如:public void (ArrayList<?> list){}
这样的泛型不可以调用具体类型的方法,因为类型不确定,所以类型中不确定有没有此方法。
问号作为占位符代表类型不确定,但仍然可以是任何类型,如果要缩小范围,就可以写成:public void (ArrayList<? extends E> list)
这样的泛型限定代表的是上限,意思是只可以接收E类型或者E的子类,
还可以写成:public void (ArrayList<? super E> list)
这样的泛型代表的是下限,意思是只可以接受E类型或者E的父类。
二:Collection集合框架详解
List
是一个接口,继承自Collection接口。
List 无法实例化,只有实现它的子类可以实例化。
List 可以有重复元素。
List中的元素有角标,可根据元素的角标索引访问元素。常用方法:
boolean add (E e) //往列表最后添加一个待定类型的元素,添加成功返回 true ,添加失败返回 false 。 boolean isEmpty () //判断List是否为空,是的话就返回true 。 boolean contains (Object o) //判断List列表中是否包含指定元素。 boolean equals (Object o) //判断List列表与指定对象是否相等 。 boolean remove(Object o) //移除第一个o元素,移除成功返回true。 void add(int index,E element)//指定位置上插入元素。 void clear () //移除List列表中所有元素。 int indeOf (Object o) //返回指定元素在列表中第一次出现的位置,如果列表不包含次元素,返回-1. int lastIndeOf (Object o) //返回指定元素在列表中逆向第一次出现的位置,如果列表不包含次元素,返回-1. int size () //返回List集合中的元素个数。 int hashCode () //返回List集合的哈希值。 E get (int index) //返回列表中指定位置上的元素。 E remove (int index) //移除指定位置上的元素,返回被移除元素,可能抛角标越界异常。 E set(int index,E element) //用指定元素替代指定角标上的元素,返回被替换元素,要抛异常。 boolean removeAll(Collection<?> c) //移除指定List中和c重复的所有元素。 boolean retainAll(Collection<?> c) //保留指定List中和c重复的所有元素。 List<E> subList (int from,int to) //截取一个短的List集合,从from到to,包含头不包含尾。 Object [] toArray() //返回按适当顺序排列的数组。 T [] toArray (T [] a) //返回指定类型的数组。 Iterator<E> iterator() //按适当顺序在列表的元素上进行迭代的迭代器。Iterator只能对元素判断,修改,取出。 ListIterator<E> listIterator //返回列表元素的列表迭代器。功能比Iterator多。
ArrayList
它是数组集合。
ArrayList实现了List接口,它可以实例化。
在构造时,
ArrayList() 默认构造一个初始容量10的列表,
ArrayList(int n)构造一个初始容量为n的列表。ArrayList**常用方法**基本与List相同。
举例: ArrayList 常见方法使用示例
import java.util.*; class Demo { public static void main(String [] args) { ArrayList<String> arrlist=new ArrayList<String>(); arrlist.add("java01"); //添加元素 arrlist.add("java02"); arrlist.add("java03"); System.out.println(arrlist); //直接打印集合。[java01, java02,java03] System.out.println(arrlist.get(1)); //获取角标1上的元素。 int L=arrlist.size(); //L指arrlist的长度,3. System.out.println(arrlist.remove(1)); //删除1角标上的元素,并返回此元素。打印java02 。 System.out.println(arrlist.indexOf("java02")); //获取对象角标。 System.out.println(arrlist.remove("java01")); //删除指定元素。返回是否删除成功,true。 System.out.println(arrlist.contains("java01"));//已经移除,不包含,返回false。 System.out.println(arrlist); //元素只剩下:[java03] arrlist.add(0,"JAVA"); //指定位置添加元素 System.out.println(arrlist); //打印数组:[JAVA,java03] //由此可见移除元素时,后面元素的角标会改变。 arrlist.clear(); //清空元素 System.out.println(arrlist.size()); //元素个数0. System.out.println(arrlist.isEmpty()); //ArrayList为空,返回true。 } }
迭代器的用法:
举例: ArrayList 用迭代器取出元素Iterator<String> it=arrlist.iterator(); while (it.hasNext()) { System.out.println(it.next()); }
或者:
for (Iterator it=arrlist.iterator();it.hasNext(); ) { System.out.println(it.next()); }
注意:写成for循环可以不用在外部定义迭代器,节省内存。而且代码更简洁。
ArrayList 特有的列表迭代器–ListIterator :
Iterator 只能对元素判断,取出,删除, ListIterator 更可以对元素添加和修改。ArrayList<String> al=new ArrayList<String>(); al.add("01"); al.add("02"); al.add("03"); for (ListIterator<String> lit=al.listIterator();lit.hasNext(); ) { String s=lit.next(); if (s.equals("02")) { lit.set("JAVA2"); lit.add("java02"); //这两句不可以换位 } }
注意: ListIterator 只能先修改再添加,不可以先添加再去修改。
因为如果先添加元素,元素后的角标都会变,再去修改就出现状态异常:IllegalStateException练习1: ArrayList集合 去除重复元素方法。
定义好ArrayList后,新建一个临时数组集合,用于存储集合元素。
然后迭代ArrayList的元素以判断是否包含的形式选择添加进临时数组集合,然后再迭代取出。import java.util.*; class Demo { public static void main(String [] args) { ArrayList<String> al=new ArrayList<String>(); al.add("01"); al.add("02"); al.add("03"); al.add("03"); al = noRepeat(al); System.out.println(al); } public static ArrayList<String> noRepeat(ArrayList<String> al) { ArrayList<String> arrlist = new ArrayList<String>(); for (Iterator<String> it=al.iterator();it.hasNext(); ) { String s=it.next(); if (!(arrlist.contains(s))) arrlist.add(s); } return arrlist; } }
练习2:集合中存储自定义对象的去重复方法:。
集合中如果添加的是自定义的对象,集合中存储的是对象的引用,那么所有对象都不会相同。
所以就要在对象类中重写equals方法以判断元素的内容是否相同,然后迭代取出。import java.util.*; 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; } public boolean equals(Object oo) { if (!(oo instanceof Person)) return false; Person p = (Person)oo; return this.name==p.name && this.age==p.age; } } class Demo { public static void main(String [] args) { ArrayList<Person> al=new ArrayList<Person>(); al.add(new Person("01",12)); al.add(new Person("02",13)); al.add(new Person("01",12)); al.add(new Person("01",13)); al=noRepeat(al); for (Iterator<Person> it=al.iterator();it.hasNext(); ) { Person p=it.next(); System.out.println(p.getName()+" + "+p.getAge()); } } public static ArrayList<Person> noRepeat(ArrayList<Person> al) { ArrayList<Person> arrlist = new ArrayList<Person>(); for (Iterator<Person> it=al.iterator();it.hasNext(); ) { Person p=it.next(); if (!arrlist.contains(p)) arrlist.add(p); } return arrlist; } }
注意:
(1)集合中存储的其实是对象的引用地址值。
(2)元素取出时,要调用对象的方法取出元素值。
(3)从太难受方法调用了equal是方法,所以对于对象引用的比较,应该重写equals方法。
(4)注意equals方法比较的是Object类型,所以有向上转型和向下转型。LinkedList
–链表集合。
LinkedList集合的特点是,集合中的元素没有角标,每个元素会和它前一个元素形成关系,这样就组成了一个链表。
当要对LinkedList中的元素查询的时候就要一个一个判断,速度慢。
但是当要增删的时候就比较快,因为不需要改动后面所有元素的角标了,只需要改变指定元素周围的关系就可以。LinkedList 常用方法和List基本相同,
LinkedList 特有的方法:
void addFirst (E e) //将元素插入到开头。 void addLast (E e) //将元素插入到末尾。 //这几个方法如果列表为空会抛NoSuchElementException异常。 E getFirst () //获取第一个元素。 E getLast () //获取最后一个元素。 E removeFirst () //移除并返回第一个元素。 E removeLast () //移除并返回最后一个元素。
从JDK1.6开始,出现了新方法,功能和以上一样,但是都不会再抛NoSuchElementException异常。
void offer (E e) void offerFirst (E e) void offerLast (E e) E peek () E peekFirst () E peekLast () E poll () E poolFirst () E pollLast ()
举例: LinkedList 模拟堆栈的先进后出数据结构和队列的先进先出数据结构。
import java.util.*; class Zhan { private LinkedList<Object> ll=new LinkedList<Object>(); public void myAdd(Object oo) { ll.offer(oo); //从末尾添加元素 } public Object myGet() { return ll.pollLast(); //从末尾获取元素并移除 } public boolean isNull() { return ll.isEmpty(); //判断集合是否为空 } } class Dui { private LinkedList<Object> ll=new LinkedList<Object>(); public void myAdd(Object oo) { ll.offer(oo); //从末尾添加元素 } public Object myGet() { return ll.pollFirst(); //从开头获取元素并移除 } public boolean isNull() { return ll.isEmpty(); //判断集合是否为空 } } class Demo { public static void main(String [] args) { Zhan z=new Zhan(); z.myAdd("z1"); z.myAdd("z2"); z.myAdd("z3"); while (!z.isNull()) System.out.println(z.myGet()); Dui d=new Dui(); d.myAdd("d1"); d.myAdd("d2"); d.myAdd("d3"); while (!d.isNull()) System.out.println(d.myGet()); } }
注意: LinkedList 如果泛型写成占位符形式
LinkedList<?>
那么就不能往集合中添加Object元素。Set
Set集合不包含重复元素,包括null值也不可重复。
元素是无序的。
Set 继承自 Collection , 它也是一个接口,不可以直接实例化。Set集合的常用方法和Collection基本相同。
HashSet
HashSet 底层数据结构是哈希表数据结构。
HashSet 是Set集合的一个子类,允许使用null元素。
HashSet 集合存元素时,不可以存相同的元素,包括null元素都不可以重复。
数据存储时不是按照元素顺序排列,而是内存中对象的哈希值顺序,元素取出时也是按照哈希表的顺序取出,所以是无序的。HashSet 构造方法:
HashSet() //构造一个默认初始容量16的Set集合 HashSet(int len) //构造一个指定初始容量的Set集合 HashSet(Collection c) //构造一个包含指定集合的Set集合
Set 常用方法:
int size() //返回集合长度 void clear() //移除集合中所有元素 boolean add(E e) //对集合添加一个元素并返回是否添加成功 boolean isEmpty() //判断集合是否为空 boolean remove(Object oo) //移除指定元素并返回是否移除成功 boolean contains(Object oo) //返回集合中是否包含指定元素 Iterator<E> iterator() //返回对此Set集合中元素迭代的迭代器
Set集合存入自定义对象时,实际存入的也是对象的引用。这时候系统会先判断对象的引用是否相同。
所以就要覆盖对象的hashCode()方法,让对象的引用都相同。引用相同时,系统还会调用equals()方法再判断一次存入的对象的内容是否相同。
所以也要重写equals方法。举例: Set 集合存储自定义对象。
import java.util.*; 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; } public boolean equals(Object oo) { //已经限定集合类型为Person,所以不用判断类型 // if (!(oo instanceof Person)) // return false; Person p=(Person)oo; return this.name == p.name && this.age==p.age; } public int hashCode() { return 123*45; } } class Demo { public static void main(String [] args) { HashSet<Person> hs=new HashSet<Person>(); hs.add(new Person("s1",12)); hs.add(new Person("s2",13)); hs.add(new Person("s1",12)); hs.add(new Person("s4",13)); for (Iterator<Person> it=hs.iterator(); it.hasNext(); ) { Person p=(Person)it.next(); System.out.println(p.getName()+" "+p.getAge()); } } }
注意:
(1)Set集合存入元素时,会先给对象分配哈希值,重写hashCode方法是为了让各个对象的哈希值相同;如果哈希值相同,就比较元素内容。
(2)重写equals方法是为了可以比较对象方法返回的内容是否相同。
(3)判断元素是否在集合中存在,先调用hashCode方法判断元素的哈希值是否相等,再调用equals方法判断元素内容是否相等。
(4)移除元素也是先判断哈希值,再判断元素内容。
(5)Set集合和List集合判断元素是否相同差别在于List不判断哈希值。TreeSet
特点: TreeSet 底层数据结构是二叉树结构。
TreeSet 集合中存入的元素必须具备比较性。
TreeSet 可以对Set集合中的元素进行自然排序。TreeSet常用方法和Set基本相同,
TreeSet特有方法:
(1)构造方法:TreeSet(Comparator<? super E> c)//此比较器可以接收TreeSet集合接受的类型或者它的父类
(2)一般方法:
E first() //返回集合中第一个元素 E last() //返回集合中最后一个元素 E pollFirst() //获取并移除第一个元素 E pollLast() //获取并移除最后一个元素 E ceiling(E e) //返回集合中大于等于指定元素的最小元素,不存在则放回null E floor(E e) //返回集合中小于等于指定元素的最大元素,不存在则返回null Comparator<? super E> comparator() //返回对集合中元素排序的比较器,如果是自然排序就返回null Iterator<E> descendingIterator() //返回集合中降序迭代的迭代器
TreeSet集合元素手动排序的第一种方式:让元素自身具备比较性。
需要实现 Comparable接口,并且覆盖接口中的compareTo方法。举例:
import java.util.*; class Person implements Comparable<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; } public int compareTo(Person p) { if (this.age<p.age) return -1; if (this.age>p.age) return 1; return this.name.compareTo(p.name); } } class Demo { public static void main(String [] args) { TreeSet<Person> ts=new TreeSet<Person>(); ts.add(new Person("s1",12)); ts.add(new Person("s2",13)); ts.add(new Person("s1",12)); ts.add(new Person("s4",13)); for (Iterator<Person> it=ts.iterator(); it.hasNext(); ) { Person p=(Person)it.next(); System.out.println(p.getName()+"++"+p.getAge()); } } }
注意: Comparable接口的compareTo方法参数类型是跟随Comparable的泛型的。
TreeSet 集合手动排序的第二种方式:让集合自身具备比较性。
当元素自身不具备比较性或者不是所需的比较性时,就要让集合自身具备比较性。
先定义一个比较器,然后在集合初始化时,将比较其对象作为参数传递给TreeSet集合的构造函数。接口 Comparator 是用于强制对对象排序的比较器。
它有两个抽象方法:equals(Object oo) compare(Object o1,Object o2) //注意不是compareTo,而是compare。
定义比较器的示例:
class Com implements Comparator<Person> { public int compare(Person p1,Person p2) { int n = p1.getName().compareTo(p2.getName()); if (n==0) return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge())); return n; } }
注意:
这里不重写equals方法,是因为类继承Object,已经有equals方法。
compare方法参数类型是跟随Comparator接口的泛型类型的。定义了比较器之后,就可以通过TreeSet的构造函数:
TreeSet(Comparator<? super E> c);
让集合自身具备比较性,然后通过传递参数的形式,在创建TreeSet对象时,添加参数:TreeSet<E> ts=new TreeSet<E>(new MyComparator());
就可以对TreeSet集合中的元素进行排序。注意:
当两种排序方法都存在时,比较器接口是对外提供的功能扩展,一般以比较器为主。举例: TreeSet 排序练习:按字符串长度排序。
import java.util.*; class Demo { public static void main(String [] args) { TreeSet<String> ts=new TreeSet<String>(new MyCom()); ts.add("aabsd"); ts.add("aaasd"); ts.add("vcx"); ts.add("q"); for (Iterator<String> it=ts.iterator();it.hasNext(); ) { System.out.println(it.next()); } } } class MyCom implements Comparator<String> { public int compare(String s1,String s2) { int n = new Integer(s1.length()).compareTo(new Integer(s2.length())); if (n==0) return s1.compareTo(s2); return n; } }
注意:
String 类有compareTo方法,可以比较字符串并返回负数,零,正数。
定义比较器比较时,往往需要比较两个内容,一个是两对象要比较的条件是否相等,一个是两对象是否是同一个。
此例还可以写成匿名内部类的形式。
2—Map 集合
一:Map集合简述
Map集合:
用于存储键值对,形成一个映射,Map集合反应的是键与值的映射关系,而且关系唯一。常用方法:
int size() //返回映射中的键值映射关系数。 void clear() //从映射中移除所有映射关系。 int hashCode() //返回此映射的哈希码值。 boolean isEmpty() //判断映射是否为空。 V get(Object key) //返回key对应的value值,如果不存在返回null。 V put(K key,V value) //添加一个映射关系,返回被覆盖的value值。 V remove(Object key) //如果存在键为key的映射关系,则将其移除,不存在返回null。 boolean equals(Object oo) //比较指定对象与此映射是否相等。 boolean containsKey(Object key) //返回映射是否包含指定key值。 boolean containsValue(Object value) //返回映射是否包含指定value值。 Set<K> keySet() //返回映射中包含的键的Set视图。 Collection<V> values() //返回映射中包含的值的Collection视图。 Set<Map.Entry<K,V>> entrySet() //返回映射中包含的映射关系的Set视图。
举例: Map常用方法用法示例。
import java.util.*; class Demo { public static void main(String [] args) { Map<String,String> map=new HashMap<String,String>(); map.put("01","zhang01"); map.put("02","zhang02"); map.put(null,"zhang03"); //null可以作为键存在,但只能有一个null键。 System.out.println(map.containsKey("02"));//判断是否包含"02"键。 System.out.println(map.get("02")); //返回"02"键对应的值并打印,不存在此键值就返回null。 System.out.println(map.remove("02")); //移除并返回"02"键的值,不存在此键就返回null。 System.out.println(map); //直接打印Map集合:{01=zhang01, 03=zhang03} System.out.println(map.values()); //打印Collection集合:[zhang01, zhang03] System.out.println(map.put("01","001"));//映射中存在同名键,所以会覆盖"01"键对应的值,并返回被覆盖的value值。 } }
Map 集合取出:
Map集合元素取出的第一种方式: keySet方法。
keySet 取出此映射中所有的键,存入一个Set集合。
因为Set具备迭代器,所以可以迭代取出所有的键,然后get方法获取键对应的值。
Map 集合的取出原理:将Map集合转成Set集合,再通过迭代器取出。Map集合本身不需要迭代器。举例: keySet方法取出映射中的键与值。
import java.util.*; class Demo { public static void main(String [] args) { Map<String,String> map=new HashMap<String,String>(); map.put("01","zhang01"); map.put("02","zhang02"); map.put("03","zhang03"); Set<String> set=map.keySet(); //返回由Map集合中所有键值组成的Set集合。 for (Iterator<String> it=set.iterator();it.hasNext(); ) { String key=it.next(); System.out.println("key:"+key+" + value:"+map.get(key)); } } }
Map 集合取出的第二种方式: entrySet方法。
entrySet 返回的是一个键值映射关系Set视图,这种关系的数据类型是 Map.Entry。
Map.Entry 是Map接口中的一个静态内部接口。常见方法:
boolean equals(Object oo) //比较两对象是否相等。 int hashCode() //返回对象哈希值 K getKey() //获取对象的键。 V getValue() //获取对象的值。 V setValue(V value) //修改对象的值。
举例: entrySet方法取出映射中的键与值。
import java.util.*; class Demo { public static void main(String [] args) { Map<String,String> map=new HashMap<String,String>(); map.put("01","zhang01"); map.put("02","zhang02"); map.put("03","zhang03"); Set<Map.Entry<String,String>> set=map.entrySet(); for (Iterator<Map.Entry<String,String>> it=set.iterator();it.hasNext(); ) { Map.Entry<String,String> entry=it.next(); String key=entry.getKey(); String value=entry.getValue(); System.out.println(key+":"+value); } } }
练习:
学生具有属性:姓名,年龄;同时具有归属地。
存入几个学生对象,以属性作为键,归属地作为值,并可以按学生年龄降序。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 String getName() { return name; } public int getAge() { return age; } public int hashCode() { return name.hashCode()+age*45; } public boolean equals(Object oo) { if (!(oo instanceof Student)) throw new ClassCastException("!类型不匹配!"); Student s=(Student)oo; return this.name.equals(s.name) && this.age==s.age; } public int compareTo(Student s) { int num=new Integer(s.age).compareTo(new Integer(this.age)); if (num==0) return this.name.compareTo(s.name); return num; } } class Demo { public static void main(String [] args) { TreeMap<Student,String> tm=new TreeMap<Student,String>(); tm.put(new Student("L1",21),"北京"); tm.put(new Student("L2",20),"南京"); tm.put(new Student("L2",20),"天津"); tm.put(new Student("L3",25),"上海"); //keySet方法取出Map集合元素。 Set<Student> keySet=tm.keySet(); for (Iterator<Student> it=keySet.iterator();it.hasNext(); ) { Student s=it.next(); System.out.println(s.getName()+"+"+s.getAge()+"<->"+tm.get(s)); } //entrySet方法取出Map集合元素。 Set<Map.Entry<Student,String>> entrySet=tm.entrySet(); for (Iterator<Map.Entry<Student,String>> it=entrySet.iterator();it.hasNext(); ) { Map.Entry<Student,String> me=it.next(); Student s=me.getKey(); String str=me.getValue(); System.out.println(s.getName()+" : "+s.getAge()+"<->"+str); } } }
注意:
Map集合必须存键值对象两个元素,可根据对象属性特点选择哪一个属性作为键。
Map集合存入重复元素时,后存入的元素会覆盖之前的元素。
TreeMap 也可以传入比较器用于对元素排序。此例如果要以姓名升序排列,可以自定义比较器。练习2:
获取字符串中字幕出现次数。形式:a(2) b(4) c(1) …import java.util.*; class Demo { public static void main(String [] args) { String s="hcgngvsgjsbcgscbgsibscgjvjbjkbxkcjsbkjv"; //可根据需要将字符串判断一次,确保字符串全是字母,没有数字或其他字符。 printTime(s); } public static void printTime(String s) { char [] ch=s.toCharArray(); TreeMap<Character,Integer> tm=new TreeMap<Character,Integer>(); for (int x=0;x<ch.length;x++) { char c=ch[x]; int i=0; if (tm.containsKey(c)) i=tm.get(c); tm.put(c,++i); } Set<Map.Entry<Character,Integer>> entrySet=tm.entrySet(); for (Iterator<Map.Entry<Character,Integer>> it=entrySet.iterator();it.hasNext(); ) { Map.Entry<Character,Integer> me=it.next(); char c=me.getKey(); int i=me.getValue(); System.out.print(c+"("+i+") "); } } }
注意:
泛型中接收的都是引用数据类型,不可以接受基础数据类型。练习3: Map集合的嵌套循环,打印学校中所有班级的学生信息。
import java.util.*; class Demo { public static void main(String [] args) { //创建一个基础班 HashMap<String,String> jichu=new HashMap<String,String>(); jichu.put("01","zhang"); jichu.put("02","wang"); //创建一个就业班 HashMap<String,String> jiuye=new HashMap<String,String>(); jiuye.put("001","zhao"); jiuye.put("002","zhou"); //创建一个学校 HashMap<String,HashMap<String,String>> school= new HashMap<String,HashMap<String,String>>(); school.put("基础班",jichu); school.put("就业班",jiuye); for (Iterator<String> it=school.keySet().iterator();it.hasNext(); ) { String roomName=it.next(); System.out.println(roomName); HashMap<String,String> room=school.get(roomName); //取出班级里的学生 for (Iterator<String> it2=room.keySet().iterator();it2.hasNext(); ) { String id=it2.next(); String name=room.get(id); System.out.println(id+"+"+name); } } } }
注意:一般情况下,使用keySet更简便一些。它不涉及Map.Entry接口。
3—集合工具
一:Collections
Collections 是用于对集合进行操作的工具类。
该类没有构造函数,不需要创建对象。该类中所有方法都是静态的。
Collections 中的泛型比较复杂, 这里通过练习的形式只简单介绍方法的用法。
Collections 的简单方法。
import java.util.*; class Demo { public static void main(String [] args) { List<String> list=new ArrayList<String>(); list.add("sss"); list.add("aa"); list.add("k"); list.add("dddd"); Collections.sort(list); //对集合自然排序,没有返回值。 System.out.println(list); Collections.sort(list,new Com());//对集合比较器排序,没有返回值。 System.out.println(list); System.out.println(Collections.max(list)); //打印集合自然排序后的最大值。 System.out.println(Collections.min(list,new Com()));//打印集合比较器排序后的最小值。 System.out.println(Collections.binarySearch(list,"aa"));//打印二分查找元素的索引。 Collections.fill(list,"A"); //将集合中所有元素替换成"A"。 System.out.println(list); Collections.reverse(list); //反转集合元素。 System.out.println(list); Collections.replaceAll(list,"A","B");//将集合中所有"A"替换成“B”。 System.out.println(list); Collections.swap(list,1,2); //置换两角标位的元素。 System.out.println(list); Collections.shuffle(list); //随机排列集合元素。 System.out.println(list); } } class Com implements Comparator<String> { public int compare(String s1,String s2) { int num=new Integer(s1.length()).compareTo(new Integer(s2.length())); if (num==0) return s1.compareTo(s2); return num; } }
注意:
(1) ArrayList 不像TreeSet、TreeMap那样,它不可以传比较器作为参数。
(2) 如果是自然排序,就直接Collections.sort(list)
,如果是自定义排序,就需要加比较其对象参数:Collections.sort(list,new Com())
。
(3)取最值时,元素在max方法中会重新排序,然后调用max方法会取出最右侧的值,调用min方法会取出最左侧的值。Collections 的reverseOrder方法:
对于需要传入比较器的String类型集合对象,如TreeSet、TreeMap,
如果传入比较器Com用于对字符串按长度排序,
可以写成:TreeSet<String> ts=new TreeSet<String>(new Com());
如果想要将排序改成长度降序,可以写成:
TreeSet<String> ts=new TreeSet<String>(Collections.reverseOrder(new Com()));
。
reverseOrder方法用于将顺序反转。Collections 的synchronizedCollection方法:
集合中的很多方法都是线程不安全的,在多线程时容易出现安全问题。
synchronizedCollection方法可以接受一个不安全的集合线程,返回一个安全的集合线程。
和它类似的还有 synchronizedList方法,synchronizedMap方法,synchronizedSet方法。
二:Arrays 类
Arrays类中主要是对数组的操作方法,而且方法都是静态的。
例如,数组二分查找:binarySearch方法,数组排序:sort方法,数组转字符串:toString方法等。
Arrays 中数组转集合的方法:asList方法。
import java.util.*; class Demo { public static void main(String [] args) { String [] arr={"aa","cc","ff","acf"}; System.out.println(Arrays.toString(arr)); //将数组打印,形式如: [aa, cc, ff, acf] List<String> list=Arrays.asList(arr); System.out.println(list); } }
注意:
(1)Arrays 的asList方法将数组转成集合后,因为数组的长度是固定的,所以不支持使用集合的增删方法。
(2)如果数组中的元素都是对象,数组转集合时,数组元素就可以直接转成集合中的元素。
如果数组中的元素都是基本数据类型,数组转集合时,会将数组作为集合元素存入集合。
所以数组转集合时,最好不是基本数据类型的数组。
(3)数组编辑和就可以用集合中的一些方法操作数组。集合转成数组:toArray(T [] t)方法。
Collection接口中提供了toArray方法,可以将集合转成数组。
toArray方法如果不带参数,就返回Object类型的数组,
如果以一个数组为参数,就以参数类型为返回的数组类型。对于ArrayList集合: [“aa”,”cc”,”ff”,”acf”]
可以返回一个String类型数组:String [] arr=list.toArray(new String [list.size()]);
。
这个数组包含集合中的元素。
注意:
(1)toArray方法中传入一个新建的数组作为参数,这个数组的长度如果比集合长度小,
该方法内部会自动新建一个长度刚好的数组。如果定义的数组长度比集合长度大,
就不会新建数组,而是顺序存入元素,没有存值的角标位值为默认值null。
(2)集合变数组是为了限制对元素的增删操作。
三:其他常见方法的应用
高级for循环:
迭代器可以简写成高级for循环的形式。
来看一个迭代器,Iterator<String> it=list.iterator(); while (it.hasNext()) { System.out.println(it.next()); }
此迭代器可以简写成:
for (String s : list) { System.out.println(s); }
这就是高级for循环的应用。
高级for循环底层就是用的迭代器原理。可变参数:
方法中的参数数量可以变化。
如:public static void show(int ... arr) { System.out.println(arr.length); } public static void main(String [] args) { show(3); //打印1 show(4,5,6,7,8);//打印5 }
此例中是往show方法中传入一个数组,并且自动将传入的int整数封装成一个数组。
相当于int [] arr={4,5,6,7,8}; show(arr);
注意:在使用可变参数时,参数列表中可变参数要放在最后面,否则系统分不清哪些参数要封装进可变参数。
静态导入:
导包后,调用方法可以不写类名调用,静态导包后,可以不写名字,直接用方法。
形式:import static java.util.Arrays.*; class Demo { public static void main(String [] args) { int [] arr={4,2,3}; sort(arr); //Arrays.sort(arr);的简写 System.out.println(Arrays.toString(arr)); } }
注意:
(1) Arrays 类中有toString()方法,Object类中也有toString()方法,
这时,就要表明是 Object.toString() 还是 Arrays.toString()。
(2) import 后加static时,导入的是这个类的所有静态成员。